我正在使用以下示例在Node.js中进行签名和验证:https : //github.com/nodejs/node-v0.x-archive/issues/6904。验证在Node.js中成功,但在WebCrypto中失败。同样,使用WebCrypto签名的消息无法在Node.js中验证。
这是我用来验证使用WebCrypto- https: //jsfiddle.net/aj49e8sj/从Node.js脚本生成的签名的代码。已在Chrome 54.0.2840.27和Firefox 48.0.2中测试
// From https://github.com/nodejs/node-v0.x-archive/issues/6904 var keys = { priv: '-----BEGIN EC PRIVATE KEY-----\n' + 'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' + 'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' + 'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' + '-----END EC PRIVATE KEY-----\n', pub: '-----BEGIN PUBLIC KEY-----\n' + 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNh\n' + 'B8i3mXyIMq704m2m52FdfKZ2pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' + '-----END PUBLIC KEY-----\n' }; var message = (new TextEncoder('UTF-8')).encode('hello'); // Algorithm used in Node.js script is ecdsa-with-SHA1, key generated with prime256v1 var algorithm = { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-1' } }; // Signature from obtained via above Node.js script var sig64 = 'MEUCIQDkAtiomagyHFi7dNfxMrzx/U0Gk/ZhmwCqaL3TimvlswIgPgeDqgZNqfR5/FZZASYsczUAhGSXjuycLhWnvk20qKc='; // Decode base64 string into ArrayBuffer var b64Decode = (str) => Uint8Array.from(atob(str), x => x.charCodeAt(0)); // Get base64 string from public key const key64 = keys.pub.split('\n') .filter(x => x.length > 0 && !x.startsWith('-----')) .join(''); // Convert to buffers var sig = b64Decode(sig64); var keySpki = b64Decode(key64); // Import and verify // Want 'Verification result: true' but will get 'false' var importKey = crypto.subtle.importKey('spki', keySpki, algorithm, true, ['verify']) .then(key => crypto.subtle.verify(algorithm, key, sig, message)) .then(result => console.log('Verification result: ' + result));
使用SHA-256而不是SHA-1的类似问题的相关问题:使用Node.js / crypto生成ECDSA签名
我检查过的事情:
我如何才能成功验证从Node.js收到的签名,反之亦然-验证从WebCrypto生成的Node.js中的签名?还是以使它们不兼容的方式使标准的实现细微不同?
编辑:
已验证的Node.js签名是DER编码的,而WebCrypto签名不是。
我不能肯定地说没有使用这两个库中的任何一个,但是一种可能性是它们没有为签名使用相同的编码类型。对于DSA / ECDSA,有两种主要格式,IEEEP1363(Windows使用)和DER(OpenSSL使用)。
“ Windows”格式应具有预设的大小(由DS的Q值和ECDSA的P值决定(Windows不支持Char-2,但如果是的话,Char-2ECDSA则可能为M))。然后将r和s都用左填充,0直到它们达到该长度。
r
s
0
在太小是合法例如r = 0x305和s = 0x810522用的sizeof(Q)是3个字节:
r = 0x305
s = 0x810522
// r 000305 // s 810522
对于“ OpenSSL”格式,它按照DER规则编码为SEQUENCE(INTEGER(r),INTEGER(s)),看起来像
// SEQUENCE 30 // (length of payload) 0A // INTEGER(r) 02 // (length of payload) 02 // note the leading 0x00 is omitted 0305 // INTEGER(s) 02 // (length of payload) 04 // Since INTEGER is a signed type, but this represented a positive number, // a 0x00 has to be inserted to keep the sign bit clear. 00810522
或者,紧凑地:
000305810522
300A02020305020400810522
“ Windows”格式始终为偶数,且长度始终相同。“ OpenSSL”格式通常大约大6个字节,但是中间可能会增加或丢失一个字节;所以有时候甚至是奇怪
Base64解码您的sig64值表明它正在使用DER编码。使用WebCrypto生成几个签名;如果没有开始,0x30那么您就有IEEE /DER问题。
sig64
0x30