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

使用OpenSSL生成ECDSA签名后,Web Crypto API验证失败求助

ECDSA签名Web Crypto API验证失败的原因与解决方法

问题核心

OpenSSL默认生成的ECDSA签名是ASN.1/DER编码格式,而Web Crypto API要求的是IEEE P1363格式(原始r+s字节拼接),这是导致验证失败的根本原因。

格式差异说明

  • OpenSSL默认签名格式:DER编码的ASN.1序列,结构为0x30 [总长度] 0x02 [r长度] r值 0x02 [s长度] s值,其中r和s是可变长度的整数(可能小于32字节)。
  • Web Crypto要求的格式:固定64字节的二进制数据,前32字节是r值(不足补前导0),后32字节是s值(同样补前导0)。

解决方案

方案1:修改OpenSSL签名命令,直接生成P1363格式签名

在签名时添加-sigopt ecdsa_scheme:plain参数,让OpenSSL直接输出Web Crypto兼容的格式:

openssl dgst -sha256 -sign ecdsa_private_key.pem -out ecdsa_signature.bin -sigopt ecdsa_scheme:plain data.txt

使用该命令生成的签名,无需修改JS代码即可直接通过Web Crypto验证。

方案2:在JavaScript中转换签名格式

如果无法修改签名生成流程,可以在验证前将DER格式的签名转换为P1363格式,添加以下转换函数:

function derToP1363(signatureDer) {
    const buffer = new Uint8Array(signatureDer);
    let offset = 0;

    // 解析ASN.1 SEQUENCE头部
    if (buffer[offset++] !== 0x30) throw new Error("无效的DER签名格式");
    let length = buffer[offset++];
    if (length & 0x80) {
        const lenBytes = length & 0x7F;
        length = 0;
        for (let i = 0; i < lenBytes; i++) {
            length = (length << 8) | buffer[offset++];
        }
    }

    // 提取r值
    if (buffer[offset++] !== 0x02) throw new Error("无效的r字段标识");
    const rLen = buffer[offset++];
    const r = buffer.slice(offset, offset + rLen);
    offset += rLen;

    // 提取s值
    if (buffer[offset++] !== 0x02) throw new Error("无效的s字段标识");
    const sLen = buffer[offset++];
    const s = buffer.slice(offset, offset + sLen);
    offset += sLen;

    // 将r和s补全为32字节(P-256曲线要求)
    const fixedR = new Uint8Array(32);
    fixedR.set(r, 32 - r.length);
    const fixedS = new Uint8Array(32);
    fixedS.set(s, 32 - s.length);

    // 拼接r和s得到P1363格式签名
    return new Uint8Array([...fixedR, ...fixedS]);
}

然后修改验证代码,转换签名后再验证:

// ... 原有的密钥导入、数据读取代码不变 ...

const signature = await readFile("./ecdsa_signature.bin");
// 转换签名格式
const p1363Signature = derToP1363(signature);

const isValid = await crypto.subtle.verify(
    {
        name: 'ECDSA',
        hash: { name: 'SHA-256' }
    },
    publicKey,
    p1363Signature,
    data
);

console.log(isValid); // 现在会返回true

内容的提问来源于stack exchange,提问作者vanilla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:28:12