问题描述
我有使用 c> c>
下面的解决方案假定规范格式是使用的连接样式 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)
]);
}
函数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);
}
函数ecdsaVerify(data,signature,key){
const verify = crypto.createVerify('SHA256');
verify.update(data);
const asn1sig = concatSigToAsn1Sig(signature);
return verify.verify(key,new Buffer(asn1sig,'hex'));
}
感谢
I have code that generates a concatenated (r-s) signature for the ECDSA signature using jsrsasign and a key in JWK format:
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');
Seems to work. I also have code that uses SubtleCrypto to achieve the same thing:
importEcdsaKey(key, 'sign') // importKey JWK -> raw .then((privateKey) => subtle.sign( { name: 'ECDSA', hash: {name: 'SHA-256'} }, privateKey, dataBuffer ))
These both return 128-byte buffers; and they cross-verify (i.e. I can verify jsrsasign signatures with SubtleCrypto and vice versa). However, when I use the Sign class in the Node.js crypto module, I seem to get something quite different.
key = require('jwk-to-pem')(key, {'private': true}); const sign = require('crypto').createSign('sha256'); sign.update(dataBuffer); return sign.sign(key);
Here I get a buffer of variable length, roughly 70 bytes; it does not cross-verify with jsrsa (which bails complaining about an invalid length for an r-s signature).
How can I get an r-s signature, as generated by jsrsasign and SubtleCrypto, using Node crypto?
The answer turns out to be that the Node crypto module generates ASN.1/DER signatures, while other APIs like jsrsasign and SubtleCrypto produce a "concatenated" signature. In both cases, the signature is a concatenation of (r, s). The difference is that ASN.1 does so with the minimum number of bytes, plus some payload length data; while the P1363 format uses two 32-bit hex encoded integers, zero-padding them if necessary.
The below solution assumes that the "canonical" format is the concatenated style used by 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')); }
Figured it out thanks to
- http://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1
- ECDSA signatures between Node.js and WebCrypto appear to be incompatible?
这篇关于使用Node.js / crypto生成ECDSA签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!