Node.js生成ECDSA-SHA256签名后,OpenSSL验证失败如何解决?
问题原因及解决方案
错误1:消息内容不一致
使用echo $MESSAGE传递消息时,echo会自动在消息末尾添加换行符,但Node.js代码中签名的是无换行的"Some data",导致两者的哈希值不匹配,直接引发验证失败。
错误2:签名格式不匹配
Node.js的crypto.sign生成ECDSA签名时,默认输出ASN.1/DER编码格式;而OpenSSL的dgst -verify默认期望ECDSA签名使用P1363格式(直接拼接r和s的字节数据),格式不兼容导致验证失败。
修正后的OpenSSL验证命令
同时修复上述两个问题:
#!/bin/zsh PUBLIC_KEY="LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUViVCtFVHUzV21BNjc3b1ZVcDZ3Q1E4eU5ocFZIMWtBQQo4V3F2T0hxR3JqaFVoUzdUcUNGRHBGNStGbklrWUpjSWpwcTJtNmJkcHpNPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K" MESSAGE="Some data" SIGNATURE="MD0CHDNm8dc0uUTBQmBMjlF7t7+QqofLJJzXfA4TIjsCHQDH6br8YJxaa7xB15hLRpWT0ewKBZnhf3UYtx3C" openssl dgst \ -sha256 \ -sigopt ec_sigform:der \ # 指定签名为DER格式 -verify <(base64 -d <<< "$PUBLIC_KEY") \ -signature <(base64 -d <<< "$SIGNATURE") \ <(echo -n "$MESSAGE") # 用-n参数避免自动添加换行符
另一种方案:修改Node.js代码生成P1363格式签名
如果希望Node.js直接生成OpenSSL默认支持的P1363格式签名,可以修改签名步骤,手动提取r和s并拼接:
const crypto = require('node:crypto') const keys = { "pubKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUViVCtFVHUzV21BNjc3b1ZVcDZ3Q1E4eU5ocFZIMWtBQQo4V3F2T0hxR3JqaFVoUzdUcUNGRHBGNStGbklrWUpjSWpwcTJtNmJkcHpNPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", "privKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1IZ0NBUUF3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0VFWVRCZkFnRUJCQnhCK01iaS96am90bWJQL1NJTjh1L1kKUitIa0p2cXF5OXdaNTZZaG9Ud0RPZ0FFYlQrRVR1M1dtQTY3N29WVXA2d0NROHlOaHBWSDFrQUE4V3F2T0hxRwpyamhVaFM3VHFDRkRwRjUrRm5Ja1lKY0lqcHEybTZiZHB6TT0KLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=" } const message = "Some data" const privateKey = Buffer.from(keys.privKey, 'base64') const publicKey = Buffer.from(keys.pubKey, 'base64') // 生成签名对象并写入消息 const sign = crypto.createSign('sha256') sign.write(message) sign.end() // 生成DER格式签名后解析出r和s const derSignature = sign.sign(privateKey) const { r, s } = crypto.ECDSA_SIG_parse(derSignature) // 获取当前密钥曲线的字节长度(示例中为P-256,对应32字节) const key = crypto.createPublicKey(publicKey) const curveLength = key.asymmetricKeyDetails.size >> 3 // 将r和s填充到曲线长度后拼接成P1363格式 const p1363Signature = Buffer.concat([ Buffer.from(r.toString('hex').padStart(curveLength * 2, '0'), 'hex'), Buffer.from(s.toString('hex').padStart(curveLength * 2, '0'), 'hex') ]) const signed = p1363Signature.toString('base64') console.log(signed)
此时只需把原OpenSSL命令中的echo $MESSAGE改为echo -n $MESSAGE,即可正常验证通过。
内容的提问来源于stack exchange,提问作者David Novák
相关产品推荐
相关产品推荐

