使用Node.js / crypto生成ECDSA签名
我有使用jsrsasign
和JWK格式的键生成ECDSA签名的连接(rs)签名的代码:
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');
似乎工作。 我也有使用SubtleCrypto
来实现同样的事情的代码:
importEcdsaKey(key, 'sign') // importKey JWK -> raw .then((privateKey) => subtle.sign( { name: 'ECDSA', hash: {name: 'SHA-256'} }, privateKey, dataBuffer ))
这两个都返回128字节的缓冲区; 他们交叉validation(即我可以validationjsrsasign
签名与SubtleCrypto
,反之亦然)。 但是,当我在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
交叉validation(保证抱怨rs签名的长度无效)。
我怎样才能得到rs签名,由jsrsasign
和SubtleCrypto
,使用节点crypto
?
答案就是Node crypto
模块生成ASN.1 / DER签名,而其他API(如jsrsasign
和SubtleCrypto
产生“连接”签名。 在这两种情况下,签名都是(r, s)
的串联。 不同之处在于ASN.1是以最小字节数加上一些有效载荷长度数据来实现的。 而P1363格式使用两个32位的hex编码整数,如果需要,填零。
下面的解决scheme假设“规范”格式是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')); }
多亏了
- https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1
- Node.js和WebCrypto之间的ECDSA签名似乎不兼容?
- Angular CryptoJs Encryption在Node JS CryptoJS中没有解密
- RSAencryption之间的c + +和node.js
- GitHub Webhook秘密从不validation
- 在Node.js中$ 2y bcrypt哈希
- 尝试在node.js中获取AESencryptionstring以匹配.net中的encryption值
- 使用ECDH和nodejsencryption解密秘密
- AES-128-GCM在Node V6上validationIV吗?
- Node.js – 如何使用crypto.randomBytes在特定范围内生成随机数字
- 将密码过程从java转换为nodejs(Blowfish)