Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Node.js/crypto生成ECDSA签名_Node.js_Cryptography_Ecdsa - Fatal编程技术网

使用Node.js/crypto生成ECDSA签名

使用Node.js/crypto生成ECDSA签名,node.js,cryptography,ecdsa,Node.js,Cryptography,Ecdsa,我的代码使用jsrsasign和JWK格式的密钥为ECDSA签名生成串联(r-s)签名: const sig = new Signature({ alg: 'SHA256withECDSA' }); sig.init(KEYUTIL.getKey(key)); sig.updateHex(dataBuffer.toString('hex')); const asn1hexSig = sig.sign(); const concatSig = ECDSA.asn1SigToConcatSig(as

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

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');
似乎有效。我还有使用
sublecrypto
实现相同功能的代码:

importEcdsaKey(key, 'sign') // importKey JWK -> raw
.then((privateKey) => subtle.sign(
    { name: 'ECDSA', hash: {name: 'SHA-256'} },
    privateKey,
    dataBuffer
))
它们都返回128字节的缓冲区;并且它们相互验证(即,我可以使用
sublecrypto
验证
jsrsasign
签名,反之亦然)。然而,当我在Node.js
crypto
模块中使用
Sign
类时,我似乎得到了完全不同的结果

key = require('jwk-to-pem')(key, {'private': true});
const sign = require('crypto').createSign('sha256');
sign.update(dataBuffer);
return sign.sign(key);
这里我得到一个可变长度的缓冲区,大约70字节;它不会与
jsrsa
进行交叉验证(这会避免抱怨r-s签名的长度无效)


如何使用Node
crypto
获得由
jsrsasign
SubtleCrypto
生成的r-s签名?

答案是Node
crypto
模块生成ASN.1/DER签名,而
jsrsasign
SubtleCrypto
等其他API生成“串联”签名签名。在这两种情况下,签名都是
(r,s)
的串联。区别在于ASN.1使用的是最小字节数加上一些有效负载长度数据;P1363格式使用两个32位十六进制编码整数,必要时对其进行零填充

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

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'));
}
多亏了我才弄明白


您确定
需要('jwk-to-pem')(key,{'private':true})生成加密模块能够理解的EC私钥的有效编码?它是否像中一样以
----begin EC PRIVATE KEY-----
开头?是的:至少,它会生成一个带有
EC PRIVATE KEY
部分的PEM字符串,
crypto
模块不会发出任何类型的错误或警告,它只会发出与我预期不同的签名。