我正在使用以下示例在Node.js中進行簽名+驗證:https://github.com/nodejs/node-v0.x-archive/issues/6904。驗證在Node.js中成功,但在WebCrypto中失敗。同樣,使用WebCrypto簽名的消息無法在Node.js中進行驗證。Node.js和WebCrypto之間的ECDSA簽名似乎不兼容?
下面是我用來驗證使用WebCrypto從Node.js腳本產生的簽名的代碼 - https://jsfiddle.net/aj49e8sj/。經測試在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類似的問題相關的問題都:Generating ECDSA signature with Node.js/crypto
事情我已經檢查:
- 我對Node.js鍵進行了解碼,並驗證它們與通過WebCrypto生成的鍵具有相同的OID。這告訴我我正在使用正確的曲線。
- SHA-1被顯式識別爲在兩個位置使用的散列。
- ECDSA在Node.js和WebCrypto中均已明確標識。
如何成功驗證從Node.js收到的簽名,反之亦然 - 驗證從WebCrypto生成的Node.js中的簽名?或者標準的實現在這種方式中有微妙的差異,使得它們不兼容?
編輯:
- WebCrypto簽名(64個字節):uTaUWTfF + AjN3aPj0b5Z2d1HybUEpV/PHV/P9RtfKaGXtcYnbgfO43IRg46rznG3/WnWwJ2sV6mPOEnEPR0vWw ==
- Node.js的簽名(71個字節):MEUCIQDkAtiomagyHFi7dNfxMrzx/U0Gk/ZhmwCqaL3TimvlswIgPgeDqgZNqfR5/FZZASYsczUAhGSXjuycLhWnvk20qKc =
已驗證Node.js簽名是DER編碼,而WebCrypto簽名不是。
正確的錢! Node.js在底層使用了OpenSSL,所以在這方面的DER編碼是有道理的。 WebCrypto規範說結果是r和s連接:https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations – SiNiquity