Node.js实现SHA256WithRSA签名遇DECODER routines错误求助
问题
我开发的Node.js(TypeScript)应用需要向Web服务发送签名,要求如下:
- 基于SHA256WithRSA算法
- 使用客户端私钥对客户端数据签名并输出签名结果
- 将签名编码为Base64
我最初尝试用HMAC实现,但发现不符合算法要求:
import { createHmac } from 'crypto'; const signature = createHmac('sha256', config.secret).update(data).digest('hex'); const signature1 = Buffer.from(signature, 'hex').toString('base64')
改用createSign后抛出错误:
import { createSign } from 'crypto'; const sign = createSign('RSA-SHA256'); sign.update(data); const signature = sign.sign(config.secret, 'base64');
错误信息:
Error: error:1E08010C:DECODER routines::unsupported at Object.signOneShot (node:internal/crypto/sig:163:15)
我的私钥是RSA2算法生成的2048位密钥,格式为无PEM标签的纯Base64字符串:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcZdmCvpg8tiiKMGs1GkYqNPZtW....
尝试添加PEM标签后仍报错:
const pemKey = ` -----BEGIN RSA PRIVATE KEY----- ${secretkey} -----END RSA PRIVATE KEY----- `;
也试过crypto.sign的写法,依旧报相同错误:
import * as crypto from 'node:crypto' const signature = crypto.sign( "sha256", Buffer.from(encodedParams), { key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, } ).toString('base64')
测试环境:Ubuntu 22.04(Node 18.20)、Mac 11.7.10(Node 20.11),已将OpenSSL从1.1.1升级到3.0,问题未解决。
解决方法
1. 错误根源:私钥解析失败
error:1E08010C:DECODER routines::unsupported本质是OpenSSL无法正确解析你的私钥,核心原因有两个:
- 纯Base64字符串未按PEM规范分段(要求每64个字符换行)
- 私钥格式与PEM标签不匹配(比如用了PKCS#1标签但实际是PKCS#8格式)
2. 正确格式化私钥
方式一:修复PKCS#1格式PEM
如果私钥是PKCS#1格式,给纯Base64字符串按64字符分段,再添加对应标签:
// 给纯Base64私钥添加换行,符合PEM规范 const formattedKey = secretKey.match(/.{1,64}/g)?.join('\n') || secretKey; const pemKey = `-----BEGIN RSA PRIVATE KEY-----\n${formattedKey}\n-----END RSA PRIVATE KEY-----`;
方式二:尝试PKCS#8格式标签
如果私钥是PKCS#8格式(多数工具默认生成),改用对应标签:
const formattedKey = secretKey.match(/.{1,64}/g)?.join('\n') || secretKey; const pemKey = `-----BEGIN PRIVATE KEY-----\n${formattedKey}\n-----END PRIVATE KEY-----`;
3. 最终签名实现代码
私钥格式修复后,用crypto.sign实现标准SHA256WithRSA(默认使用PKCS#1 v1.5填充,这是该算法的标准要求):
import * as crypto from 'node:crypto'; // 要签名的原始数据 const data = 'your_data_to_sign'; // 你的纯Base64私钥 const secretKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcZdmCvpg8tiiKMGs1GkYqNPZtW....'; // 格式化私钥为标准PEM格式 const formattedKey = secretKey.match(/.{1,64}/g)?.join('\n') || secretKey; // 先试PKCS#1标签,不行换PKCS#8 const pemKey = `-----BEGIN RSA PRIVATE KEY-----\n${formattedKey}\n-----END RSA PRIVATE KEY-----`; try { const signature = crypto.sign( 'sha256', Buffer.from(data), { key: pemKey, // SHA256WithRSA默认用PKCS1_PADDING,不要用PSS_PADDING(除非服务端明确要求) padding: crypto.constants.RSA_PKCS1_PADDING } ).toString('base64'); console.log('生成的签名:', signature); } catch (err) { console.error('签名失败:', err); }
4. 关键注意事项
- 不要随意指定
RSA_PKCS1_PSS_PADDING,SHA256WithRSA通常指SHA256哈希+RSA PKCS#1 v1.5填充 - 确保私钥没有多余空格、换行或特殊字符
- 如果私钥是加密的(带密码),需要在配置中添加
passphrase字段:{ key: pemKey, passphrase: 'your_password' }
内容的提问来源于stack exchange,提问作者user824624
相关产品推荐
相关产品推荐

