当前位置: 首页 > 知识库问答 >
问题:

用Node.js/crypto生成ECDSA签名

诸葛亮
2023-03-14

我有代码使用jsrsasign为ECDSA签名生成串联(r-s)签名和JWK格式的密钥:

const sig = new Signature({ alg: 'SHA256withECDSA' });
sig.init(KEYUTIL.getKey(key));
sig.updateHex(dataBuffer.toString('hex'));
const asn1hexSig = sig.sign();
const concatSig = ECDSA.asn1SigToConcatSig(asn1hexSig);
return new Buffer(concatSig, 'hex');

似乎有效。我也有使用SubuleCrypto来实现相同目标的代码:

importEcdsaKey(key, 'sign') // importKey JWK -> raw
.then((privateKey) => subtle.sign(
    { name: 'ECDSA', hash: {name: 'SHA-256'} },
    privateKey,
    dataBuffer
))

这两者都返回128字节的缓冲区;并且它们可以交叉验证(例如,我可以用< code>SubtleCrypto验证< code > JSR sign 签名,反之亦然)。然而,当我在Node.js crypto模块中使用< code>Sign类时,我似乎得到了完全不同的东西。

key = require('jwk-to-pem')(key, {'private': true});
const sign = require('crypto').createSign('sha256');
sign.update(dataBuffer);
return sign.sign(key);

在这里,我得到了一个可变长度的缓冲区,大约70字节;它不会与 jsrsa 交叉验证(jsrsa 抱怨 r-s 签名的长度无效)。

如何使用 Node 加密获取由 jsrsasignSubtleCrypto 生成的 r-s 签名?

共有1个答案

冯玮
2023-03-14

答案是Nodecrypto模块生成ASN.1/DER签名,而其他API(如jsrsasignSubtleCrypto)生成“连接”签名。在这两种情况下,签名都是(r, s)的连接。区别在于ASN.1使用最小字节数以及一些有效负载长度html" target="_blank">数据来执行此操作;而P1363格式使用两个32位十六进制编码的整数,必要时将它们填充为零。

下面的解决方案假设“规范”格式是SubtleCrypto使用的连接样式。

const asn1 = require('asn1.js');
const BN = require('bn.js');
const crypto = require('crypto');

const EcdsaDerSig = asn1.define('ECPrivateKey', function() {
    return this.seq().obj(
        this.key('r').int(),
        this.key('s').int()
    );
});

function asn1SigSigToConcatSig(asn1SigBuffer) {
    const rsSig = EcdsaDerSig.decode(asn1SigBuffer, 'der');
    return Buffer.concat([
        rsSig.r.toArrayLike(Buffer, 'be', 32),
        rsSig.s.toArrayLike(Buffer, 'be', 32)
    ]);
}

function concatSigToAsn1SigSig(concatSigBuffer) {
    const r = new BN(concatSigBuffer.slice(0, 32).toString('hex'), 16, 'be');
    const s = new BN(concatSigBuffer.slice(32).toString('hex'), 16, 'be');
    return EcdsaDerSig.encode({r, s}, 'der');
}

function ecdsaSign(hashBuffer, key) {
    const sign = crypto.createSign('sha256');
    sign.update(asBuffer(hashBuffer));
    const asn1SigBuffer = sign.sign(key, 'buffer');
    return asn1SigSigToConcatSig(asn1SigBuffer);
}

function ecdsaVerify(data, signature, key) {
    const verify = crypto.createVerify('SHA256');
    verify.update(data);
    const asn1sig = concatSigToAsn1Sig(signature);
    return verify.verify(key, new Buffer(asn1sig, 'hex'));
}

多亏了你,我才明白

    < Li > https://crypto . stack exchange . com/questions/1795/how-can-I-convert-a-der-ECD sa-signature-to-ASN-1 < li > ECDSA和WebCrypto之间的ECDSA签名似乎不兼容?
 类似资料:
  • 下面是Java代码: 然后使用C代码来验证签名 我在想我需要将我的签名编码为hexa,但它并没有解决我的问题。我已经使用crypto编写了一个c版本的符号方法,并且已经验证过了。所以为什么当我使用java代码时,签名没有得到验证。谢谢

  • 问题内容: 我用nodejs crypto创建了一个私钥,并想用该密钥签名文件。我的代码如下: 但是我得到了错误: 我知道它与密钥格式有关,但我不知道该如何解决。有人可以帮忙吗? 更新:我编辑了privateKey以适合pem格式: 现在我遇到了另一个错误: 问题答案: 用于签署数据的密钥必须是有效的PEM编码的私钥。DH 函数不以这种格式返回密钥,而是返回裸机专用密钥数据。 您的选择包括: 通过

  • 我试图用ECDSA和secp256r1曲线(P256)和SHA256算法来生成签名。我也在使用弹力城堡图书馆。下面的代码,

  • 我正在使用secp256r1曲线和使用BouncyCastle的SHA256算法实现ECDSA签名生成。 对于某些输入,签名长度为127个字符。我感觉开头的“0”被删除了,因为签名被存储到ECDSASigner类中的BigInteger datatype中。 我使用确定性方法添加了rfc6979 ECDSA签名中的示例 唯一的区别是r值中的零。因为签名的长度只有127。 如果我的推论是正确的,请让

  • 我在nodejs中有一个非常小的代码,我在其中签名一个字符串,然后尝试使用openssl生成的节点密码和密钥对来验证它。无论我尝试什么,结果总是“错误”,签名无法验证。 生成公钥/私钥对: 生成的密钥是(我不在乎是否公开): 然后,这是我的节点代码: 我尝试使用不同的算法和编码。我已经读了带有"fs"的PEM文件,也没有运气。我错过了什么?顺便说一句,这些键使用npm URSA模块完美工作,所以我

  • 我已经在Java中生成了一个ECDSA签名,我希望从中获得R和S值,以便获得COSE编码的签名。根据我的理解,我生成的签名是DER编码的(默认情况下使用bouncyCastle)。当我使用P-256曲线(SHA256withECDSA)时,我正确地检索了R和S值。 当我使用其他曲线(P-521、P-384)时,从一种编码到另一种编码的签名解析有一些问题。