You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:50:34