diff --git a/javascript/webcryptoapi/testcases/EcdsaTest.js b/javascript/webcryptoapi/testcases/EcdsaTest.js index 187b8e9..04064ab 100644 --- a/javascript/webcryptoapi/testcases/EcdsaTest.js +++ b/javascript/webcryptoapi/testcases/EcdsaTest.js @@ -41,7 +41,7 @@ var Ecdsa = function() {}; /** * Verifies the given signature using the given ECDSA public key. * @param {!CryptoKey} pk The ECDSA public key - * @param {!string} hashAlg The hash algorithm + * @param {string} hashAlg The hash algorithm * @param {!ArrayBuffer} msg The message to be verified * @param {!ArrayBuffer} sig The signature to be verified * @@ -49,56 +49,40 @@ var Ecdsa = function() {}; */ Ecdsa.verify = function(pk, hashAlg, msg, sig) { return crypto.subtle.verify( - { - name: 'ECDSA', - hash: {name: hashAlg} - }, - pk, - sig, - msg - ); + {name: 'ECDSA', hash: {name: hashAlg}}, pk, sig, msg); }; /** * Signs a message using the given ECDSA private key and hash algorithm. * @param {!CryptoKey} sk The ECDSA private key * @param {!ArrayBuffer} msg The message to be signed - * @param {!string} hashAlg The hash algorithm + * @param {string} hashAlg The hash algorithm * * @return {!Promise} */ Ecdsa.sign = function(sk, msg, hashAlg) { return crypto.subtle.sign( - { + { name: 'ECDSA', hash: {name: hashAlg}, - }, - sk, - msg - ); + }, + sk, msg); }; /** * Imports a ECDSA public key. * @param {!JSONObject} keyData The key data in JWK format - * @param {!string} hashAlg The hash algorithm + * @param {string} hashAlg The hash algorithm * @param {!Array} usages The usages of the key * * @return {!Promise} */ Ecdsa.importPublicKey = function(keyData, hashAlg, usages) { return crypto.subtle.importKey( - 'jwk', - keyData, - { - name: 'ECDSA', - namedCurve: keyData['crv'], - hash: {name: hashAlg} - }, - true, - usages - ); + 'jwk', keyData, + {name: 'ECDSA', namedCurve: keyData['crv'], hash: {name: hashAlg}}, true, + usages); }; /** @@ -113,20 +97,18 @@ Ecdsa.exportKey = function(key) { /** * Generates an ECDSA key pair using the given hash algorithm and curve name. - * @param {!string} hashAlg The hash algorithm - * @param {!string} curveName The curve name + * @param {string} hashAlg The hash algorithm + * @param {string} curveName The curve name * * @return {!Promise} */ Ecdsa.generateKey = function(hashAlg, curveName) { return crypto.subtle.generateKey( - { + { name: 'ECDSA', namedCurve: curveName, - }, - true, - ['sign', 'verify'] - ); + }, + true, ['sign', 'verify']); }; @@ -139,20 +121,25 @@ Ecdsa.generateKey = function(hashAlg, curveName) { Ecdsa.testVerify = function() { tc = this; var promise = new Promise((resolve, reject) => { - Ecdsa.importPublicKey(tc.keyData, tc.hashAlg, ['verify']).then(function(pk){ - Ecdsa.verify(pk, tc.hashAlg, tc.msg, tc.sig).then(function(isValid){ - if ((tc.result == 'valid' && !isValid) || - (tc.result == 'invalid' && isValid)) { - reject('Failed in test case ' + tc.id); - } - resolve(); - }).catch(function(err){ - // don't expect any exception in signature verification - reject('Unexpected exception on test case ' + tc.id + ": " + err); - }); - }).catch(function(err){ - reject('Failed to import key in test case ' + tc.id + ': ' + err); - }); + Ecdsa.importPublicKey(tc.keyData, tc.hashAlg, ['verify']) + .then(function(pk) { + Ecdsa.verify(pk, tc.hashAlg, tc.msg, tc.sig) + .then(function(isValid) { + if ((tc.result == 'valid' && !isValid) || + (tc.result == 'invalid' && isValid)) { + reject('Failed in test case ' + tc.id); + } + resolve(); + }) + .catch(function(err) { + // don't expect any exception in signature verification + reject( + 'Unexpected exception on test case ' + tc.id + ': ' + err); + }); + }) + .catch(function(err) { + reject('Failed to import key in test case ' + tc.id + ': ' + err); + }); }); return promise; }; @@ -162,10 +149,10 @@ Ecdsa.testVerify = function() { * Parameters of a ECDSA signature verification test. * @param {!number} id Test case's id * @param {!JSONObject} keyData The key data in JWK format - * @param {!string} hashAlg The hash algorithm + * @param {string} hashAlg The hash algorithm * @param {!ArrayBuffer} msg The message that was signed * @param {!ArrayBuffer} sig The signature to be verified - * @param {!string} result The expected result of the test case + * @param {string} result The expected result of the test case */ var EcdsaVerifyTestCase = function(id, keyData, hashAlg, msg, sig, result) { this.id = id; @@ -191,8 +178,8 @@ function testEcdsaVectors() { var keyData = tg['jwk']; var curveName = keyData['crv']; var hashAlg = tg['sha']; - if (SUPPORTED['ecdsa-curve'].indexOf(curveName) == -1 - || SUPPORTED['hash'].indexOf(hashAlg) == -1) { + if (SUPPORTED['ecdsa-curve'].indexOf(curveName) == -1 || + SUPPORTED['hash'].indexOf(hashAlg) == -1) { continue; } for (var j = 0; j < tg['tests'].length; j++) { @@ -201,8 +188,8 @@ function testEcdsaVectors() { var result = tc['result']; var msg = TestUtil.hexToArrayBuffer(tc['msg']); var sig = TestUtil.hexToArrayBuffer(tc['sig']); - var test = new EcdsaVerifyTestCase( - tcId, keyData, hashAlg, msg, sig, result); + var test = + new EcdsaVerifyTestCase(tcId, keyData, hashAlg, msg, sig, result); testCase.addNewTest('Test ' + tcId, Ecdsa.testVerify, test); } } @@ -219,9 +206,9 @@ function testEcdsaVectors() { Ecdsa.extractSig = function(sig) { var bytes = new Uint8Array(sig); var byteLen = bytes.length; - var rBytes = bytes.subarray(0, byteLen/2); + var rBytes = bytes.subarray(0, byteLen / 2); var r = new BigInteger(rBytes); - var sBytes = bytes.subarray(byteLen/2, byteLen); + var sBytes = bytes.subarray(byteLen / 2, byteLen); var s = new BigInteger(sBytes); return [r, s]; }; @@ -250,7 +237,7 @@ Ecdsa.extractNonce = function(h, r, s, d, curveSpec) { * @param {!wycheproof.BigInteger} s The 's' value of the signature * @param {!wycheproof.BigInteger} d The private component of the ECDSA key * @param {!wycheproof.BigInteger} k The nonce that needs to be checked - * @param {!string} curveName The curve name + * @param {string} curveName The curve name */ Ecdsa.checkNonceCorrectness = function(msg, r, s, d, k, curveName) { var e2eCurveMap = { @@ -259,14 +246,13 @@ Ecdsa.checkNonceCorrectness = function(msg, r, s, d, k, curveName) { 'P-521': 'P_521', }; var e2eCurveName = e2eCurveMap[curveName]; - var key = new e2e.ecc.Ecdsa(e2eCurveName, - {privKey: d.toByteArray()}); + var key = new e2e.ecc.Ecdsa(e2eCurveName, {privKey: d.toByteArray()}); var msgBytes = new Uint8Array(msg); var calSig = key.signForTestingOnly(msgBytes, k); var calR = new BigInteger(calSig['r']); var calS = new BigInteger(calSig['s']); - assertTrue('Nonce calculation was incorrect', - r.isEqual(calR) && s.isEqual(calS)); + assertTrue( + 'Nonce calculation was incorrect', r.isEqual(calR) && s.isEqual(calS)); }; /** @@ -285,61 +271,72 @@ Ecdsa.checkNonceCorrectness = function(msg, r, s, d, k, curveName) { */ Ecdsa.testBias = function() { var tc = this; - var nDone = 0; var countLsb = 0; var countMsb = 0; - var promise = new Promise(function(resolve, reject){ - for (var i = 0; i < tc.nTests; i++) { - Ecdsa.generateKey(tc.hashAlg, tc.curveName).then(function(key){ - Ecdsa.exportKey(key.privateKey).then(function(keyData){ - Ecdsa.sign(key.privateKey, tc.msg, tc.hashAlg).then(function(sig){ - HashUtil.digest(tc.hashAlg, tc.msg).then(function(digest){ - var curveSpec = EcUtil.getCurveSpec(tc.curveName); - var h = new BigInteger(new Uint8Array(digest)); - // private key value - var d = BigInteger.fromHex(TestUtil.base64UrlToHex(keyData['d'])); - var r, s; - [r, s] = Ecdsa.extractSig(sig); - var k = Ecdsa.extractNonce(h, r, s, d, curveSpec); - // Uncomment this line to check correctness of nonce calculation - // Ecdsa.checkNonceCorrectness(tc.msg, r, s, d, k, tc.curveName); - var halfN = curveSpec.n.shiftRight(1); - if (k.isBitSet(0)) countLsb += 1; - if (k.compare(halfN) == 1) countMsb += 1; - nDone += 1; - if (nDone == tc.nTests) { - if (countLsb < tc.minCount || countLsb > tc.nTests-tc.minCount) { - reject("Bias detected in the LSB of k" + - ", hash: " + tc.hashAlg + ", curve: " + tc.curveName + - ", countLSB: " + countLsb + ", countMSB: " + countMsb); - } - if (countMsb < tc.minCount || countMsb > tc.nTests-tc.minCount) { - reject("Bias detected in the MSB of k" + - ", hash: " + tc.hashAlg + ", curve: " + tc.curveName + - ", countLSB: " + countLsb + ", countMSB: " + countMsb); - } - resolve(); + return Ecdsa.generateKey(tc.hashAlg, tc.curveName) + .then(function(key) { + return Ecdsa.exportKey(key.privateKey) + .then(function(keyData) { + var promises = []; + + for (var i = 0; i < tc.nTests; i++) { + promises.push( + Ecdsa.sign(key.privateKey, tc.msg, tc.hashAlg) + .then(function(sig) { + return HashUtil.digest(tc.hashAlg, tc.msg) + .then(function(digest) { + var curveSpec = + EcUtil.getCurveSpec(tc.curveName); + var h = new BigInteger(new Uint8Array(digest)); + // private key value + var d = BigInteger.fromHex( + TestUtil.base64UrlToHex(keyData['d'])); + var r, s; + [r, s] = Ecdsa.extractSig(sig); + var k = + Ecdsa.extractNonce(h, r, s, d, curveSpec); + // Uncomment this line to check correctness of + // nonce calculation + // Ecdsa.checkNonceCorrectness(tc.msg, r, s, d, + // k, tc.curveName); + var halfN = curveSpec.n.shiftRight(1); + if (k.isBitSet(0)) countLsb += 1; + if (k.compare(halfN) == 1) countMsb += 1; + }); + })); } + + return Promise.all(promises).then(function() { + if (countLsb < tc.minCount || + countLsb > tc.nTests - tc.minCount) { + reject( + 'Bias detected in the LSB of k' + + ', hash: ' + tc.hashAlg + ', curve: ' + tc.curveName + + ', countLSB: ' + countLsb + ', countMSB: ' + countMsb); + } + if (countMsb < tc.minCount || + countMsb > tc.nTests - tc.minCount) { + reject( + 'Bias detected in the MSB of k' + + ', hash: ' + tc.hashAlg + ', curve: ' + tc.curveName + + ', countLSB: ' + countLsb + ', countMSB: ' + countMsb); + } + }); + }) + .catch(function(err) { + throw new Error('Failed to export private key: ' + err); }); - }).catch(function(err){ - reject('Failed to sign: ' + err); - }); - }).catch(function(err){ - reject('Failed to export private key: ' + err); - }); - }).catch(function(err){ - reject('Failed to generate key: ' + err); + }) + .catch(function(err) { + throw new Error('Failed to generate key: ' + err); }); - } - }); - return promise; }; /** * Parameters of a ECDSA bias test. - * @param {!string} hashAlg The hash algorithm - * @param {!string} curveName The curve name + * @param {string} hashAlg The hash algorithm + * @param {string} curveName The curve name * @param {!ArrayBuffer} msg The message that was signed * @param {!number} nTests The number of key to be generated * @param {!number} minCount @@ -362,17 +359,19 @@ var EcdsaBiasTestCase = function(hashAlg, curveName, msg, nTests, minCount) { */ function testEcdsaBiasAll() { var testCase = new goog.testing.TestCase(); - testCase.promiseTimeout = 120*1000; - var msg = TestUtil.hexToArrayBuffer('48656c6c6f'); // msg = 'Hello' + testCase.promiseTimeout = 120 * 1000; + var msg = TestUtil.hexToArrayBuffer('48656c6c6f'); // msg = 'Hello' var nTests = 1024; var minCount = 410; - var biasTest256 = new EcdsaBiasTestCase('SHA-256', 'P-256', msg, nTests, minCount); + var biasTest256 = + new EcdsaBiasTestCase('SHA-256', 'P-256', msg, nTests, minCount); testCase.addNewTest('bias256', Ecdsa.testBias, biasTest256); - var biasTest384 = new EcdsaBiasTestCase('SHA-384', 'P-384', msg, nTests, minCount); + var biasTest384 = + new EcdsaBiasTestCase('SHA-384', 'P-384', msg, nTests, minCount); testCase.addNewTest('bias384', Ecdsa.testBias, biasTest384); - var biasTest521 = new EcdsaBiasTestCase('SHA-512', 'P-521', msg, nTests, minCount); + var biasTest521 = + new EcdsaBiasTestCase('SHA-512', 'P-521', msg, nTests, minCount); testCase.addNewTest('bias521', Ecdsa.testBias, biasTest521); - return testCase.runTestsReturningPromise() - .then(wycheproof.TestUtil.checkTestCaseResult); + return testCase.runTestsReturningPromise().then( + wycheproof.TestUtil.checkTestCaseResult); } -