mirror of
https://github.com/servo/servo.git
synced 2025-08-08 23:15:33 +01:00
Update web-platform-tests to revision dc5cbf088edcdb266541d4e5a76149a2c6e716a0
This commit is contained in:
parent
1d40075f03
commit
079092dfea
2381 changed files with 90360 additions and 17722 deletions
|
@ -0,0 +1,269 @@
|
|||
|
||||
function run_test() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
var pkcs8 = {
|
||||
"P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]),
|
||||
"P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]),
|
||||
"P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196])
|
||||
};
|
||||
|
||||
var spki = {
|
||||
"P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]),
|
||||
"P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]),
|
||||
"P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245])
|
||||
};
|
||||
|
||||
var sizes = {
|
||||
"P-521": 66,
|
||||
"P-256": 32,
|
||||
"P-384": 48
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]),
|
||||
"P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]),
|
||||
"P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45])
|
||||
};
|
||||
|
||||
importKeys(pkcs8, spki, sizes)
|
||||
.then(function(results) {
|
||||
publicKeys = results.publicKeys;
|
||||
privateKeys = results.privateKeys;
|
||||
ecdsaKeyPairs = results.ecdsaKeyPairs;
|
||||
noDeriveBitsKeys = results.noDeriveBitsKeys;
|
||||
|
||||
Object.keys(sizes).forEach(function(namedCurve) {
|
||||
// Basic success case
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " good parameters");
|
||||
|
||||
// Case insensitivity check
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " mixed case parameters");
|
||||
|
||||
// Null length
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], null)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " with null length");
|
||||
|
||||
// Shorter than entire derivation per algorithm
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 32)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 32), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " short result");
|
||||
|
||||
// Non-multiple of 8
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " non-multiple of 8 bits");
|
||||
|
||||
// Errors to test:
|
||||
|
||||
// - missing public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH"}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " missing public curve");
|
||||
|
||||
// - Non CryptoKey public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property of algorithm is not a CryptoKey");
|
||||
|
||||
// - wrong named curve
|
||||
promise_test(function(test) {
|
||||
publicKey = publicKeys["P-256"];
|
||||
if (namedCurve === "P-256") {
|
||||
publicKey = publicKeys["P-384"];
|
||||
}
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " mismatched curves");
|
||||
|
||||
// - not ECDH public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property of algorithm is not an ECDSA public key");
|
||||
|
||||
// - No deriveBits usage in baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveBitsKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " no deriveBits usage for base key");
|
||||
|
||||
// - Use public key for baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " base key is not a private key");
|
||||
|
||||
// - Use private key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property value is a private key");
|
||||
|
||||
// - Use secret key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"])
|
||||
.then(function(secretKey) {
|
||||
subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
});
|
||||
}, namedCurve + " public property value is a secret key");
|
||||
|
||||
// - Length greater than 256, 384, 521 for particular curves OperationError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] + 8)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " asking for too many bits");
|
||||
});
|
||||
done()
|
||||
});
|
||||
|
||||
function importKeys(pkcs8, spki, sizes) {
|
||||
var privateKeys = {};
|
||||
var publicKeys = {};
|
||||
var ecdsaKeyPairs = {};
|
||||
var noDeriveBitsKeys = {};
|
||||
|
||||
var promises = [];
|
||||
Object.keys(pkcs8).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(pkcs8).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, ["deriveKey"])
|
||||
.then(function(key) {
|
||||
noDeriveBitsKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(spki).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("spki", spki[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(sizes).forEach(function(namedCurve) {
|
||||
var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"])
|
||||
.then(function(keyPair) {
|
||||
ecdsaKeyPairs[namedCurve] = keyPair;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveBitsKeys: noDeriveBitsKeys}});
|
||||
}
|
||||
|
||||
// Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is
|
||||
// omitted, the two values must be the same length and have the same contents
|
||||
// in every byte. If bitCount is included, only that leading number of bits
|
||||
// have to match.
|
||||
function equalBuffers(a, b, bitCount) {
|
||||
var remainder;
|
||||
|
||||
if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
var length = a.byteLength;
|
||||
if (typeof bitCount !== "undefined") {
|
||||
length = Math.floor(bitCount / 8);
|
||||
}
|
||||
|
||||
for (var i=0; i<length; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bitCount !== "undefined") {
|
||||
remainder = bitCount % 8;
|
||||
return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("ecdh_bits.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,238 @@
|
|||
|
||||
function run_test() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
var pkcs8 = {
|
||||
"P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]),
|
||||
"P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]),
|
||||
"P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196])
|
||||
};
|
||||
|
||||
var spki = {
|
||||
"P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]),
|
||||
"P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]),
|
||||
"P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245])
|
||||
};
|
||||
|
||||
var sizes = {
|
||||
"P-521": 66,
|
||||
"P-256": 32,
|
||||
"P-384": 48
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]),
|
||||
"P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]),
|
||||
"P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45])
|
||||
};
|
||||
|
||||
importKeys(pkcs8, spki, sizes)
|
||||
.then(function(results) {
|
||||
publicKeys = results.publicKeys;
|
||||
privateKeys = results.privateKeys;
|
||||
ecdsaKeyPairs = results.ecdsaKeyPairs;
|
||||
noDeriveKeyKeys = results.noDeriveKeyKeys;
|
||||
|
||||
Object.keys(sizes).forEach(function(namedCurve) {
|
||||
// Basic success case
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " good parameters");
|
||||
|
||||
// Case insensitivity check
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " mixed case parameters");
|
||||
// Errors to test:
|
||||
|
||||
// - missing public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH"}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " missing public curve");
|
||||
|
||||
// - Non CryptoKey public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property of algorithm is not a CryptoKey");
|
||||
|
||||
// - wrong named curve
|
||||
promise_test(function(test) {
|
||||
publicKey = publicKeys["P-256"];
|
||||
if (namedCurve === "P-256") {
|
||||
publicKey = publicKeys["P-384"];
|
||||
}
|
||||
return subtle.deriveKey({name: "ECDH", public: publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " mismatched curves");
|
||||
|
||||
// - not ECDH public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property of algorithm is not an ECDSA public key");
|
||||
|
||||
// - No deriveKey usage in baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveKeyKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " no deriveKey usage for base key");
|
||||
|
||||
// - Use public key for baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " base key is not a private key");
|
||||
|
||||
// - Use private key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, namedCurve + " public property value is a private key");
|
||||
|
||||
// - Use secret key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(secretKey) {
|
||||
subtle.deriveKey({name: "ECDH", public: secretKey}, privateKeys[namedCurve], {name: "AES-CBC", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
});
|
||||
}, namedCurve + " public property value is a secret key");
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
function importKeys(pkcs8, spki, sizes) {
|
||||
var privateKeys = {};
|
||||
var publicKeys = {};
|
||||
var ecdsaKeyPairs = {};
|
||||
var noDeriveKeyKeys = {};
|
||||
|
||||
var promises = [];
|
||||
Object.keys(pkcs8).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(pkcs8).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, ["deriveBits"])
|
||||
.then(function(key) {
|
||||
noDeriveKeyKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(spki).forEach(function(namedCurve) {
|
||||
var operation = subtle.importKey("spki", spki[namedCurve],
|
||||
{name: "ECDH", namedCurve: namedCurve},
|
||||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[namedCurve] = key;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(sizes).forEach(function(namedCurve) {
|
||||
var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"])
|
||||
.then(function(keyPair) {
|
||||
ecdsaKeyPairs[namedCurve] = keyPair;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveKeyKeys: noDeriveKeyKeys}});
|
||||
}
|
||||
|
||||
// Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is
|
||||
// omitted, the two values must be the same length and have the same contents
|
||||
// in every byte. If bitCount is included, only that leading number of bits
|
||||
// have to match.
|
||||
function equalBuffers(a, b, bitCount) {
|
||||
var remainder;
|
||||
|
||||
if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
var length = a.byteLength;
|
||||
if (typeof bitCount !== "undefined") {
|
||||
length = Math.floor(bitCount / 8);
|
||||
}
|
||||
|
||||
for (var i=0; i<length; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bitCount !== "undefined") {
|
||||
remainder = bitCount % 8;
|
||||
return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("ecdh_keys.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,294 @@
|
|||
|
||||
function run_test() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
// hkdf2_vectors sets up test data with the correct derivations for each
|
||||
// test case.
|
||||
var testData = getTestData();
|
||||
var derivedKeys = testData.derivedKeys;
|
||||
var salts = testData.salts;
|
||||
var derivations = testData.derivations;
|
||||
var infos = testData.infos;
|
||||
|
||||
// What kinds of keys can be created with deriveKey? The following:
|
||||
var derivedKeyTypes = testData.derivedKeyTypes;
|
||||
|
||||
setUpBaseKeys(derivedKeys)
|
||||
.then(function(allKeys) {
|
||||
// We get several kinds of base keys. Normal ones that can be used for
|
||||
// derivation operations, ones that lack the deriveBits usage, ones
|
||||
// that lack the deriveKeys usage, and one key that is for the wrong
|
||||
// algorithm (not HKDF in this case).
|
||||
var baseKeys = allKeys.baseKeys;
|
||||
var noBits = allKeys.noBits;
|
||||
var noKey = allKeys.noKey;
|
||||
var wrongKey = allKeys.wrongKey;
|
||||
|
||||
// Test each combination of derivedKey size, salt size, hash function,
|
||||
// and number of iterations. The derivations object is structured in
|
||||
// that way, so navigate it to run tests and compare with correct results.
|
||||
Object.keys(derivations).forEach(function(derivedKeySize) {
|
||||
Object.keys(derivations[derivedKeySize]).forEach(function(saltSize) {
|
||||
Object.keys(derivations[derivedKeySize][saltSize]).forEach(function(hashName) {
|
||||
Object.keys(derivations[derivedKeySize][saltSize][hashName]).forEach(function(infoSize) {
|
||||
var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info";
|
||||
var algorithm = {name: "HKDF", salt: salts[saltSize], hash: hashName};
|
||||
if (infoSize !== "missing") {
|
||||
algorithm.info = infos[infoSize];
|
||||
}
|
||||
|
||||
// Check for correct deriveBits result
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[derivedKeySize][saltSize][hashName][infoSize]), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, testName);
|
||||
|
||||
// 0 length (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 0)
|
||||
.then(function(derivation) {
|
||||
assert_equals(derivation.byteLength, 0, "Derived correctly empty key");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with 0 length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with 0 length");
|
||||
|
||||
// Check for correct deriveKey results for every kind of
|
||||
// key that can be created by the deriveKeys operation.
|
||||
derivedKeyTypes.forEach(function(derivedKeyType) {
|
||||
var testName = "Derived key of type ";
|
||||
Object.keys(derivedKeyType.algorithm).forEach(function(prop) {
|
||||
testName += prop + ": " + derivedKeyType.algorithm[prop] + " ";
|
||||
});
|
||||
testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info";
|
||||
|
||||
// Test the particular key derivation.
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
// Need to export the key to see that the correct bits were set.
|
||||
return subtle.exportKey("raw", key)
|
||||
.then(function(buffer) {
|
||||
assert_true(equalBuffers(buffer, derivations[derivedKeySize][saltSize][hashName][infoSize].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value");
|
||||
}, function(err) {
|
||||
assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
|
||||
});
|
||||
}, testName);
|
||||
|
||||
// Test various error conditions for deriveKey:
|
||||
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
var badHash = hashName.substring(0, 3) + hashName.substring(4);
|
||||
promise_test(function(test) {
|
||||
var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash};
|
||||
return subtle.deriveKey(badAlgorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("bad hash name should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with bad hash name " + badHash);
|
||||
|
||||
// - baseKey usages missing "deriveKey" (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey(algorithm, noKey[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with missing deriveKey usage");
|
||||
|
||||
// - baseKey algorithm does not match HKDF (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey(algorithm, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with wrong (ECDH) key");
|
||||
|
||||
});
|
||||
|
||||
// Test various error conditions for deriveBits below:
|
||||
// length null (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], null)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("null length should have thrown an TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "deriveBits with null length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with null length");
|
||||
|
||||
// length not multiple of 8 (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 44)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-multiple of 8 length should have thrown an OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with non-multiple of 8 length");
|
||||
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
var badHash = hashName.substring(0, 3) + hashName.substring(4);
|
||||
promise_test(function(test) {
|
||||
var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash};
|
||||
return subtle.deriveBits(badAlgorithm, baseKeys[derivedKeySize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("bad hash name should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with bad hash name " + badHash);
|
||||
|
||||
// - baseKey usages missing "deriveBits" (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, noBits[derivedKeySize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with missing deriveBits usage");
|
||||
|
||||
// - baseKey algorithm does not match HKDF (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, wrongKey, 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with wrong (ECDH) key");
|
||||
});
|
||||
});
|
||||
|
||||
// - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError)
|
||||
var nonDigestHash = "PBKDF2";
|
||||
Object.keys(infos).forEach(function(infoSize) {
|
||||
var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info";
|
||||
var algorithm = {name: "HKDF", salt: salts[saltSize], hash: nonDigestHash};
|
||||
if (infoSize !== "missing") {
|
||||
algorithm.info = infos[infoSize];
|
||||
}
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-digest algorithm should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with non-digest algorithm " + nonDigestHash);
|
||||
|
||||
derivedKeyTypes.forEach(function(derivedKeyType) {
|
||||
var testName = "Derived key of type ";
|
||||
Object.keys(derivedKeyType.algorithm).forEach(function(prop) {
|
||||
testName += prop + ": " + derivedKeyType.algorithm[prop] + " ";
|
||||
});
|
||||
testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info";
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-digest algorithm should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
}, function(err) {
|
||||
test(function(test) {
|
||||
assert_unreached("setUpBaseKeys failed with error '" + err.message + "'");
|
||||
}, "setUpBaseKeys");
|
||||
done();
|
||||
});
|
||||
|
||||
// Deriving bits and keys requires starting with a base key, which is created
|
||||
// by importing a derivedKey. setUpBaseKeys returns a promise that yields the
|
||||
// necessary base keys.
|
||||
function setUpBaseKeys(derivedKeys) {
|
||||
var promises = [];
|
||||
|
||||
var baseKeys = {};
|
||||
var noBits = {};
|
||||
var noKey = {};
|
||||
var wrongKey = null;
|
||||
|
||||
Object.keys(derivedKeys).forEach(function(derivedKeySize) {
|
||||
var promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey", "deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
baseKeys[derivedKeySize] = baseKey;
|
||||
}, function(err) {
|
||||
baseKeys[derivedKeySize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
noKey[derivedKeySize] = baseKey;
|
||||
}, function(err) {
|
||||
noKey[derivedKeySize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey"])
|
||||
.then(function(baseKey) {
|
||||
noBits[derivedKeySize] = baseKey;
|
||||
}, function(err) {
|
||||
noBits[derivedKeySize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
wrongKey = baseKey.privateKey;
|
||||
}, function(err) {
|
||||
wrongKey = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
|
||||
return Promise.all(promises).then(function() {
|
||||
return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey};
|
||||
});
|
||||
}
|
||||
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("hkdf_vectors.js");
|
||||
importScripts("hkdf.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,276 @@
|
|||
|
||||
function getTestData() {
|
||||
|
||||
// deriveBits and deriveKey take as input:
|
||||
// - derivedKey (actually, a CryptoKey representing a derivedKey)
|
||||
// - salt (BufferSource)
|
||||
// - hash (which one to use)
|
||||
// - iterations (how many times to use it)
|
||||
|
||||
// deriveBits also takes a length. deriveKey uses the length of the output key
|
||||
// - length is the number of bits, NOT octets, but it MUST be a multiple of 8
|
||||
// - note that result of length(n) is first n bits of length(m) if m>n
|
||||
|
||||
// Variations to test:
|
||||
// - empty, short, and fairly long derivedKey
|
||||
// - empty, short, and fairly long salt
|
||||
// - SHA-1, SHA-256, SHA-384, SHA-512 hash
|
||||
// - 1, 1000, and 100000 million iterations
|
||||
|
||||
// Test cases to generate: 3 * 3 * 4 * 3 = 108
|
||||
|
||||
// Error conditions to test:
|
||||
// - length null (OperationError)
|
||||
// - length not a multiple of 8 (OperationError)
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
// - legal algorithm name but not digest one (e.g., AES-CBC) (NotSupportedError)
|
||||
// - baseKey usages missing "deriveBits" (InvalidAccessError)
|
||||
// - baseKey algorithm does not match HKDF (InvalidAccessError)
|
||||
// - 0 iterations
|
||||
|
||||
var derivedKeyTypes = [
|
||||
{algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CBC", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CBC", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "AES-KW", length: 192}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "AES-KW", length: 256}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-1", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-256", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-384", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-512", length: 256}, usages: ["sign", "verify"]}
|
||||
];
|
||||
|
||||
var derivedKeys = {
|
||||
"short": new Uint8Array([80, 64, 115, 115, 119, 48, 114, 100]),
|
||||
"long": new Uint8Array([85, 115, 101, 114, 115, 32, 115, 104, 111, 117, 108, 100, 32, 112, 105, 99, 107, 32, 108, 111, 110, 103, 32, 112, 97, 115, 115, 112, 104, 114, 97, 115, 101, 115, 32, 40, 110, 111, 116, 32, 117, 115, 101, 32, 115, 104, 111, 114, 116, 32, 112, 97, 115, 115, 119, 111, 114, 100, 115, 41, 33]),
|
||||
"empty": new Uint8Array([])
|
||||
};
|
||||
|
||||
var salts = {
|
||||
"normal": new Uint8Array([83, 111, 100, 105, 117, 109, 32, 67, 104, 108, 111, 114, 105, 100, 101, 32, 99, 111, 109, 112, 111, 117, 110, 100]),
|
||||
"empty": new Uint8Array([]),
|
||||
"missing": null
|
||||
};
|
||||
|
||||
var infos = {
|
||||
"normal": new Uint8Array([72, 75, 68, 70, 32, 101, 120, 116, 114, 97, 32, 105, 110, 102, 111]),
|
||||
"empty": new Uint8Array([]),
|
||||
"missing": null
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"short": {
|
||||
"normal": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([25, 186, 116, 54, 142, 107, 153, 51, 144, 242, 127, 233, 167, 208, 43, 195, 56, 23, 63, 114, 190, 113, 161, 159, 199, 68, 252, 219, 63, 212, 184, 75]),
|
||||
"empty": new Uint8Array([151, 96, 31, 78, 12, 83, 165, 211, 243, 162, 129, 0, 153, 188, 104, 32, 236, 80, 8, 52, 52, 118, 155, 89, 252, 36, 164, 23, 169, 84, 55, 52]),
|
||||
"missing": new Uint8Array([151, 96, 31, 78, 12, 83, 165, 211, 243, 162, 129, 0, 153, 188, 104, 32, 236, 80, 8, 52, 52, 118, 155, 89, 252, 36, 164, 23, 169, 84, 55, 52])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([75, 189, 109, 178, 67, 95, 182, 150, 21, 127, 96, 137, 201, 119, 195, 199, 63, 62, 172, 94, 243, 221, 107, 170, 230, 4, 203, 83, 191, 187, 21, 62]),
|
||||
"empty": new Uint8Array([47, 49, 87, 231, 254, 12, 16, 176, 18, 152, 200, 240, 136, 106, 144, 237, 207, 128, 171, 222, 245, 219, 193, 223, 43, 20, 130, 83, 43, 82, 185, 52]),
|
||||
"missing": new Uint8Array([47, 49, 87, 231, 254, 12, 16, 176, 18, 152, 200, 240, 136, 106, 144, 237, 207, 128, 171, 222, 245, 219, 193, 223, 43, 20, 130, 83, 43, 82, 185, 52])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([5, 173, 34, 237, 33, 56, 201, 96, 14, 77, 158, 39, 37, 222, 211, 1, 245, 210, 135, 251, 251, 87, 2, 249, 153, 188, 101, 54, 211, 237, 239, 152]),
|
||||
"empty": new Uint8Array([213, 27, 111, 183, 229, 153, 202, 48, 197, 238, 38, 69, 147, 228, 184, 95, 34, 32, 199, 195, 171, 0, 49, 87, 191, 248, 203, 79, 54, 156, 117, 96]),
|
||||
"missing": new Uint8Array([213, 27, 111, 183, 229, 153, 202, 48, 197, 238, 38, 69, 147, 228, 184, 95, 34, 32, 199, 195, 171, 0, 49, 87, 191, 248, 203, 79, 54, 156, 117, 96])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([42, 245, 144, 30, 40, 132, 156, 40, 68, 56, 87, 56, 106, 161, 172, 59, 177, 39, 233, 38, 49, 193, 192, 81, 72, 45, 102, 144, 148, 23, 114, 180]),
|
||||
"empty": new Uint8Array([158, 75, 113, 144, 51, 116, 33, 1, 233, 15, 26, 214, 30, 47, 243, 180, 37, 104, 99, 102, 114, 150, 215, 67, 137, 241, 240, 42, 242, 196, 230, 166]),
|
||||
"missing": new Uint8Array([158, 75, 113, 144, 51, 116, 33, 1, 233, 15, 26, 214, 30, 47, 243, 180, 37, 104, 99, 102, 114, 150, 215, 67, 137, 241, 240, 42, 242, 196, 230, 166])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([251, 72, 47, 242, 44, 79, 141, 70, 108, 77, 254, 110, 41, 242, 204, 46, 205, 171, 245, 136, 67, 40, 251, 240, 138, 115, 143, 217, 69, 241, 102, 203]),
|
||||
"empty": new Uint8Array([30, 2, 60, 23, 179, 64, 83, 60, 234, 239, 57, 35, 12, 184, 179, 187, 219, 246, 99, 161, 61, 96, 117, 208, 221, 50, 108, 4, 148, 120, 251, 165]),
|
||||
"missing": new Uint8Array([30, 2, 60, 23, 179, 64, 83, 60, 234, 239, 57, 35, 12, 184, 179, 187, 219, 246, 99, 161, 61, 96, 117, 208, 221, 50, 108, 4, 148, 120, 251, 165])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([241, 123, 91, 220, 216, 215, 211, 212, 96, 16, 54, 161, 148, 54, 49, 125, 22, 68, 249, 164, 224, 149, 110, 252, 14, 55, 43, 131, 172, 218, 207, 219]),
|
||||
"empty": new Uint8Array([199, 180, 116, 148, 47, 49, 248, 63, 175, 93, 20, 115, 24, 2, 177, 189, 73, 71, 133, 73, 203, 58, 143, 61, 191, 237, 196, 211, 32, 156, 245, 182]),
|
||||
"missing": new Uint8Array([199, 180, 116, 148, 47, 49, 248, 63, 175, 93, 20, 115, 24, 2, 177, 189, 73, 71, 133, 73, 203, 58, 143, 61, 191, 237, 196, 211, 32, 156, 245, 182])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([193, 38, 241, 230, 242, 90, 157, 228, 44, 247, 212, 39, 5, 154, 82, 237, 150, 1, 242, 154, 88, 21, 203, 251, 198, 75, 199, 246, 104, 198, 163, 65]),
|
||||
"empty": new Uint8Array([50, 21, 195, 240, 141, 231, 5, 73, 176, 81, 183, 3, 55, 69, 168, 24, 79, 140, 186, 166, 177, 115, 83, 48, 210, 188, 182, 177, 111, 70, 66, 239]),
|
||||
"missing": new Uint8Array([50, 21, 195, 240, 141, 231, 5, 73, 176, 81, 183, 3, 55, 69, 168, 24, 79, 140, 186, 166, 177, 115, 83, 48, 210, 188, 182, 177, 111, 70, 66, 239])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([115, 60, 139, 107, 207, 172, 135, 92, 127, 8, 152, 42, 110, 63, 251, 86, 10, 206, 166, 241, 101, 71, 110, 184, 52, 96, 185, 53, 62, 212, 29, 254]),
|
||||
"empty": new Uint8Array([200, 225, 39, 116, 19, 83, 5, 201, 20, 127, 44, 196, 118, 110, 94, 173, 37, 216, 244, 87, 185, 161, 149, 61, 82, 103, 115, 97, 206, 213, 88, 251]),
|
||||
"missing": new Uint8Array([200, 225, 39, 116, 19, 83, 5, 201, 20, 127, 44, 196, 118, 110, 94, 173, 37, 216, 244, 87, 185, 161, 149, 61, 82, 103, 115, 97, 206, 213, 88, 251])
|
||||
}
|
||||
},
|
||||
"missing": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([251, 72, 47, 242, 44, 79, 141, 70, 108, 77, 254, 110, 41, 242, 204, 46, 205, 171, 245, 136, 67, 40, 251, 240, 138, 115, 143, 217, 69, 241, 102, 203]),
|
||||
"empty": new Uint8Array([30, 2, 60, 23, 179, 64, 83, 60, 234, 239, 57, 35, 12, 184, 179, 187, 219, 246, 99, 161, 61, 96, 117, 208, 221, 50, 108, 4, 148, 120, 251, 165]),
|
||||
"missing": new Uint8Array([30, 2, 60, 23, 179, 64, 83, 60, 234, 239, 57, 35, 12, 184, 179, 187, 219, 246, 99, 161, 61, 96, 117, 208, 221, 50, 108, 4, 148, 120, 251, 165])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([241, 123, 91, 220, 216, 215, 211, 212, 96, 16, 54, 161, 148, 54, 49, 125, 22, 68, 249, 164, 224, 149, 110, 252, 14, 55, 43, 131, 172, 218, 207, 219]),
|
||||
"empty": new Uint8Array([199, 180, 116, 148, 47, 49, 248, 63, 175, 93, 20, 115, 24, 2, 177, 189, 73, 71, 133, 73, 203, 58, 143, 61, 191, 237, 196, 211, 32, 156, 245, 182]),
|
||||
"missing": new Uint8Array([199, 180, 116, 148, 47, 49, 248, 63, 175, 93, 20, 115, 24, 2, 177, 189, 73, 71, 133, 73, 203, 58, 143, 61, 191, 237, 196, 211, 32, 156, 245, 182])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([193, 38, 241, 230, 242, 90, 157, 228, 44, 247, 212, 39, 5, 154, 82, 237, 150, 1, 242, 154, 88, 21, 203, 251, 198, 75, 199, 246, 104, 198, 163, 65]),
|
||||
"empty": new Uint8Array([50, 21, 195, 240, 141, 231, 5, 73, 176, 81, 183, 3, 55, 69, 168, 24, 79, 140, 186, 166, 177, 115, 83, 48, 210, 188, 182, 177, 111, 70, 66, 239]),
|
||||
"missing": new Uint8Array([50, 21, 195, 240, 141, 231, 5, 73, 176, 81, 183, 3, 55, 69, 168, 24, 79, 140, 186, 166, 177, 115, 83, 48, 210, 188, 182, 177, 111, 70, 66, 239])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([115, 60, 139, 107, 207, 172, 135, 92, 127, 8, 152, 42, 110, 63, 251, 86, 10, 206, 166, 241, 101, 71, 110, 184, 52, 96, 185, 53, 62, 212, 29, 254]),
|
||||
"empty": new Uint8Array([200, 225, 39, 116, 19, 83, 5, 201, 20, 127, 44, 196, 118, 110, 94, 173, 37, 216, 244, 87, 185, 161, 149, 61, 82, 103, 115, 97, 206, 213, 88, 251]),
|
||||
"missing": new Uint8Array([200, 225, 39, 116, 19, 83, 5, 201, 20, 127, 44, 196, 118, 110, 94, 173, 37, 216, 244, 87, 185, 161, 149, 61, 82, 103, 115, 97, 206, 213, 88, 251])
|
||||
}
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"normal": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([249, 21, 113, 181, 33, 247, 238, 241, 62, 87, 58, 164, 99, 120, 101, 158, 243, 183, 243, 111, 253, 209, 187, 5, 93, 178, 205, 119, 210, 96, 196, 103]),
|
||||
"empty": new Uint8Array([104, 175, 28, 44, 246, 185, 55, 13, 32, 84, 52, 71, 152, 189, 187, 24, 71, 204, 244, 7, 183, 101, 43, 121, 61, 209, 54, 212, 100, 14, 3, 72]),
|
||||
"missing": new Uint8Array([104, 175, 28, 44, 246, 185, 55, 13, 32, 84, 52, 71, 152, 189, 187, 24, 71, 204, 244, 7, 183, 101, 43, 121, 61, 209, 54, 212, 100, 14, 3, 72])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([113, 10, 174, 47, 223, 136, 158, 69, 254, 15, 185, 149, 178, 194, 107, 51, 235, 152, 134, 80, 236, 15, 174, 241, 103, 2, 138, 122, 108, 203, 54, 56]),
|
||||
"empty": new Uint8Array([229, 222, 86, 128, 129, 199, 30, 86, 39, 80, 130, 152, 113, 195, 66, 117, 129, 4, 118, 94, 214, 243, 6, 240, 97, 60, 157, 75, 179, 54, 242, 170]),
|
||||
"missing": new Uint8Array([229, 222, 86, 128, 129, 199, 30, 86, 39, 80, 130, 152, 113, 195, 66, 117, 129, 4, 118, 94, 214, 243, 6, 240, 97, 60, 157, 75, 179, 54, 242, 170])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([127, 149, 126, 220, 188, 227, 203, 11, 112, 86, 110, 30, 182, 14, 253, 30, 64, 90, 19, 48, 76, 102, 29, 54, 99, 119, 129, 9, 191, 6, 137, 156]),
|
||||
"empty": new Uint8Array([48, 98, 243, 207, 26, 115, 11, 156, 239, 81, 240, 44, 29, 250, 200, 94, 217, 30, 75, 0, 101, 235, 80, 202, 159, 216, 176, 16, 126, 114, 135, 51]),
|
||||
"missing": new Uint8Array([48, 98, 243, 207, 26, 115, 11, 156, 239, 81, 240, 44, 29, 250, 200, 94, 217, 30, 75, 0, 101, 235, 80, 202, 159, 216, 176, 16, 126, 114, 135, 51])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([49, 183, 214, 133, 48, 168, 99, 231, 23, 192, 129, 202, 105, 23, 182, 134, 80, 179, 221, 154, 41, 243, 6, 6, 226, 202, 209, 153, 190, 193, 77, 19]),
|
||||
"empty": new Uint8Array([229, 121, 209, 249, 231, 240, 142, 111, 153, 15, 252, 252, 206, 30, 210, 1, 197, 227, 126, 98, 205, 246, 6, 240, 186, 74, 202, 128, 66, 127, 188, 68]),
|
||||
"missing": new Uint8Array([229, 121, 209, 249, 231, 240, 142, 111, 153, 15, 252, 252, 206, 30, 210, 1, 197, 227, 126, 98, 205, 246, 6, 240, 186, 74, 202, 128, 66, 127, 188, 68])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([97, 158, 182, 249, 40, 115, 149, 187, 213, 237, 106, 103, 201, 104, 70, 90, 216, 43, 108, 85, 159, 60, 56, 182, 4, 187, 176, 143, 88, 50, 11, 3]),
|
||||
"empty": new Uint8Array([255, 68, 123, 66, 61, 131, 254, 118, 131, 108, 50, 51, 114, 40, 181, 107, 91, 217, 191, 104, 213, 142, 125, 202, 75, 124, 202, 132, 42, 69, 225, 26]),
|
||||
"missing": new Uint8Array([255, 68, 123, 66, 61, 131, 254, 118, 131, 108, 50, 51, 114, 40, 181, 107, 91, 217, 191, 104, 213, 142, 125, 202, 75, 124, 202, 132, 42, 69, 225, 26])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([19, 62, 138, 127, 127, 244, 51, 105, 12, 200, 132, 50, 194, 163, 56, 194, 119, 229, 193, 55, 86, 255, 135, 143, 70, 117, 63, 230, 165, 100, 227, 229]),
|
||||
"empty": new Uint8Array([222, 84, 247, 238, 200, 12, 156, 198, 109, 52, 159, 201, 135, 248, 13, 70, 29, 178, 239, 79, 244, 225, 133, 5, 210, 139, 216, 12, 180, 44, 125, 118]),
|
||||
"missing": new Uint8Array([222, 84, 247, 238, 200, 12, 156, 198, 109, 52, 159, 201, 135, 248, 13, 70, 29, 178, 239, 79, 244, 225, 133, 5, 210, 139, 216, 12, 180, 44, 125, 118])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([173, 185, 60, 219, 206, 121, 183, 213, 17, 89, 182, 192, 19, 26, 43, 98, 242, 56, 40, 210, 106, 205, 104, 94, 52, 192, 101, 53, 230, 247, 116, 150]),
|
||||
"empty": new Uint8Array([71, 113, 13, 42, 117, 7, 224, 90, 29, 220, 200, 122, 124, 47, 144, 97, 119, 162, 102, 239, 185, 230, 34, 81, 12, 204, 179, 113, 60, 208, 141, 88]),
|
||||
"missing": new Uint8Array([71, 113, 13, 42, 117, 7, 224, 90, 29, 220, 200, 122, 124, 47, 144, 97, 119, 162, 102, 239, 185, 230, 34, 81, 12, 204, 179, 113, 60, 208, 141, 88])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([164, 1, 215, 201, 21, 138, 41, 229, 199, 25, 58, 185, 115, 15, 7, 72, 133, 28, 197, 186, 173, 180, 44, 173, 2, 75, 98, 144, 254, 33, 52, 54]),
|
||||
"empty": new Uint8Array([180, 247, 231, 85, 118, 116, 213, 1, 203, 251, 192, 20, 138, 216, 0, 192, 117, 1, 137, 254, 41, 90, 42, 202, 94, 27, 244, 18, 44, 133, 237, 249]),
|
||||
"missing": new Uint8Array([180, 247, 231, 85, 118, 116, 213, 1, 203, 251, 192, 20, 138, 216, 0, 192, 117, 1, 137, 254, 41, 90, 42, 202, 94, 27, 244, 18, 44, 133, 237, 249])
|
||||
}
|
||||
},
|
||||
"missing": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([97, 158, 182, 249, 40, 115, 149, 187, 213, 237, 106, 103, 201, 104, 70, 90, 216, 43, 108, 85, 159, 60, 56, 182, 4, 187, 176, 143, 88, 50, 11, 3]),
|
||||
"empty": new Uint8Array([255, 68, 123, 66, 61, 131, 254, 118, 131, 108, 50, 51, 114, 40, 181, 107, 91, 217, 191, 104, 213, 142, 125, 202, 75, 124, 202, 132, 42, 69, 225, 26]),
|
||||
"missing": new Uint8Array([255, 68, 123, 66, 61, 131, 254, 118, 131, 108, 50, 51, 114, 40, 181, 107, 91, 217, 191, 104, 213, 142, 125, 202, 75, 124, 202, 132, 42, 69, 225, 26])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([19, 62, 138, 127, 127, 244, 51, 105, 12, 200, 132, 50, 194, 163, 56, 194, 119, 229, 193, 55, 86, 255, 135, 143, 70, 117, 63, 230, 165, 100, 227, 229]),
|
||||
"empty": new Uint8Array([222, 84, 247, 238, 200, 12, 156, 198, 109, 52, 159, 201, 135, 248, 13, 70, 29, 178, 239, 79, 244, 225, 133, 5, 210, 139, 216, 12, 180, 44, 125, 118]),
|
||||
"missing": new Uint8Array([222, 84, 247, 238, 200, 12, 156, 198, 109, 52, 159, 201, 135, 248, 13, 70, 29, 178, 239, 79, 244, 225, 133, 5, 210, 139, 216, 12, 180, 44, 125, 118])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([173, 185, 60, 219, 206, 121, 183, 213, 17, 89, 182, 192, 19, 26, 43, 98, 242, 56, 40, 210, 106, 205, 104, 94, 52, 192, 101, 53, 230, 247, 116, 150]),
|
||||
"empty": new Uint8Array([71, 113, 13, 42, 117, 7, 224, 90, 29, 220, 200, 122, 124, 47, 144, 97, 119, 162, 102, 239, 185, 230, 34, 81, 12, 204, 179, 113, 60, 208, 141, 88]),
|
||||
"missing": new Uint8Array([71, 113, 13, 42, 117, 7, 224, 90, 29, 220, 200, 122, 124, 47, 144, 97, 119, 162, 102, 239, 185, 230, 34, 81, 12, 204, 179, 113, 60, 208, 141, 88])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([164, 1, 215, 201, 21, 138, 41, 229, 199, 25, 58, 185, 115, 15, 7, 72, 133, 28, 197, 186, 173, 180, 44, 173, 2, 75, 98, 144, 254, 33, 52, 54]),
|
||||
"empty": new Uint8Array([180, 247, 231, 85, 118, 116, 213, 1, 203, 251, 192, 20, 138, 216, 0, 192, 117, 1, 137, 254, 41, 90, 42, 202, 94, 27, 244, 18, 44, 133, 237, 249]),
|
||||
"missing": new Uint8Array([180, 247, 231, 85, 118, 116, 213, 1, 203, 251, 192, 20, 138, 216, 0, 192, 117, 1, 137, 254, 41, 90, 42, 202, 94, 27, 244, 18, 44, 133, 237, 249])
|
||||
}
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"normal": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([106, 134, 50, 228, 134, 137, 157, 194, 100, 241, 161, 249, 32, 89, 63, 40, 128, 128, 78, 14, 26, 218, 207, 148, 235, 78, 213, 229, 248, 61, 13, 18]),
|
||||
"empty": new Uint8Array([234, 80, 18, 254, 181, 135, 81, 213, 188, 142, 182, 78, 13, 234, 205, 89, 126, 215, 16, 201, 243, 82, 88, 174, 107, 154, 8, 122, 237, 7, 37, 174]),
|
||||
"missing": new Uint8Array([234, 80, 18, 254, 181, 135, 81, 213, 188, 142, 182, 78, 13, 234, 205, 89, 126, 215, 16, 201, 243, 82, 88, 174, 107, 154, 8, 122, 237, 7, 37, 174])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([199, 151, 225, 209, 242, 202, 183, 242, 138, 95, 67, 69, 92, 16, 89, 127, 148, 51, 133, 237, 251, 66, 140, 254, 43, 152, 190, 212, 169, 85, 215, 161]),
|
||||
"empty": new Uint8Array([224, 140, 220, 196, 197, 166, 170, 121, 157, 134, 188, 3, 169, 84, 117, 39, 110, 187, 128, 29, 154, 222, 1, 110, 20, 168, 250, 91, 100, 5, 22, 81]),
|
||||
"missing": new Uint8Array([224, 140, 220, 196, 197, 166, 170, 121, 157, 134, 188, 3, 169, 84, 117, 39, 110, 187, 128, 29, 154, 222, 1, 110, 20, 168, 250, 91, 100, 5, 22, 81])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([171, 103, 158, 103, 188, 180, 48, 95, 238, 66, 239, 148, 14, 80, 156, 221, 212, 6, 227, 73, 143, 133, 116, 24, 169, 121, 171, 57, 207, 49, 95, 81]),
|
||||
"empty": new Uint8Array([254, 66, 33, 135, 24, 140, 134, 54, 211, 109, 170, 213, 142, 242, 132, 49, 164, 51, 191, 15, 239, 114, 209, 202, 231, 53, 160, 75, 219, 190, 185, 211]),
|
||||
"missing": new Uint8Array([254, 66, 33, 135, 24, 140, 134, 54, 211, 109, 170, 213, 142, 242, 132, 49, 164, 51, 191, 15, 239, 114, 209, 202, 231, 53, 160, 75, 219, 190, 185, 211])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([223, 146, 185, 169, 250, 156, 1, 184, 152, 206, 234, 161, 49, 52, 131, 46, 49, 203, 28, 8, 29, 22, 165, 35, 92, 105, 216, 86, 81, 227, 23, 172]),
|
||||
"empty": new Uint8Array([230, 13, 67, 43, 6, 238, 136, 157, 250, 183, 41, 154, 32, 236, 35, 105, 117, 49, 209, 25, 252, 247, 102, 208, 152, 141, 10, 203, 12, 0, 199, 247]),
|
||||
"missing": new Uint8Array([230, 13, 67, 43, 6, 238, 136, 157, 250, 183, 41, 154, 32, 236, 35, 105, 117, 49, 209, 25, 252, 247, 102, 208, 152, 141, 10, 203, 12, 0, 199, 247])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([234, 203, 157, 102, 112, 255, 59, 25, 4, 119, 154, 65, 145, 1, 177, 255, 170, 189, 109, 101, 16, 189, 80, 133, 104, 1, 116, 106, 135, 31, 123, 49]),
|
||||
"empty": new Uint8Array([71, 12, 198, 83, 135, 202, 74, 16, 199, 166, 138, 59, 81, 72, 200, 229, 19, 218, 166, 49, 1, 0, 7, 57, 196, 198, 101, 155, 134, 17, 136, 132]),
|
||||
"missing": new Uint8Array([71, 12, 198, 83, 135, 202, 74, 16, 199, 166, 138, 59, 81, 72, 200, 229, 19, 218, 166, 49, 1, 0, 7, 57, 196, 198, 101, 155, 134, 17, 136, 132])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([87, 3, 145, 116, 241, 111, 84, 24, 168, 104, 86, 218, 235, 119, 246, 157, 75, 77, 80, 0, 51, 75, 109, 209, 244, 244, 179, 231, 179, 220, 185, 211]),
|
||||
"empty": new Uint8Array([157, 115, 201, 142, 121, 30, 128, 235, 229, 180, 203, 69, 105, 58, 163, 47, 221, 68, 181, 250, 62, 218, 179, 236, 130, 249, 208, 244, 214, 105, 5, 226]),
|
||||
"missing": new Uint8Array([157, 115, 201, 142, 121, 30, 128, 235, 229, 180, 203, 69, 105, 58, 163, 47, 221, 68, 181, 250, 62, 218, 179, 236, 130, 249, 208, 244, 214, 105, 5, 226])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([161, 189, 216, 195, 50, 198, 70, 74, 75, 182, 162, 242, 49, 174, 201, 164, 68, 35, 126, 171, 224, 77, 47, 85, 242, 171, 37, 212, 12, 84, 235, 238]),
|
||||
"empty": new Uint8Array([136, 95, 192, 41, 179, 34, 75, 137, 110, 9, 224, 187, 229, 235, 52, 126, 197, 158, 104, 39, 200, 232, 87, 179, 148, 245, 79, 244, 155, 136, 168, 246]),
|
||||
"missing": new Uint8Array([136, 95, 192, 41, 179, 34, 75, 137, 110, 9, 224, 187, 229, 235, 52, 126, 197, 158, 104, 39, 200, 232, 87, 179, 148, 245, 79, 244, 155, 136, 168, 246])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([183, 184, 110, 66, 42, 209, 200, 165, 113, 253, 165, 40, 218, 22, 160, 102, 244, 36, 134, 221, 64, 86, 121, 47, 217, 51, 98, 8, 142, 93, 212, 194]),
|
||||
"empty": new Uint8Array([235, 112, 240, 29, 237, 233, 175, 175, 164, 73, 238, 225, 177, 40, 101, 4, 225, 246, 35, 136, 179, 247, 221, 79, 149, 102, 151, 176, 232, 40, 254, 24]),
|
||||
"missing": new Uint8Array([235, 112, 240, 29, 237, 233, 175, 175, 164, 73, 238, 225, 177, 40, 101, 4, 225, 246, 35, 136, 179, 247, 221, 79, 149, 102, 151, 176, 232, 40, 254, 24])
|
||||
}
|
||||
},
|
||||
"missing": {
|
||||
"SHA-384": {
|
||||
"normal": new Uint8Array([234, 203, 157, 102, 112, 255, 59, 25, 4, 119, 154, 65, 145, 1, 177, 255, 170, 189, 109, 101, 16, 189, 80, 133, 104, 1, 116, 106, 135, 31, 123, 49]),
|
||||
"empty": new Uint8Array([71, 12, 198, 83, 135, 202, 74, 16, 199, 166, 138, 59, 81, 72, 200, 229, 19, 218, 166, 49, 1, 0, 7, 57, 196, 198, 101, 155, 134, 17, 136, 132]),
|
||||
"missing": new Uint8Array([71, 12, 198, 83, 135, 202, 74, 16, 199, 166, 138, 59, 81, 72, 200, 229, 19, 218, 166, 49, 1, 0, 7, 57, 196, 198, 101, 155, 134, 17, 136, 132])
|
||||
},
|
||||
"SHA-512": {
|
||||
"normal": new Uint8Array([87, 3, 145, 116, 241, 111, 84, 24, 168, 104, 86, 218, 235, 119, 246, 157, 75, 77, 80, 0, 51, 75, 109, 209, 244, 244, 179, 231, 179, 220, 185, 211]),
|
||||
"empty": new Uint8Array([157, 115, 201, 142, 121, 30, 128, 235, 229, 180, 203, 69, 105, 58, 163, 47, 221, 68, 181, 250, 62, 218, 179, 236, 130, 249, 208, 244, 214, 105, 5, 226]),
|
||||
"missing": new Uint8Array([157, 115, 201, 142, 121, 30, 128, 235, 229, 180, 203, 69, 105, 58, 163, 47, 221, 68, 181, 250, 62, 218, 179, 236, 130, 249, 208, 244, 214, 105, 5, 226])
|
||||
},
|
||||
"SHA-1": {
|
||||
"normal": new Uint8Array([161, 189, 216, 195, 50, 198, 70, 74, 75, 182, 162, 242, 49, 174, 201, 164, 68, 35, 126, 171, 224, 77, 47, 85, 242, 171, 37, 212, 12, 84, 235, 238]),
|
||||
"empty": new Uint8Array([136, 95, 192, 41, 179, 34, 75, 137, 110, 9, 224, 187, 229, 235, 52, 126, 197, 158, 104, 39, 200, 232, 87, 179, 148, 245, 79, 244, 155, 136, 168, 246]),
|
||||
"missing": new Uint8Array([136, 95, 192, 41, 179, 34, 75, 137, 110, 9, 224, 187, 229, 235, 52, 126, 197, 158, 104, 39, 200, 232, 87, 179, 148, 245, 79, 244, 155, 136, 168, 246])
|
||||
},
|
||||
"SHA-256": {
|
||||
"normal": new Uint8Array([183, 184, 110, 66, 42, 209, 200, 165, 113, 253, 165, 40, 218, 22, 160, 102, 244, 36, 134, 221, 64, 86, 121, 47, 217, 51, 98, 8, 142, 93, 212, 194]),
|
||||
"empty": new Uint8Array([235, 112, 240, 29, 237, 233, 175, 175, 164, 73, 238, 225, 177, 40, 101, 4, 225, 246, 35, 136, 179, 247, 221, 79, 149, 102, 151, 176, 232, 40, 254, 24]),
|
||||
"missing": new Uint8Array([235, 112, 240, 29, 237, 233, 175, 175, 164, 73, 238, 225, 177, 40, 101, 4, 225, 246, 35, 136, 179, 247, 221, 79, 149, 102, 151, 176, 232, 40, 254, 24])
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {derivedKeys: derivedKeys, salts: salts, derivations: derivations, derivedKeyTypes: derivedKeyTypes, infos: infos};
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
|
||||
function run_test() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
// pbkdf2_vectors sets up test data with the correct derivations for each
|
||||
// test case.
|
||||
var testData = getTestData();
|
||||
var passwords = testData.passwords;
|
||||
var salts = testData.salts;
|
||||
var derivations = testData.derivations;
|
||||
|
||||
// What kinds of keys can be created with deriveKey? The following:
|
||||
var derivedKeyTypes = testData.derivedKeyTypes;
|
||||
|
||||
setUpBaseKeys(passwords)
|
||||
.then(function(allKeys) {
|
||||
// We get several kinds of base keys. Normal ones that can be used for
|
||||
// derivation operations, ones that lack the deriveBits usage, ones
|
||||
// that lack the deriveKeys usage, and one key that is for the wrong
|
||||
// algorithm (not PBKDF2 in this case).
|
||||
var baseKeys = allKeys.baseKeys;
|
||||
var noBits = allKeys.noBits;
|
||||
var noKey = allKeys.noKey;
|
||||
var wrongKey = allKeys.wrongKey;
|
||||
|
||||
// Test each combination of password size, salt size, hash function,
|
||||
// and number of iterations. The derivations object is structured in
|
||||
// that way, so navigate it to run tests and compare with correct results.
|
||||
Object.keys(derivations).forEach(function(passwordSize) {
|
||||
Object.keys(derivations[passwordSize]).forEach(function(saltSize) {
|
||||
Object.keys(derivations[passwordSize][saltSize]).forEach(function(hashName) {
|
||||
Object.keys(derivations[passwordSize][saltSize][hashName]).forEach(function(iterations) {
|
||||
var testName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations";
|
||||
|
||||
// Check for correct deriveBits result
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[passwordSize][saltSize][hashName][iterations]), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, testName);
|
||||
|
||||
// Check for correct deriveKey results for every kind of
|
||||
// key that can be created by the deriveKeys operation.
|
||||
derivedKeyTypes.forEach(function(derivedKeyType) {
|
||||
var testName = "Derived key of type ";
|
||||
Object.keys(derivedKeyType.algorithm).forEach(function(prop) {
|
||||
testName += prop + ": " + derivedKeyType.algorithm[prop] + " ";
|
||||
});
|
||||
testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations";
|
||||
|
||||
// Test the particular key derivation.
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
// Need to export the key to see that the correct bits were set.
|
||||
return subtle.exportKey("raw", key)
|
||||
.then(function(buffer) {
|
||||
assert_true(equalBuffers(buffer, derivations[passwordSize][saltSize][hashName][iterations].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value");
|
||||
}, function(err) {
|
||||
assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
|
||||
});
|
||||
}, testName);
|
||||
|
||||
// Test various error conditions for deriveKey:
|
||||
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
var badHash = hashName.substring(0, 3) + hashName.substring(4);
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("bad hash name should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with bad hash name " + badHash);
|
||||
|
||||
// - baseKey usages missing "deriveKey" (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noKey[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with missing deriveKey usage");
|
||||
|
||||
// - baseKey algorithm does not match PBKDF2 (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(key) {
|
||||
assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with wrong (ECDH) key");
|
||||
|
||||
});
|
||||
|
||||
// Test various error conditions for deriveBits below:
|
||||
// length null (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], null)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("null length should have thrown an OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with null length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with null length");
|
||||
|
||||
// 0 length (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("0 length should have thrown an OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with 0 length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with 0 length");
|
||||
|
||||
// length not multiple of 8 (OperationError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 44)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-multiple of 8 length should have thrown an OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName + " with non-multiple of 8 length");
|
||||
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
var badHash = hashName.substring(0, 3) + hashName.substring(4);
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("bad hash name should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with bad hash name " + badHash);
|
||||
|
||||
// - baseKey usages missing "deriveBits" (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noBits[passwordSize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with missing deriveBits usage");
|
||||
|
||||
// - baseKey algorithm does not match PBKDF2 (InvalidAccessError)
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message);
|
||||
});
|
||||
}, testName + " with wrong (ECDH) key");
|
||||
});
|
||||
|
||||
// Check that 0 iterations throws proper error
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("0 iterations should have thrown an error");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "deriveBits with 0 iterations correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations");
|
||||
|
||||
derivedKeyTypes.forEach(function(derivedKeyType) {
|
||||
var testName = "Derived key of type ";
|
||||
Object.keys(derivedKeyType.algorithm).forEach(function(prop) {
|
||||
testName += prop + ": " + derivedKeyType.algorithm[prop] + " ";
|
||||
});
|
||||
testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations";
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("0 iterations should have thrown an error");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "derivekey with 0 iterations correctly threw OperationError: " + err.message);
|
||||
});
|
||||
}, testName);
|
||||
});
|
||||
});
|
||||
|
||||
// - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError)
|
||||
var nonDigestHash = "PBKDF2";
|
||||
[1, 1000, 100000].forEach(function(iterations) {
|
||||
var testName = passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations";
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-digest algorithm should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName + " with non-digest algorithm " + nonDigestHash);
|
||||
|
||||
derivedKeyTypes.forEach(function(derivedKeyType) {
|
||||
var testName = "Derived key of type ";
|
||||
Object.keys(derivedKeyType.algorithm).forEach(function(prop) {
|
||||
testName += prop + ": " + derivedKeyType.algorithm[prop] + " ";
|
||||
});
|
||||
testName += " using " + passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations";
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("non-digest algorithm should have thrown an NotSupportedError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message);
|
||||
});
|
||||
}, testName);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
}, function(err) {
|
||||
test(function(test) {
|
||||
assert_unreached("setUpBaseKeys failed with error '" + err.message + "'");
|
||||
}, "setUpBaseKeys");
|
||||
done();
|
||||
});
|
||||
|
||||
// Deriving bits and keys requires starting with a base key, which is created
|
||||
// by importing a password. setUpBaseKeys returns a promise that yields the
|
||||
// necessary base keys.
|
||||
function setUpBaseKeys(passwords) {
|
||||
var promises = [];
|
||||
|
||||
var baseKeys = {};
|
||||
var noBits = {};
|
||||
var noKey = {};
|
||||
var wrongKey = null;
|
||||
|
||||
Object.keys(passwords).forEach(function(passwordSize) {
|
||||
var promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey", "deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
baseKeys[passwordSize] = baseKey;
|
||||
}, function(err) {
|
||||
baseKeys[passwordSize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
noKey[passwordSize] = baseKey;
|
||||
}, function(err) {
|
||||
noKey[passwordSize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey"])
|
||||
.then(function(baseKey) {
|
||||
noBits[passwordSize] = baseKey;
|
||||
}, function(err) {
|
||||
noBits[passwordSize] = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"])
|
||||
.then(function(baseKey) {
|
||||
wrongKey = baseKey.privateKey;
|
||||
}, function(err) {
|
||||
wrongKey = null;
|
||||
});
|
||||
promises.push(promise);
|
||||
|
||||
|
||||
return Promise.all(promises).then(function() {
|
||||
return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey};
|
||||
});
|
||||
}
|
||||
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("pbkdf2_vectors.js");
|
||||
importScripts("pbkdf2.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,269 @@
|
|||
function getTestData() {
|
||||
|
||||
// deriveBits and deriveKey take as input:
|
||||
// - password (actually, a CryptoKey representing a password)
|
||||
// - salt (BufferSource)
|
||||
// - hash (which one to use)
|
||||
// - iterations (how many times to use it)
|
||||
|
||||
// deriveBits also takes a length. deriveKey uses the length of the output key
|
||||
// - length is the number of bits, NOT octets, but it MUST be a multiple of 8
|
||||
// - note that result of length(n) is first n bits of length(m) if m>n
|
||||
|
||||
// Variations to test:
|
||||
// - empty, short, and fairly long password
|
||||
// - empty, short, and fairly long salt
|
||||
// - SHA-1, SHA-256, SHA-384, SHA-512 hash
|
||||
// - 1, 1000, and 100000 million iterations
|
||||
|
||||
// Test cases to generate: 3 * 3 * 4 * 3 = 108
|
||||
|
||||
// Error conditions to test:
|
||||
// - length null (OperationError)
|
||||
// - length not a multiple of 8 (OperationError)
|
||||
// - illegal name for hash algorithm (NotSupportedError)
|
||||
// - legal algorithm name but not digest one (e.g., AES-CBC) (NotSupportedError)
|
||||
// - baseKey usages missing "deriveBits" (InvalidAccessError)
|
||||
// - baseKey algorithm does not match PBKDF2 (InvalidAccessError)
|
||||
// - 0 iterations
|
||||
|
||||
var derivedKeyTypes = [
|
||||
{algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CBC", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CBC", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CTR", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 192}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 256}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "AES-KW", length: 192}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "AES-KW", length: 256}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-1", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-256", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-384", length: 256}, usages: ["sign", "verify"]},
|
||||
{algorithm: {name: "HMAC", hash: "SHA-512", length: 256}, usages: ["sign", "verify"]}
|
||||
];
|
||||
|
||||
var passwords = {
|
||||
"short": new Uint8Array([80, 64, 115, 115, 119, 48, 114, 100]),
|
||||
"long": new Uint8Array([85, 115, 101, 114, 115, 32, 115, 104, 111, 117, 108, 100, 32, 112, 105, 99, 107, 32, 108, 111, 110, 103, 32, 112, 97, 115, 115, 112, 104, 114, 97, 115, 101, 115, 32, 40, 110, 111, 116, 32, 117, 115, 101, 32, 115, 104, 111, 114, 116, 32, 112, 97, 115, 115, 119, 111, 114, 100, 115, 41, 33]),
|
||||
"empty": new Uint8Array([])
|
||||
};
|
||||
|
||||
var salts = {
|
||||
"short": new Uint8Array([78, 97, 67, 108]),
|
||||
"long": new Uint8Array([83, 111, 100, 105, 117, 109, 32, 67, 104, 108, 111, 114, 105, 100, 101, 32, 99, 111, 109, 112, 111, 117, 110, 100]),
|
||||
"empty": new Uint8Array([])
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"short": {
|
||||
"short": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([170, 236, 90, 151, 109, 77, 53, 203, 32, 36, 72, 111, 201, 249, 187, 154, 163, 234, 231, 206, 242, 188, 230, 38, 100, 181, 179, 117, 28, 245, 15, 241]),
|
||||
"1": new Uint8Array([128, 205, 15, 21, 54, 67, 102, 167, 37, 81, 195, 121, 117, 247, 182, 55, 186, 137, 194, 155, 70, 57, 236, 114, 15, 105, 167, 13, 187, 237, 81, 92]),
|
||||
"100000": new Uint8Array([111, 94, 163, 198, 198, 245, 228, 131, 52, 103, 180, 124, 58, 103, 30, 101, 113, 78, 135, 7, 27, 209, 227, 109, 113, 111, 132, 107, 92, 210, 137, 128])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([134, 92, 89, 69, 225, 31, 91, 243, 221, 240, 2, 231, 203, 23, 72, 246, 34, 77, 38, 113, 232, 6, 218, 212, 170, 240, 144, 160, 67, 103, 218, 41]),
|
||||
"1": new Uint8Array([105, 244, 213, 206, 245, 199, 216, 186, 147, 142, 136, 3, 136, 200, 246, 59, 107, 36, 72, 178, 98, 109, 19, 67, 252, 92, 182, 139, 189, 127, 39, 178]),
|
||||
"100000": new Uint8Array([72, 59, 167, 242, 226, 254, 56, 44, 246, 29, 32, 178, 152, 18, 226, 212, 150, 16, 166, 0, 65, 174, 64, 236, 249, 252, 126, 241, 56, 233, 56, 118])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([83, 136, 234, 94, 98, 225, 181, 87, 152, 26, 190, 92, 228, 19, 33, 39, 88, 170, 106, 157, 44, 91, 240, 140, 1, 157, 69, 157, 186, 102, 107, 144]),
|
||||
"1": new Uint8Array([70, 36, 219, 210, 19, 115, 238, 86, 89, 193, 37, 177, 132, 238, 218, 162, 106, 51, 183, 124, 161, 19, 20, 185, 240, 201, 218, 225, 228, 78, 155, 4]),
|
||||
"100000": new Uint8Array([245, 143, 67, 95, 188, 92, 5, 134, 92, 145, 79, 217, 114, 16, 138, 9, 69, 125, 95, 154, 72, 241, 78, 117, 228, 204, 2, 217, 137, 131, 3, 138])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([78, 108, 165, 121, 87, 67, 155, 227, 167, 83, 112, 66, 66, 37, 226, 33, 29, 85, 240, 90, 240, 5, 97, 223, 63, 62, 254, 233, 17, 107, 195, 76]),
|
||||
"1": new Uint8Array([198, 188, 85, 164, 4, 173, 206, 163, 106, 26, 181, 103, 152, 8, 94, 10, 175, 105, 127, 107, 178, 193, 106, 80, 114, 248, 56, 241, 125, 254, 108, 182]),
|
||||
"100000": new Uint8Array([171, 37, 121, 101, 152, 231, 75, 41, 195, 36, 245, 186, 77, 144, 234, 125, 200, 159, 198, 137, 16, 65, 180, 213, 108, 148, 21, 101, 5, 247, 34, 192])
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([163, 16, 239, 60, 107, 58, 149, 230, 216, 202, 102, 68, 227, 220, 253, 136, 34, 42, 89, 254, 142, 0, 197, 45, 106, 18, 99, 29, 130, 193, 210, 75]),
|
||||
"1": new Uint8Array([104, 7, 52, 108, 197, 62, 222, 209, 203, 150, 74, 114, 98, 133, 137, 166, 189, 72, 53, 89, 144, 191, 223, 231, 70, 81, 9, 113, 2, 7, 5, 157]),
|
||||
"100000": new Uint8Array([44, 140, 102, 116, 200, 121, 207, 24, 80, 188, 155, 127, 189, 204, 110, 167, 171, 176, 161, 82, 33, 150, 168, 102, 135, 83, 5, 222, 165, 116, 134, 243])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([156, 23, 254, 150, 137, 94, 173, 191, 209, 204, 9, 95, 193, 187, 131, 79, 40, 229, 204, 201, 236, 150, 202, 129, 76, 255, 148, 26, 75, 244, 7, 39]),
|
||||
"1": new Uint8Array([87, 119, 2, 122, 255, 64, 81, 251, 155, 67, 193, 241, 239, 4, 99, 189, 103, 117, 17, 117, 212, 40, 161, 61, 163, 218, 132, 90, 89, 19, 50, 205]),
|
||||
"100000": new Uint8Array([180, 121, 201, 113, 92, 66, 22, 56, 220, 224, 167, 5, 252, 11, 123, 167, 213, 111, 163, 6, 49, 136, 6, 53, 128, 224, 112, 223, 241, 219, 73, 124])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([137, 211, 178, 123, 95, 110, 138, 240, 21, 242, 248, 124, 243, 104, 161, 67, 138, 32, 108, 78, 207, 95, 230, 129, 252, 59, 249, 76, 86, 33, 62, 246]),
|
||||
"1": new Uint8Array([87, 111, 124, 22, 88, 37, 190, 249, 239, 20, 180, 188, 44, 130, 70, 157, 30, 64, 143, 248, 231, 186, 48, 102, 148, 121, 127, 158, 69, 183, 102, 237]),
|
||||
"100000": new Uint8Array([30, 57, 232, 191, 102, 118, 252, 211, 21, 102, 85, 69, 122, 250, 20, 190, 231, 113, 219, 203, 252, 208, 114, 65, 199, 206, 226, 9, 167, 203, 31, 233])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([177, 167, 183, 220, 32, 223, 23, 74, 74, 14, 65, 13, 191, 175, 3, 180, 195, 117, 196, 80, 168, 157, 122, 158, 211, 73, 180, 229, 46, 100, 223, 216]),
|
||||
"1": new Uint8Array([18, 185, 15, 89, 79, 9, 8, 207, 145, 45, 101, 92, 148, 143, 156, 42, 30, 171, 133, 87, 101, 188, 18, 120, 94, 241, 138, 160, 43, 142, 126, 220]),
|
||||
"100000": new Uint8Array([212, 89, 77, 138, 27, 89, 82, 10, 72, 135, 137, 34, 166, 93, 102, 61, 40, 246, 165, 250, 73, 233, 49, 211, 0, 216, 249, 186, 249, 61, 10, 235])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([174, 181, 249, 125, 102, 39, 238, 188, 222, 107, 19, 154, 0, 137, 85, 0, 48, 247, 64, 28, 103, 224, 28, 5, 122, 51, 56, 23, 94, 63, 58, 23]),
|
||||
"1": new Uint8Array([79, 16, 137, 192, 30, 67, 139, 222, 100, 154, 55, 159, 164, 24, 251, 195, 184, 86, 37, 135, 114, 223, 233, 17, 128, 111, 155, 208, 128, 159, 188, 126]),
|
||||
"100000": new Uint8Array([215, 104, 125, 246, 199, 129, 220, 136, 214, 78, 249, 203, 175, 149, 211, 213, 209, 21, 95, 102, 178, 48, 35, 158, 110, 129, 193, 85, 12, 136, 64, 207])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([181, 172, 114, 11, 122, 190, 8, 50, 252, 81, 163, 27, 30, 197, 103, 59, 235, 30, 65, 132, 10, 223, 211, 214, 6, 232, 99, 143, 64, 6, 235, 72]),
|
||||
"1": new Uint8Array([143, 123, 125, 69, 156, 117, 47, 100, 191, 18, 190, 98, 91, 101, 212, 150, 172, 36, 234, 54, 81, 107, 22, 142, 22, 251, 2, 104, 69, 180, 232, 46]),
|
||||
"100000": new Uint8Array([186, 26, 15, 54, 186, 215, 113, 82, 101, 100, 5, 30, 185, 202, 32, 125, 161, 155, 98, 229, 55, 98, 52, 153, 118, 169, 163, 209, 176, 239, 126, 32])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([115, 111, 60, 61, 110, 188, 194, 167, 185, 112, 64, 62, 38, 150, 192, 235, 76, 209, 119, 15, 85, 241, 150, 252, 112, 137, 230, 102, 193, 31, 119, 218]),
|
||||
"1": new Uint8Array([192, 207, 251, 12, 229, 219, 53, 31, 170, 36, 218, 213, 144, 37, 131, 207, 195, 10, 159, 84, 217, 170, 105, 145, 254, 130, 29, 3, 18, 33, 39, 233]),
|
||||
"100000": new Uint8Array([28, 80, 149, 172, 154, 123, 212, 16, 239, 15, 114, 201, 147, 236, 169, 27, 176, 229, 113, 233, 178, 251, 171, 112, 79, 140, 19, 17, 145, 250, 209, 108])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([185, 210, 242, 33, 123, 78, 229, 168, 191, 3, 69, 243, 107, 44, 152, 135, 51, 245, 3, 169, 117, 223, 234, 199, 183, 19, 95, 84, 165, 242, 153, 113]),
|
||||
"1": new Uint8Array([1, 158, 84, 171, 66, 240, 4, 133, 211, 170, 27, 38, 252, 222, 33, 174, 95, 82, 203, 15, 9, 96, 255, 201, 118, 127, 37, 198, 94, 45, 178, 249]),
|
||||
"100000": new Uint8Array([167, 162, 134, 152, 41, 121, 120, 7, 179, 229, 118, 193, 120, 120, 180, 102, 68, 158, 137, 230, 4, 71, 213, 65, 119, 90, 150, 235, 124, 26, 93, 237])
|
||||
}
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"short": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([250, 164, 66, 251, 171, 244, 5, 140, 198, 83, 104, 181, 61, 126, 197, 17, 60, 9, 234, 126, 94, 55, 67, 49, 47, 75, 235, 237, 217, 128, 186, 55]),
|
||||
"1": new Uint8Array([94, 222, 136, 54, 253, 171, 238, 197, 211, 115, 59, 67, 74, 186, 196, 67, 212, 21, 25, 59, 89, 158, 9, 38, 25, 59, 0, 15, 64, 106, 90, 125]),
|
||||
"100000": new Uint8Array([246, 42, 230, 199, 135, 27, 24, 26, 167, 18, 50, 245, 235, 136, 55, 36, 152, 239, 50, 172, 10, 125, 113, 81, 25, 232, 240, 82, 235, 16, 45, 41])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([240, 146, 143, 80, 161, 85, 242, 106, 140, 156, 27, 199, 243, 181, 203, 83, 28, 83, 168, 245, 16, 64, 201, 206, 95, 199, 157, 67, 15, 240, 192, 244]),
|
||||
"1": new Uint8Array([62, 156, 18, 179, 246, 223, 182, 68, 21, 148, 236, 112, 99, 252, 169, 98, 255, 218, 16, 182, 207, 48, 184, 152, 163, 30, 249, 241, 48, 107, 17, 25]),
|
||||
"100000": new Uint8Array([151, 74, 207, 187, 15, 15, 32, 200, 30, 201, 40, 41, 243, 140, 61, 175, 8, 106, 125, 245, 139, 145, 43, 133, 109, 31, 94, 204, 147, 85, 239, 27])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([83, 180, 33, 97, 19, 78, 21, 200, 113, 171, 215, 26, 186, 19, 144, 208, 31, 76, 106, 148, 12, 170, 245, 193, 121, 37, 141, 143, 27, 29, 104, 11]),
|
||||
"1": new Uint8Array([138, 231, 47, 148, 230, 252, 213, 79, 203, 252, 166, 98, 0, 162, 17, 165, 27, 47, 132, 103, 135, 210, 11, 104, 8, 190, 223, 21, 108, 228, 108, 160]),
|
||||
"100000": new Uint8Array([167, 253, 164, 199, 157, 211, 186, 26, 135, 95, 101, 233, 36, 139, 33, 8, 153, 202, 8, 20, 174, 56, 153, 93, 140, 229, 165, 53, 96, 203, 172, 49])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([238, 235, 119, 20, 66, 10, 0, 177, 138, 206, 194, 181, 151, 157, 29, 166, 19, 115, 32, 43, 127, 139, 167, 27, 8, 98, 147, 170, 184, 89, 224, 160]),
|
||||
"1": new Uint8Array([255, 161, 233, 167, 39, 169, 44, 39, 174, 111, 116, 177, 199, 151, 143, 158, 26, 248, 96, 225, 6, 55, 99, 64, 172, 67, 217, 105, 209, 54, 64, 91]),
|
||||
"100000": new Uint8Array([222, 172, 112, 203, 227, 241, 114, 14, 53, 59, 78, 128, 22, 221, 181, 148, 117, 239, 183, 11, 106, 35, 133, 231, 53, 210, 214, 234, 109, 98, 74, 77])
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([53, 101, 133, 81, 240, 236, 19, 57, 138, 123, 69, 224, 38, 28, 253, 101, 76, 30, 82, 65, 30, 110, 69, 125, 238, 104, 244, 174, 171, 233, 37, 167]),
|
||||
"1": new Uint8Array([207, 85, 66, 44, 239, 110, 27, 196, 158, 109, 8, 43, 34, 115, 212, 128, 232, 242, 232, 130, 45, 173, 209, 70, 156, 42, 50, 217, 101, 125, 18, 241]),
|
||||
"100000": new Uint8Array([26, 186, 181, 241, 228, 97, 223, 55, 139, 136, 192, 162, 43, 231, 110, 242, 241, 98, 125, 247, 74, 199, 203, 251, 132, 189, 204, 179, 84, 188, 136, 137])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([67, 225, 32, 36, 196, 211, 84, 114, 127, 126, 88, 132, 44, 203, 96, 51, 161, 97, 214, 13, 197, 174, 81, 111, 7, 110, 74, 88, 161, 136, 13, 56]),
|
||||
"1": new Uint8Array([222, 74, 251, 192, 173, 211, 228, 211, 47, 75, 198, 225, 34, 168, 138, 228, 74, 43, 60, 207, 1, 72, 231, 118, 43, 172, 5, 196, 62, 148, 239, 127]),
|
||||
"100000": new Uint8Array([249, 169, 35, 132, 164, 234, 223, 195, 86, 6, 73, 179, 127, 182, 118, 232, 60, 69, 60, 187, 217, 159, 128, 187, 166, 240, 161, 14, 189, 21, 11, 82])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([110, 144, 200, 110, 224, 123, 135, 62, 150, 80, 113, 2, 86, 115, 255, 5, 66, 159, 103, 140, 48, 249, 27, 55, 225, 226, 218, 81, 32, 54, 211, 32]),
|
||||
"1": new Uint8Array([29, 16, 78, 165, 210, 53, 0, 106, 18, 168, 15, 113, 184, 14, 229, 40, 4, 139, 100, 204, 26, 122, 15, 48, 247, 223, 75, 162, 107, 131, 32, 199]),
|
||||
"100000": new Uint8Array([20, 16, 48, 118, 59, 249, 131, 200, 86, 77, 93, 76, 147, 95, 227, 202, 53, 73, 96, 129, 89, 172, 25, 52, 193, 89, 144, 64, 102, 140, 35, 99])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([63, 213, 135, 201, 75, 169, 70, 184, 185, 220, 205, 221, 42, 91, 116, 246, 119, 141, 79, 97, 230, 145, 248, 58, 196, 122, 47, 169, 88, 11, 253, 248]),
|
||||
"1": new Uint8Array([253, 92, 174, 184, 179, 171, 229, 137, 188, 21, 156, 78, 81, 248, 0, 87, 14, 116, 246, 67, 151, 166, 197, 238, 19, 29, 254, 217, 63, 5, 17, 170]),
|
||||
"100000": new Uint8Array([17, 153, 45, 139, 129, 51, 17, 36, 76, 84, 75, 98, 41, 41, 69, 226, 8, 212, 3, 206, 189, 107, 149, 82, 161, 165, 98, 6, 93, 153, 88, 234])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([249, 202, 20, 139, 12, 4, 24, 144, 191, 248, 131, 29, 182, 23, 71, 25, 126, 148, 206, 104, 241, 144, 237, 242, 105, 105, 75, 77, 100, 72, 97, 202]),
|
||||
"1": new Uint8Array([73, 171, 63, 159, 136, 47, 219, 158, 82, 139, 77, 159, 27, 62, 140, 113, 210, 99, 154, 191, 23, 1, 213, 110, 185, 155, 213, 18, 1, 228, 32, 255]),
|
||||
"100000": new Uint8Array([23, 73, 223, 205, 119, 229, 37, 133, 25, 234, 34, 49, 186, 44, 214, 84, 59, 7, 51, 57, 172, 155, 21, 69, 187, 100, 49, 83, 250, 246, 209, 123])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([69, 122, 121, 85, 235, 236, 236, 113, 165, 30, 251, 98, 55, 229, 177, 214, 47, 77, 234, 181, 201, 61, 123, 61, 17, 209, 231, 15, 175, 250, 65, 126]),
|
||||
"1": new Uint8Array([209, 191, 161, 166, 184, 169, 119, 131, 159, 140, 63, 157, 82, 221, 2, 16, 78, 32, 41, 192, 235, 42, 98, 8, 204, 64, 136, 22, 231, 118, 138, 140]),
|
||||
"100000": new Uint8Array([232, 5, 172, 156, 193, 216, 65, 44, 66, 68, 109, 35, 125, 27, 80, 79, 149, 64, 179, 98, 189, 27, 117, 228, 81, 83, 30, 133, 62, 36, 117, 61])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([231, 55, 93, 229, 3, 103, 102, 196, 12, 184, 95, 67, 181, 63, 206, 79, 250, 64, 42, 182, 190, 53, 113, 0, 126, 245, 213, 84, 83, 253, 127, 10]),
|
||||
"1": new Uint8Array([164, 106, 98, 152, 109, 156, 57, 9, 244, 16, 20, 221, 114, 207, 227, 74, 38, 18, 71, 133, 77, 115, 18, 207, 79, 190, 173, 96, 185, 182, 158, 221]),
|
||||
"100000": new Uint8Array([122, 64, 61, 154, 19, 174, 216, 22, 78, 156, 7, 44, 84, 84, 98, 37, 31, 217, 66, 241, 115, 106, 107, 240, 60, 225, 200, 131, 48, 4, 142, 4])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([126, 102, 200, 75, 234, 136, 143, 146, 195, 72, 217, 20, 85, 133, 24, 108, 174, 71, 43, 18, 251, 167, 240, 173, 40, 23, 149, 117, 193, 170, 129, 90]),
|
||||
"1": new Uint8Array([79, 81, 12, 81, 129, 172, 92, 44, 95, 212, 189, 20, 31, 151, 18, 73, 91, 236, 162, 121, 98, 71, 66, 180, 214, 211, 13, 8, 185, 108, 10, 105]),
|
||||
"100000": new Uint8Array([95, 26, 106, 196, 165, 109, 151, 150, 167, 48, 154, 120, 218, 170, 249, 24, 186, 218, 245, 237, 30, 236, 195, 240, 184, 163, 164, 76, 61, 56, 214, 84])
|
||||
}
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"short": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([127, 247, 149, 74, 237, 223, 65, 121, 95, 200, 48, 6, 102, 120, 109, 73, 116, 38, 154, 169, 28, 199, 233, 56, 17, 201, 83, 51, 29, 86, 214, 9]),
|
||||
"1": new Uint8Array([233, 240, 218, 30, 151, 223, 164, 85, 248, 88, 206, 107, 154, 241, 236, 192, 41, 159, 18, 95, 241, 168, 71, 235, 93, 73, 85, 134, 111, 67, 230, 4]),
|
||||
"100000": new Uint8Array([28, 115, 19, 43, 106, 85, 233, 217, 222, 44, 219, 254, 31, 85, 191, 10, 181, 159, 217, 31, 120, 241, 9, 197, 0, 150, 3, 139, 133, 87, 177, 71])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([213, 97, 196, 200, 78, 156, 96, 186, 71, 82, 162, 211, 131, 191, 85, 239, 246, 67, 252, 158, 69, 34, 82, 214, 130, 30, 57, 68, 147, 80, 207, 114]),
|
||||
"1": new Uint8Array([231, 226, 180, 31, 72, 135, 66, 27, 203, 118, 78, 180, 165, 111, 99, 210, 80, 46, 51, 199, 100, 251, 223, 96, 98, 106, 212, 46, 217, 103, 35, 66]),
|
||||
"100000": new Uint8Array([239, 208, 7, 82, 188, 159, 250, 251, 90, 57, 157, 209, 213, 131, 78, 141, 44, 43, 103, 110, 205, 75, 32, 99, 251, 31, 229, 129, 208, 241, 56, 11])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([114, 201, 43, 189, 61, 218, 180, 120, 158, 136, 228, 42, 209, 205, 168, 60, 192, 114, 158, 108, 181, 16, 106, 87, 126, 80, 213, 207, 97, 120, 36, 129]),
|
||||
"1": new Uint8Array([166, 103, 218, 71, 184, 248, 87, 183, 198, 95, 112, 166, 200, 231, 160, 108, 224, 210, 82, 17, 162, 182, 235, 175, 88, 220, 170, 242, 104, 180, 107, 29]),
|
||||
"100000": new Uint8Array([6, 225, 158, 27, 131, 230, 72, 11, 21, 84, 223, 43, 49, 162, 201, 45, 27, 252, 249, 188, 27, 219, 200, 117, 31, 248, 104, 91, 222, 239, 125, 201])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([40, 53, 243, 237, 83, 86, 84, 32, 201, 9, 81, 80, 155, 12, 17, 115, 182, 69, 23, 79, 21, 70, 171, 58, 195, 230, 200, 92, 180, 113, 181, 59]),
|
||||
"1": new Uint8Array([45, 219, 73, 36, 62, 179, 181, 145, 44, 178, 96, 205, 216, 127, 176, 78, 240, 209, 17, 191, 164, 77, 64, 164, 94, 2, 168, 165, 195, 193, 81, 141]),
|
||||
"100000": new Uint8Array([128, 174, 217, 5, 202, 50, 174, 11, 178, 169, 216, 245, 50, 240, 72, 160, 230, 114, 70, 62, 239, 159, 131, 223, 167, 216, 139, 202, 114, 101, 83, 234])
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([139, 184, 156, 247, 25, 114, 254, 90, 204, 22, 253, 197, 248, 207, 253, 44, 46, 113, 120, 192, 134, 179, 187, 230, 28, 193, 49, 70, 25, 19, 89, 88]),
|
||||
"1": new Uint8Array([123, 11, 204, 168, 29, 214, 55, 163, 179, 57, 134, 102, 97, 151, 22, 197, 242, 177, 244, 165, 194, 78, 133, 193, 138, 153, 85, 85, 158, 77, 118, 146]),
|
||||
"100000": new Uint8Array([38, 198, 168, 174, 75, 209, 251, 231, 21, 174, 71, 142, 255, 243, 236, 174, 131, 175, 166, 23, 237, 53, 189, 74, 63, 99, 195, 218, 118, 164, 45, 34])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([92, 172, 193, 108, 223, 190, 5, 44, 253, 115, 169, 137, 27, 140, 14, 120, 177, 155, 46, 7, 234, 226, 66, 61, 72, 254, 213, 224, 138, 168, 73, 75]),
|
||||
"1": new Uint8Array([187, 115, 248, 22, 138, 143, 57, 29, 61, 84, 202, 137, 47, 183, 43, 142, 96, 53, 227, 127, 137, 30, 90, 112, 73, 27, 148, 220, 5, 81, 11, 196]),
|
||||
"100000": new Uint8Array([135, 253, 252, 41, 51, 146, 203, 243, 62, 204, 155, 81, 65, 162, 254, 250, 116, 209, 80, 73, 151, 86, 134, 60, 72, 76, 10, 120, 182, 39, 77, 127])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([204, 87, 72, 236, 196, 18, 136, 160, 225, 51, 104, 84, 58, 170, 46, 246, 44, 151, 186, 117, 24, 250, 136, 246, 225, 28, 53, 118, 63, 201, 48, 180]),
|
||||
"1": new Uint8Array([31, 70, 180, 12, 242, 251, 61, 196, 26, 61, 156, 237, 136, 151, 184, 97, 5, 3, 104, 16, 226, 191, 172, 112, 64, 129, 75, 214, 93, 66, 141, 103]),
|
||||
"100000": new Uint8Array([51, 226, 153, 59, 244, 114, 157, 201, 147, 255, 246, 110, 105, 204, 85, 119, 113, 53, 235, 250, 188, 229, 51, 87, 91, 206, 74, 150, 100, 90, 116, 44])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([19, 83, 247, 69, 130, 55, 171, 51, 46, 224, 82, 226, 159, 130, 154, 42, 185, 14, 114, 99, 14, 161, 4, 147, 180, 238, 207, 251, 159, 248, 158, 29]),
|
||||
"1": new Uint8Array([97, 201, 53, 196, 98, 195, 50, 28, 137, 102, 53, 69, 209, 58, 79, 107, 82, 181, 25, 28, 251, 116, 121, 229, 141, 207, 230, 68, 77, 67, 16, 108]),
|
||||
"100000": new Uint8Array([121, 186, 248, 14, 197, 130, 146, 5, 56, 128, 30, 157, 146, 156, 224, 112, 132, 39, 121, 135, 72, 141, 115, 58, 2, 104, 82, 196, 82, 240, 111, 180])
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"SHA-384": {
|
||||
"1000": new Uint8Array([156, 191, 231, 45, 25, 77, 163, 78, 23, 200, 33, 221, 21, 105, 239, 80, 168, 110, 180, 216, 147, 89, 23, 118, 173, 198, 165, 194, 30, 0, 49, 207]),
|
||||
"1": new Uint8Array([75, 176, 66, 165, 194, 140, 238, 111, 102, 249, 145, 199, 23, 253, 119, 2, 103, 120, 126, 43, 179, 3, 30, 174, 39, 13, 135, 214, 58, 217, 149, 52]),
|
||||
"100000": new Uint8Array([237, 107, 215, 40, 37, 103, 171, 228, 141, 84, 45, 6, 125, 9, 244, 4, 189, 4, 74, 226, 206, 254, 17, 218, 204, 83, 28, 71, 100, 205, 53, 205])
|
||||
},
|
||||
"SHA-512": {
|
||||
"1000": new Uint8Array([203, 147, 9, 108, 58, 2, 190, 235, 28, 95, 172, 54, 118, 92, 144, 17, 254, 153, 248, 216, 234, 98, 54, 96, 72, 252, 152, 203, 152, 223, 234, 143]),
|
||||
"1": new Uint8Array([109, 46, 203, 187, 251, 46, 109, 205, 112, 86, 250, 249, 175, 106, 160, 110, 174, 89, 67, 145, 219, 152, 50, 121, 166, 191, 39, 224, 235, 34, 134, 20]),
|
||||
"100000": new Uint8Array([137, 225, 98, 84, 235, 173, 92, 186, 114, 224, 174, 190, 22, 20, 199, 249, 183, 149, 167, 80, 95, 38, 55, 32, 108, 225, 10, 52, 73, 162, 184, 187])
|
||||
},
|
||||
"SHA-1": {
|
||||
"1000": new Uint8Array([110, 64, 145, 10, 192, 46, 200, 156, 235, 185, 216, 152, 177, 58, 9, 209, 205, 122, 223, 111, 140, 192, 140, 196, 115, 48, 44, 137, 115, 170, 46, 25]),
|
||||
"1": new Uint8Array([30, 67, 122, 28, 121, 215, 91, 230, 30, 145, 20, 29, 174, 32, 175, 252, 72, 146, 204, 153, 171, 204, 63, 231, 83, 136, 123, 204, 200, 146, 1, 118]),
|
||||
"100000": new Uint8Array([169, 225, 190, 187, 54, 188, 38, 215, 201, 151, 213, 72, 60, 188, 141, 228, 164, 25, 209, 231, 6, 87, 19, 66, 99, 37, 134, 236, 51, 10, 114, 144])
|
||||
},
|
||||
"SHA-256": {
|
||||
"1000": new Uint8Array([79, 197, 138, 33, 193, 0, 206, 24, 53, 184, 249, 153, 29, 115, 139, 86, 150, 93, 20, 178, 78, 23, 97, 251, 223, 252, 105, 172, 94, 11, 102, 122]),
|
||||
"1": new Uint8Array([247, 206, 11, 101, 61, 45, 114, 164, 16, 140, 245, 171, 233, 18, 255, 221, 119, 118, 22, 219, 187, 39, 167, 14, 130, 4, 243, 174, 45, 15, 111, 173]),
|
||||
"100000": new Uint8Array([100, 168, 104, 212, 178, 58, 246, 150, 211, 115, 77, 11, 129, 77, 4, 205, 209, 172, 40, 1, 40, 233, 118, 83, 160, 95, 50, 180, 156, 19, 162, 154])
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {passwords: passwords, salts: salts, derivations: derivations, derivedKeyTypes: derivedKeyTypes};
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: deriveBits() Using ECDH</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveBits">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="ecdh_bits.js"></script>
|
||||
|
||||
<h1>deriveBits Tests for ECDH</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI:deriveKey() Using ECDH</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="ecdh_keys.js"></script>
|
||||
|
||||
<h1>deriveKey Tests for ECDH</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: deriveBits() and deriveKey() Using HKDF</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveBits">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="hkdf_vectors.js"></script>
|
||||
<script src="hkdf.js"></script>
|
||||
|
||||
<h1>deriveBits and deriveKey Tests for HKDF</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveBits">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-deriveKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="pbkdf2_vectors.js"></script>
|
||||
<script src="pbkdf2.js"></script>
|
||||
|
||||
<h1>deriveBits and deriveKey Tests for PBKDF2</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,279 @@
|
|||
// Test importKey and exportKey for EC algorithms. Only "happy paths" are
|
||||
// currently tested - those where the operation should succeed.
|
||||
|
||||
function run_test() {
|
||||
var subtle = crypto.subtle;
|
||||
|
||||
var curves = ['P-256', 'P-384', 'P-521'];
|
||||
|
||||
var keyData = {
|
||||
"P-521": {
|
||||
spki: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]),
|
||||
pkcs8: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]),
|
||||
jwk: {
|
||||
kty: "EC",
|
||||
crv: "P-521",
|
||||
x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_",
|
||||
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
|
||||
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
|
||||
}
|
||||
},
|
||||
|
||||
"P-256": {
|
||||
spki: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]),
|
||||
pkcs8: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]),
|
||||
jwk: {
|
||||
kty: "EC",
|
||||
crv: "P-256",
|
||||
x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE",
|
||||
y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg",
|
||||
d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo"
|
||||
}
|
||||
},
|
||||
|
||||
"P-384": {
|
||||
spki: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]),
|
||||
pkcs8: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]),
|
||||
jwk: {
|
||||
kty: "EC",
|
||||
crv: "P-384",
|
||||
x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1",
|
||||
y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo",
|
||||
d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz"
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// combinations to test
|
||||
var testVectors = [
|
||||
{name: "ECDSA", privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{name: "ECDH", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}
|
||||
];
|
||||
|
||||
// TESTS ARE HERE:
|
||||
// Test every test vector, along with all available key data
|
||||
testVectors.forEach(function(vector) {
|
||||
curves.forEach(function(curve) {
|
||||
|
||||
[true, false].forEach(function(extractable) {
|
||||
|
||||
// Test public keys first
|
||||
[[]].forEach(function(usages) { // Only valid usages argument is empty array
|
||||
['spki', 'jwk'].forEach(function(format) {
|
||||
var algorithm = {name: vector.name, namedCurve: curve};
|
||||
var data = keyData[curve];
|
||||
if (format === "jwk") { // Not all fields used for public keys
|
||||
data = {jwk: {kty: keyData[curve].jwk.kty, crv: keyData[curve].jwk.crv, x: keyData[curve].jwk.x, y: keyData[curve].jwk.y}};
|
||||
}
|
||||
|
||||
testFormat(format, algorithm, data, curve, usages, extractable);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Next, test private keys
|
||||
allValidUsages(vector.privateUsages, []).forEach(function(usages) {
|
||||
['pkcs8', 'jwk'].forEach(function(format) {
|
||||
var algorithm = {name: vector.name, namedCurve: curve};
|
||||
var data = keyData[curve];
|
||||
|
||||
testFormat(format, algorithm, data, curve, usages, extractable);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Test importKey with a given key format and other parameters. If
|
||||
// extrable is true, export the key and verify that it matches the input.
|
||||
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
|
||||
promise_test(function(test) {
|
||||
return subtle.importKey(format, keyData[format], algorithm, extractable, usages).
|
||||
then(function(key) {
|
||||
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
|
||||
if (!extractable) {
|
||||
return;
|
||||
}
|
||||
|
||||
return subtle.exportKey(format, key).
|
||||
then(function(result) {
|
||||
if (format !== "jwk") {
|
||||
assert_true(equalBuffers(keyData[format], result), "Round trip works");
|
||||
} else {
|
||||
assert_true(equalJwk(keyData[format], result), "Round trip works");
|
||||
}
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Helper methods follow:
|
||||
|
||||
// Are two array buffers the same?
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are two Jwk objects "the same"? That is, does the object returned include
|
||||
// matching values for each property that was expected? It's okay if the
|
||||
// returned object has extra methods; they aren't checked.
|
||||
function equalJwk(expected, got) {
|
||||
var fields = Object.keys(expected);
|
||||
var fieldName;
|
||||
|
||||
for(var i=0; i<fields.length; i++) {
|
||||
fieldName = fields[i];
|
||||
if (!(fieldName in got)) {
|
||||
return false;
|
||||
}
|
||||
if (expected[fieldName] !== got[fieldName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build minimal Jwk objects from raw key data and algorithm specifications
|
||||
function jwkData(keyData, algorithm) {
|
||||
var result = {
|
||||
kty: "oct",
|
||||
k: byteArrayToUnpaddedBase64(keyData)
|
||||
};
|
||||
|
||||
if (algorithm.name.substring(0, 3) === "AES") {
|
||||
result.alg = "A" + (8 * keyData.byteLength).toString() + algorithm.name.substring(4);
|
||||
} else if (algorithm.name === "HMAC") {
|
||||
result.alg = "HS" + algorithm.hash.substring(4);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Jwk format wants Base 64 without the typical padding at the end.
|
||||
function byteArrayToUnpaddedBase64(byteArray){
|
||||
var binaryString = "";
|
||||
for (var i=0; i<byteArray.byteLength; i++){
|
||||
binaryString += String.fromCharCode(byteArray[i]);
|
||||
}
|
||||
var base64String = btoa(binaryString);
|
||||
|
||||
return base64String.replace(/=/g, "");
|
||||
}
|
||||
|
||||
// Want to test every valid combination of usages. Start by creating a list
|
||||
// of all non-empty subsets to possible usages.
|
||||
function allNonemptySubsetsOf(arr) {
|
||||
var results = [];
|
||||
var firstElement;
|
||||
var remainingElements;
|
||||
|
||||
for(var i=0; i<arr.length; i++) {
|
||||
firstElement = arr[i];
|
||||
remainingElements = arr.slice(i+1);
|
||||
results.push([firstElement]);
|
||||
|
||||
if (remainingElements.length > 0) {
|
||||
allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
|
||||
combination.push(firstElement);
|
||||
results.push(combination);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Return a list of all valid usage combinations, given the possible ones
|
||||
// and the ones that are required for a particular operation.
|
||||
function allValidUsages(possibleUsages, requiredUsages) {
|
||||
var allUsages = [];
|
||||
|
||||
allNonemptySubsetsOf(possibleUsages).forEach(function(usage) {
|
||||
for (var i=0; i<requiredUsages.length; i++) {
|
||||
if (!usage.includes(requiredUsages[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
allUsages.push(usage);
|
||||
});
|
||||
|
||||
return allUsages;
|
||||
}
|
||||
|
||||
// Convert method parameters to a string to uniquely name each test
|
||||
function parameterString(format, data, algorithm, extractable, usages) {
|
||||
if ("byteLength" in data) {
|
||||
data = "buffer(" + data.byteLength.toString() + ")";
|
||||
} else {
|
||||
data = "object(" + Object.keys(data).join(", ") + ")";
|
||||
}
|
||||
var result = "(" +
|
||||
objectToString(format) + ", " +
|
||||
objectToString(data) + ", " +
|
||||
objectToString(algorithm) + ", " +
|
||||
objectToString(extractable) + ", " +
|
||||
objectToString(usages) +
|
||||
")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Character representation of any object we may use as a parameter.
|
||||
function objectToString(obj) {
|
||||
var keyValuePairs = [];
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else if (typeof obj === "object") {
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
|
||||
});
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
} else if (typeof obj === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
var keyValuePairs = [];
|
||||
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
var value = obj[keyName];
|
||||
if (typeof value === "object") {
|
||||
value = objectToString(value);
|
||||
} else if (typeof value === "array") {
|
||||
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
keyValuePairs.push(keyName + ": " + value);
|
||||
});
|
||||
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
}
|
||||
|
||||
return; // from run_test
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("ec_importKey.js");
|
||||
run_test();
|
||||
done();
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("rsa_importKey.js");
|
||||
run_test();
|
||||
done();
|
|
@ -0,0 +1,242 @@
|
|||
// Test importKey and exportKey for non-PKC algorithms. Only "happy paths" are
|
||||
// currently tested - those where the operation should succeed.
|
||||
|
||||
function run_test() {
|
||||
var subtle = crypto.subtle;
|
||||
|
||||
// keying material for algorithms that can use any bit string.
|
||||
var rawKeyData = [
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24]),
|
||||
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32])
|
||||
];
|
||||
|
||||
// combinations of algorithms, usages, parameters, and formats to test
|
||||
var testVectors = [
|
||||
{name: "AES-CTR", legalUsages: ["encrypt", "decrypt"], extractable: [true, false], formats: ["raw", "jwk"]},
|
||||
{name: "AES-CBC", legalUsages: ["encrypt", "decrypt"], extractable: [true, false], formats: ["raw", "jwk"]},
|
||||
{name: "AES-GCM", legalUsages: ["encrypt", "decrypt"], extractable: [true, false], formats: ["raw", "jwk"]},
|
||||
{name: "AES-KW", legalUsages: ["wrapKey", "unwrapKey"], extractable: [true, false], formats: ["raw", "jwk"]},
|
||||
{name: "HMAC", hash: "SHA-1", legalUsages: ["sign", "verify"], extractable: [false], formats: ["raw", "jwk"]},
|
||||
{name: "HMAC", hash: "SHA-256", legalUsages: ["sign", "verify"], extractable: [false], formats: ["raw", "jwk"]},
|
||||
{name: "HMAC", hash: "SHA-384", legalUsages: ["sign", "verify"], extractable: [false], formats: ["raw", "jwk"]},
|
||||
{name: "HMAC", hash: "SHA-512", legalUsages: ["sign", "verify"], extractable: [false], formats: ["raw", "jwk"]},
|
||||
{name: "HKDF", legalUsages: ["deriveBits", "deriveKey"], extractable: [false], formats: ["raw"]},
|
||||
{name: "PBKDF2", legalUsages: ["deriveBits", "deriveKey"], extractable: [false], formats: ["raw"]}
|
||||
];
|
||||
|
||||
|
||||
|
||||
// TESTS ARE HERE:
|
||||
// Test every test vector, along with all available key data
|
||||
testVectors.forEach(function(vector) {
|
||||
var algorithm = {name: vector.name};
|
||||
if ("hash" in vector) {
|
||||
algorithm.hash = vector.hash;
|
||||
}
|
||||
|
||||
rawKeyData.forEach(function(keyData) {
|
||||
// Generate all combinations of valid usages for testing
|
||||
allValidUsages(vector.legalUsages, []).forEach(function(usages) {
|
||||
// Try each legal value of the extractable parameter
|
||||
vector.extractable.forEach(function(extractable) {
|
||||
vector.formats.forEach(function(format) {
|
||||
var data = keyData;
|
||||
if (format === "jwk") {
|
||||
data = jwkData(keyData, algorithm);
|
||||
}
|
||||
testFormat(format, algorithm, data, keyData.length * 8, usages, extractable);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Test importKey with a given key format and other parameters. If
|
||||
// extrable is true, export the key and verify that it matches the input.
|
||||
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
|
||||
promise_test(function(test) {
|
||||
return subtle.importKey(format, keyData, algorithm, extractable, usages).
|
||||
then(function(key) {
|
||||
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
|
||||
if (!extractable) {
|
||||
return;
|
||||
}
|
||||
|
||||
return subtle.exportKey(format, key).
|
||||
then(function(result) {
|
||||
if (format !== "jwk") {
|
||||
assert_true(equalBuffers(keyData, result), "Round trip works");
|
||||
} else {
|
||||
assert_true(equalJwk(keyData, result), "Round trip works");
|
||||
}
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Helper methods follow:
|
||||
|
||||
// Are two array buffers the same?
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are two Jwk objects "the same"? That is, does the object returned include
|
||||
// matching values for each property that was expected? It's okay if the
|
||||
// returned object has extra methods; they aren't checked.
|
||||
function equalJwk(expected, got) {
|
||||
var fields = Object.keys(expected);
|
||||
var fieldName;
|
||||
|
||||
for(var i=0; i<fields.length; i++) {
|
||||
fieldName = fields[i];
|
||||
if (!(fieldName in got)) {
|
||||
return false;
|
||||
}
|
||||
if (expected[fieldName] !== got[fieldName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build minimal Jwk objects from raw key data and algorithm specifications
|
||||
function jwkData(keyData, algorithm) {
|
||||
var result = {
|
||||
kty: "oct",
|
||||
k: byteArrayToUnpaddedBase64(keyData)
|
||||
};
|
||||
|
||||
if (algorithm.name.substring(0, 3) === "AES") {
|
||||
result.alg = "A" + (8 * keyData.byteLength).toString() + algorithm.name.substring(4);
|
||||
} else if (algorithm.name === "HMAC") {
|
||||
result.alg = "HS" + algorithm.hash.substring(4);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Jwk format wants Base 64 without the typical padding at the end.
|
||||
function byteArrayToUnpaddedBase64(byteArray){
|
||||
var binaryString = "";
|
||||
for (var i=0; i<byteArray.byteLength; i++){
|
||||
binaryString += String.fromCharCode(byteArray[i]);
|
||||
}
|
||||
var base64String = btoa(binaryString);
|
||||
|
||||
return base64String.replace(/=/g, "");
|
||||
}
|
||||
|
||||
// Want to test every valid combination of usages. Start by creating a list
|
||||
// of all non-empty subsets to possible usages.
|
||||
function allNonemptySubsetsOf(arr) {
|
||||
var results = [];
|
||||
var firstElement;
|
||||
var remainingElements;
|
||||
|
||||
for(var i=0; i<arr.length; i++) {
|
||||
firstElement = arr[i];
|
||||
remainingElements = arr.slice(i+1);
|
||||
results.push([firstElement]);
|
||||
|
||||
if (remainingElements.length > 0) {
|
||||
allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
|
||||
combination.push(firstElement);
|
||||
results.push(combination);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Return a list of all valid usage combinations, given the possible ones
|
||||
// and the ones that are required for a particular operation.
|
||||
function allValidUsages(possibleUsages, requiredUsages) {
|
||||
var allUsages = [];
|
||||
|
||||
allNonemptySubsetsOf(possibleUsages).forEach(function(usage) {
|
||||
for (var i=0; i<requiredUsages.length; i++) {
|
||||
if (!usage.includes(requiredUsages[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
allUsages.push(usage);
|
||||
});
|
||||
|
||||
return allUsages;
|
||||
}
|
||||
|
||||
// Convert method parameters to a string to uniquely name each test
|
||||
function parameterString(format, data, algorithm, extractable, usages) {
|
||||
var result = "(" +
|
||||
objectToString(format) + ", " +
|
||||
objectToString(data) + ", " +
|
||||
objectToString(algorithm) + ", " +
|
||||
objectToString(extractable) + ", " +
|
||||
objectToString(usages) +
|
||||
")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Character representation of any object we may use as a parameter.
|
||||
function objectToString(obj) {
|
||||
var keyValuePairs = [];
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else if (typeof obj === "object") {
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
|
||||
});
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
} else if (typeof obj === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
var keyValuePairs = [];
|
||||
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
var value = obj[keyName];
|
||||
if (typeof value === "object") {
|
||||
value = objectToString(value);
|
||||
} else if (typeof value === "array") {
|
||||
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
keyValuePairs.push(keyName + ": " + value);
|
||||
});
|
||||
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
}
|
||||
|
||||
return; // from run_test
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("symmetric_importKey.js");
|
||||
run_test();
|
||||
done();
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<meta charset=utf-8>
|
||||
<title>WebCryptoAPI: importKey() for EC keys</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href=https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-importKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="ec_importKey.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<meta charset=utf-8>
|
||||
<title>WebCryptoAPI: importKey() for RSA keys</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href=https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-importKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="rsa_importKey.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<meta charset=utf-8>
|
||||
<title>WebCryptoAPI: importKey() for symmetric keys</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href=https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-importKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="symmetric_importKey.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
479
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/ecdsa.js
Normal file
479
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/ecdsa.js
Normal file
|
@ -0,0 +1,479 @@
|
|||
|
||||
function run_test() {
|
||||
var subtle = self.crypto.subtle; // Change to test prefixed implementations
|
||||
|
||||
// When are all these tests really done? When all the promises they use have resolved.
|
||||
var all_promises = [];
|
||||
|
||||
// Source file [algorithm_name]_vectors.js provides the getTestVectors method
|
||||
// for the algorithm that drives these tests.
|
||||
var testVectors = getTestVectors();
|
||||
|
||||
// Test verification first, because signing tests rely on that working
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with an altered buffer after call
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
var signature = copyBuffer(vector.signature);
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
signature[0] = 255 - signature[0];
|
||||
return operation;
|
||||
}, vector.name + " verification with altered signature after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification with altered signature after call");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful verification even if plaintext is altered after call.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
return operation;
|
||||
}, vector.name + " with altered plaintext after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " with altered plaintext after call");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to using privateKey to verify.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.plaintext)
|
||||
.then(function(plaintext) {
|
||||
assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " using privateKey to verify");
|
||||
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " using privateKey to verify");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to using publicKey to sign.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
return subtle.sign(algorithm, vector.publicKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " using publicKey to sign");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " using publicKey to sign");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to no "verify" usage.
|
||||
testVectors.forEach(function(originalVector) {
|
||||
var vector = Object.assign({}, originalVector);
|
||||
|
||||
var promise = importVectorKeys(vector, [], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(plaintext) {
|
||||
assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " no verify usage");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " no verify usage");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful signing and verification.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
return subtle.sign(algorithm, vector.privateKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
// Can we verify the signature?
|
||||
return subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Round trip verification works");
|
||||
return signature;
|
||||
}, function(err) {
|
||||
assert_unreached("verify error for test " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " round trip");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested signing or verifying
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " round trip");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test signing with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"])
|
||||
.then(function(wrongKey) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
return importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.sign(algorithm, wrongKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Signing should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " signing with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name");
|
||||
});
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
|
||||
}, "generate wrong key step: " + vector.name + " signing with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"])
|
||||
.then(function(wrongKey) {
|
||||
return importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Verifying should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verifying with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name");
|
||||
});
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
|
||||
}, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification fails with wrong signature
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
var signature = copyBuffer(vector.signature);
|
||||
signature[0] = 255 - signature[0];
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to altered signature");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to altered signature");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification fails with wrong hash
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var hashName = "SHA-1";
|
||||
if (vector.hashName === "SHA-1") {
|
||||
hashName = "SHA-256"
|
||||
}
|
||||
var algorithm = {name: vector.algorithmName, hash: hashName};
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to wrong hash");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to wrong hash");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification fails with bad hash name
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
// use the wrong name for the hash
|
||||
var hashName = vector.hashName.substring(0, 3) + vector.hashName.substring(4);
|
||||
var algorithm = {name: vector.algorithmName, hash: hashName};
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_unreached("Verification should throw an error");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "NotSupportedError", "Correctly throws NotSupportedError for illegal hash name")
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to bad hash name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to bad hash name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification fails with short (odd length) signature
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
var signature = vector.signature.slice(1); // Skip the first byte
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to shortened signature");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to shortened signature");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification fails with wrong plaintext
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
var algorithm = {name: vector.algorithmName, hash: vector.hashName};
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to altered plaintext");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to altered plaintext");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
|
||||
Promise.all(all_promises)
|
||||
.then(function() {done();})
|
||||
.catch(function() {done();})
|
||||
return;
|
||||
|
||||
// A test vector has all needed fields for signing and verifying, EXCEPT that the
|
||||
// key field may be null. This function replaces that null with the Correct
|
||||
// CryptoKey object.
|
||||
//
|
||||
// Returns a Promise that yields an updated vector on success.
|
||||
function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) {
|
||||
var publicPromise, privatePromise;
|
||||
|
||||
if (vector.publicKey !== null) {
|
||||
publicPromise = new Promise(function(resolve, reject) {
|
||||
resolve(vector);
|
||||
});
|
||||
} else {
|
||||
publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, publicKeyUsages)
|
||||
.then(function(key) {
|
||||
vector.publicKey = key;
|
||||
return vector;
|
||||
}); // Returns a copy of the sourceBuffer it is sent.
|
||||
}
|
||||
|
||||
if (vector.privateKey !== null) {
|
||||
privatePromise = new Promise(function(resolve, reject) {
|
||||
resolve(vector);
|
||||
});
|
||||
} else {
|
||||
privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, privateKeyUsages)
|
||||
.then(function(key) {
|
||||
vector.privateKey = key;
|
||||
return vector;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.all([publicPromise, privatePromise]);
|
||||
}
|
||||
|
||||
// Returns a copy of the sourceBuffer it is sent.
|
||||
function copyBuffer(sourceBuffer) {
|
||||
var source = new Uint8Array(sourceBuffer);
|
||||
var copy = new Uint8Array(sourceBuffer.byteLength)
|
||||
|
||||
for (var i=0; i<source.byteLength; i++) {
|
||||
copy[i] = source[i];
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("ecdsa_vectors.js");
|
||||
importScripts("ecdsa.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
// ecdsa_vectors.js
|
||||
|
||||
// Data for testing ECDSA with every curve currently in the WebCryptoAPI recommendation.
|
||||
|
||||
// The following function returns an array of test vectors
|
||||
// for the subtleCrypto encrypt method.
|
||||
//
|
||||
// Each test vector has the following fields:
|
||||
// name - a unique name for this vector
|
||||
// publicKeyBuffer - an arrayBuffer with the key data
|
||||
// publicKeyFormat - "spki" "jwk"
|
||||
// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
|
||||
// privateKeyBuffer - an arrayBuffer with the key data
|
||||
// privateKeyFormat - "pkcs8" or "jwk"
|
||||
// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
|
||||
// algorithmName - the name of the AlgorithmIdentifier parameter to provide to encrypt
|
||||
// namedCurve - the curve used
|
||||
// hashName - the hash function to sign with
|
||||
// plaintext - the text to encrypt
|
||||
// signature - the expected signature
|
||||
function getTestVectors() {
|
||||
var pkcs8 = {
|
||||
"P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 230, 238, 207, 158, 98, 108, 202, 142, 24, 7, 155, 146, 197, 238, 38, 158, 84, 202, 18, 142, 175, 212, 137, 71, 255, 81, 171, 160, 10, 192, 229, 214, 161, 68, 3, 66, 0, 4, 10, 5, 30, 56, 111, 103, 196, 166, 225, 229, 203, 238, 125, 55, 116, 91, 88, 142, 190, 114, 15, 117, 89, 22, 40, 111, 150, 41, 105, 122, 57, 23, 17, 216, 106, 234, 201, 103, 8, 210, 58, 38, 35, 216, 198, 237, 187, 84, 217, 164, 63, 100, 6, 105, 49, 128, 15, 53, 29, 158, 117, 235, 238, 30]),
|
||||
"P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 2, 169, 160, 216, 153, 239, 168, 126, 117, 100, 17, 9, 7, 233, 216, 44, 33, 189, 98, 101, 163, 122, 189, 154, 111, 219, 15, 128, 236, 132, 77, 211, 161, 66, 83, 32, 214, 125, 220, 48, 245, 219, 116, 239, 185, 162, 230, 97, 161, 100, 3, 98, 0, 4, 29, 49, 157, 105, 45, 202, 95, 87, 84, 186, 123, 50, 193, 22, 66, 198, 216, 210, 180, 251, 130, 73, 195, 242, 20, 215, 30, 144, 181, 37, 41, 102, 217, 127, 123, 235, 31, 170, 177, 228, 243, 226, 96, 85, 73, 194, 238, 219, 82, 3, 41, 179, 190, 166, 181, 229, 86, 36, 161, 81, 80, 161, 105, 102, 99, 95, 25, 22, 239, 4, 221, 117, 142, 105, 64, 157, 6, 51, 203, 75, 37, 153, 65, 121, 178, 42, 118, 156, 116, 52, 54, 145, 14, 121, 153, 81]),
|
||||
"P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 83, 62, 97, 143, 152, 234, 209, 181, 19, 236, 136, 120, 200, 130, 13, 55, 122, 54, 216, 240, 63, 43, 160, 70, 201, 49, 130, 90, 61, 53, 135, 48, 192, 178, 96, 51, 219, 183, 247, 228, 163, 212, 67, 74, 3, 94, 36, 183, 7, 249, 18, 71, 102, 23, 110, 26, 240, 184, 93, 242, 46, 170, 186, 156, 37, 161, 129, 137, 3, 129, 134, 0, 4, 0, 166, 222, 236, 251, 72, 145, 23, 241, 228, 28, 196, 160, 100, 7, 61, 134, 115, 8, 110, 81, 219, 37, 8, 110, 141, 183, 100, 212, 239, 246, 10, 173, 99, 88, 253, 207, 150, 122, 198, 132, 89, 39, 94, 42, 128, 79, 142, 238, 183, 228, 196, 40, 75, 20, 81, 192, 165, 234, 118, 254, 112, 7, 172, 5, 71, 1, 197, 237, 218, 249, 168, 158, 124, 79, 220, 201, 36, 199, 55, 216, 245, 133, 218, 151, 3, 169, 84, 194, 59, 231, 193, 74, 175, 166, 102, 84, 178, 86, 119, 10, 147, 142, 127, 38, 231, 0, 198, 3, 147, 28, 123, 208, 189, 181, 208, 99, 44, 125, 30, 171, 70, 111, 9, 217, 118, 194, 74, 50, 62, 27, 124])
|
||||
};
|
||||
|
||||
var spki = {
|
||||
"P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 10, 5, 30, 56, 111, 103, 196, 166, 225, 229, 203, 238, 125, 55, 116, 91, 88, 142, 190, 114, 15, 117, 89, 22, 40, 111, 150, 41, 105, 122, 57, 23, 17, 216, 106, 234, 201, 103, 8, 210, 58, 38, 35, 216, 198, 237, 187, 84, 217, 164, 63, 100, 6, 105, 49, 128, 15, 53, 29, 158, 117, 235, 238, 30]),
|
||||
"P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 29, 49, 157, 105, 45, 202, 95, 87, 84, 186, 123, 50, 193, 22, 66, 198, 216, 210, 180, 251, 130, 73, 195, 242, 20, 215, 30, 144, 181, 37, 41, 102, 217, 127, 123, 235, 31, 170, 177, 228, 243, 226, 96, 85, 73, 194, 238, 219, 82, 3, 41, 179, 190, 166, 181, 229, 86, 36, 161, 81, 80, 161, 105, 102, 99, 95, 25, 22, 239, 4, 221, 117, 142, 105, 64, 157, 6, 51, 203, 75, 37, 153, 65, 121, 178, 42, 118, 156, 116, 52, 54, 145, 14, 121, 153, 81]),
|
||||
"P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 166, 222, 236, 251, 72, 145, 23, 241, 228, 28, 196, 160, 100, 7, 61, 134, 115, 8, 110, 81, 219, 37, 8, 110, 141, 183, 100, 212, 239, 246, 10, 173, 99, 88, 253, 207, 150, 122, 198, 132, 89, 39, 94, 42, 128, 79, 142, 238, 183, 228, 196, 40, 75, 20, 81, 192, 165, 234, 118, 254, 112, 7, 172, 5, 71, 1, 197, 237, 218, 249, 168, 158, 124, 79, 220, 201, 36, 199, 55, 216, 245, 133, 218, 151, 3, 169, 84, 194, 59, 231, 193, 74, 175, 166, 102, 84, 178, 86, 119, 10, 147, 142, 127, 38, 231, 0, 198, 3, 147, 28, 123, 208, 189, 181, 208, 99, 44, 125, 30, 171, 70, 111, 9, 217, 118, 194, 74, 50, 62, 27, 124])
|
||||
};
|
||||
|
||||
// plaintext
|
||||
var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
|
||||
|
||||
// For verification tests.
|
||||
var signatures = {
|
||||
"P-256": {
|
||||
"SHA-1": new Uint8Array([172, 224, 125, 170, 52, 83, 158, 179, 85, 149, 130, 217, 59, 201, 0, 251, 237, 196, 51, 243, 218, 231, 211, 136, 157, 249, 219, 16, 140, 178, 145, 16, 177, 104, 68, 179, 88, 49, 219, 184, 212, 202, 109, 248, 110, 64, 202, 129, 7, 173, 226, 88, 194, 69, 164, 158, 120, 120, 128, 3, 115, 14, 181, 197]),
|
||||
"SHA-256": new Uint8Array([83, 223, 63, 226, 42, 29, 106, 105, 225, 145, 197, 180, 118, 154, 109, 110, 66, 67, 47, 251, 53, 190, 203, 65, 207, 36, 19, 57, 49, 122, 124, 118, 59, 74, 222, 134, 42, 235, 180, 229, 134, 24, 205, 81, 171, 156, 100, 218, 127, 242, 126, 53, 27, 77, 249, 101, 157, 132, 244, 30, 67, 30, 64, 12]),
|
||||
"SHA-384": new Uint8Array([235, 111, 173, 249, 151, 252, 218, 129, 123, 117, 136, 26, 162, 115, 247, 110, 169, 145, 95, 189, 228, 98, 32, 82, 34, 94, 154, 197, 47, 83, 124, 137, 215, 71, 222, 247, 135, 22, 221, 238, 77, 247, 223, 194, 42, 158, 175, 224, 76, 182, 56, 138, 97, 196, 238, 109, 42, 102, 13, 71, 1, 43, 56, 92]),
|
||||
"SHA-512": new Uint8Array([74, 201, 175, 173, 69, 107, 160, 142, 203, 41, 225, 5, 73, 146, 6, 40, 93, 130, 129, 35, 156, 171, 190, 161, 12, 10, 234, 123, 7, 5, 112, 97, 57, 183, 15, 52, 94, 215, 79, 255, 175, 222, 66, 234, 253, 180, 62, 161, 7, 11, 249, 37, 118, 185, 13, 102, 67, 84, 101, 189, 73, 132, 110, 206])
|
||||
},
|
||||
"P-384": {
|
||||
"SHA-1": new Uint8Array([101, 254, 7, 14, 195, 234, 195, 82, 80, 208, 11, 158, 230, 219, 77, 45, 173, 213, 243, 187, 185, 196, 149, 200, 103, 29, 42, 13, 43, 153, 20, 159, 178, 79, 136, 175, 7, 78, 11, 144, 50, 104, 179, 208, 237, 95, 14, 20, 104, 87, 150, 178, 143, 227, 75, 45, 142, 220, 223, 16, 132, 91, 36, 207, 121, 179, 54, 39, 216, 189, 44, 129, 98, 28, 181, 30, 3, 12, 33, 164, 58, 187, 10, 135, 64, 250, 194, 111, 133, 34, 230, 131, 195, 103, 172, 150]),
|
||||
"SHA-256": new Uint8Array([75, 194, 223, 234, 59, 205, 164, 251, 180, 253, 146, 123, 3, 15, 155, 128, 177, 245, 210, 173, 155, 183, 170, 6, 41, 56, 105, 87, 113, 32, 178, 177, 208, 239, 17, 204, 217, 254, 208, 113, 74, 171, 54, 190, 246, 57, 40, 247, 132, 245, 60, 126, 9, 223, 147, 233, 179, 229, 176, 200, 131, 207, 114, 9, 81, 180, 254, 35, 130, 199, 132, 46, 220, 252, 212, 93, 149, 106, 114, 210, 154, 64, 48, 160, 56, 169, 0, 230, 247, 221, 133, 122, 86, 80, 211, 232]),
|
||||
"SHA-384": new Uint8Array([13, 217, 194, 199, 240, 182, 244, 217, 50, 130, 84, 169, 2, 232, 115, 116, 179, 192, 146, 25, 94, 107, 226, 26, 161, 166, 220, 216, 235, 166, 15, 123, 11, 56, 196, 0, 109, 250, 33, 70, 212, 233, 253, 35, 220, 51, 97, 121, 151, 64, 23, 73, 58, 31, 79, 116, 238, 207, 228, 85, 190, 61, 169, 237, 153, 100, 29, 129, 97, 13, 254, 180, 104, 182, 7, 218, 148, 29, 87, 20, 231, 181, 26, 238, 44, 69, 170, 14, 156, 77, 160, 33, 178, 55, 0, 144]),
|
||||
"SHA-512": new Uint8Array([114, 251, 219, 54, 159, 211, 76, 28, 84, 38, 77, 7, 244, 250, 205, 105, 176, 46, 66, 6, 248, 168, 187, 37, 155, 136, 42, 48, 92, 86, 253, 226, 211, 81, 7, 228, 147, 197, 60, 214, 180, 175, 11, 49, 48, 111, 77, 3, 253, 67, 207, 199, 98, 161, 3, 14, 23, 163, 215, 117, 69, 58, 18, 18, 177, 66, 159, 123, 61, 147, 6, 106, 95, 66, 161, 11, 19, 140, 209, 119, 220, 9, 97, 110, 130, 125, 89, 136, 34, 215, 141, 70, 39, 183, 84, 230])
|
||||
},
|
||||
"P-521": {
|
||||
"SHA-1": new Uint8Array([1, 120, 26, 23, 166, 14, 67, 18, 105, 96, 253, 57, 110, 18, 16, 145, 108, 33, 21, 202, 68, 40, 217, 104, 56, 156, 75, 70, 193, 85, 54, 116, 206, 147, 123, 142, 33, 112, 12, 230, 9, 50, 174, 15, 87, 92, 161, 135, 221, 89, 119, 32, 219, 131, 158, 177, 242, 12, 126, 51, 148, 120, 117, 89, 220, 213, 0, 32, 126, 87, 13, 245, 199, 228, 173, 159, 192, 165, 247, 32, 101, 233, 206, 28, 158, 61, 18, 202, 94, 109, 217, 244, 79, 225, 40, 86, 27, 117, 244, 34, 108, 79, 173, 242, 61, 131, 83, 108, 198, 105, 234, 64, 152, 227, 115, 182, 203, 145, 156, 139, 92, 252, 5, 5, 166, 125, 150, 178, 118, 164, 106, 61]),
|
||||
"SHA-256": new Uint8Array([1, 116, 219, 167, 123, 20, 215, 63, 102, 245, 113, 103, 134, 163, 229, 168, 215, 201, 49, 68, 94, 109, 50, 10, 146, 41, 217, 97, 216, 161, 179, 239, 209, 26, 94, 163, 60, 121, 73, 90, 197, 153, 187, 182, 138, 100, 26, 132, 157, 88, 216, 62, 248, 84, 204, 38, 95, 166, 201, 23, 223, 246, 238, 67, 90, 103, 1, 179, 213, 82, 125, 172, 32, 251, 10, 112, 51, 195, 254, 121, 116, 78, 172, 239, 123, 63, 252, 39, 182, 77, 200, 99, 248, 111, 66, 152, 44, 178, 34, 146, 69, 254, 157, 228, 138, 165, 158, 182, 83, 212, 73, 112, 134, 217, 17, 165, 189, 39, 14, 149, 197, 30, 126, 152, 247, 165, 134, 63, 199, 251, 6, 92]),
|
||||
"SHA-384": new Uint8Array([1, 247, 125, 177, 229, 19, 120, 225, 23, 197, 184, 190, 200, 160, 63, 150, 87, 210, 68, 197, 78, 131, 121, 8, 191, 113, 1, 37, 95, 65, 81, 82, 93, 158, 137, 207, 127, 84, 99, 27, 51, 104, 145, 157, 56, 36, 255, 159, 127, 120, 254, 129, 35, 154, 26, 159, 222, 43, 122, 131, 233, 92, 166, 160, 202, 17, 1, 185, 139, 29, 164, 237, 0, 236, 118, 147, 103, 233, 149, 139, 128, 71, 212, 127, 146, 171, 139, 255, 150, 241, 51, 11, 249, 72, 201, 34, 9, 1, 27, 140, 219, 180, 150, 212, 100, 219, 185, 22, 114, 14, 183, 2, 189, 173, 146, 140, 153, 185, 128, 183, 101, 4, 224, 173, 28, 18, 180, 168, 87, 49, 199, 12]),
|
||||
"SHA-512": new Uint8Array([0, 178, 202, 175, 103, 152, 81, 154, 157, 54, 219, 250, 254, 120, 107, 47, 186, 28, 194, 172, 185, 149, 147, 193, 119, 179, 110, 58, 28, 238, 183, 2, 39, 90, 226, 60, 252, 202, 10, 173, 120, 246, 182, 222, 230, 180, 113, 139, 149, 208, 209, 167, 21, 170, 51, 120, 71, 14, 80, 181, 22, 193, 142, 15, 51, 5, 1, 240, 7, 30, 106, 50, 134, 127, 167, 15, 105, 92, 211, 156, 78, 135, 225, 66, 185, 228, 19, 77, 56, 116, 11, 214, 254, 227, 84, 165, 117, 22, 126, 19, 82, 78, 148, 131, 38, 55, 145, 15, 225, 30, 83, 168, 95, 178, 27, 145, 173, 184, 27, 177, 119, 156, 78, 43, 139, 200, 124, 113, 125, 195, 80, 132])
|
||||
}
|
||||
}
|
||||
|
||||
// Old ASN.1 signatures below.
|
||||
// var signatures = {
|
||||
// "P-256": {
|
||||
// "SHA-1": new Uint8Array([48, 70, 2, 33, 0, 189, 178, 29, 63, 162, 177, 41, 146, 224, 212, 75, 195, 12, 201, 193, 68, 61, 21, 122, 25, 40, 54, 22, 203, 197, 247, 160, 97, 3, 157, 35, 146, 2, 33, 0, 202, 253, 208, 131, 220, 167, 213, 121, 60, 56, 76, 111, 93, 197, 64, 54, 149, 82, 23, 255, 65, 206, 208, 154, 16, 52, 250, 3, 135, 178, 223, 248]),
|
||||
// "SHA-256": new Uint8Array([48, 68, 2, 32, 91, 78, 119, 119, 168, 102, 87, 56, 106, 33, 140, 190, 53, 232, 207, 81, 251, 156, 33, 85, 156, 6, 1, 183, 61, 254, 248, 113, 89, 191, 223, 202, 2, 32, 9, 130, 207, 194, 45, 48, 4, 134, 19, 133, 121, 124, 93, 141, 29, 63, 26, 0, 167, 132, 123, 80, 240, 184, 69, 182, 18, 111, 211, 211, 139, 209]),
|
||||
// "SHA-384": new Uint8Array([48, 69, 2, 32, 62, 124, 63, 100, 198, 132, 82, 37, 86, 53, 94, 121, 230, 167, 204, 146, 92, 56, 129, 66, 185, 242, 140, 181, 218, 239, 217, 133, 15, 166, 13, 86, 2, 33, 0, 164, 128, 5, 101, 173, 76, 227, 174, 140, 27, 28, 83, 80, 176, 202, 44, 0, 137, 37, 16, 150, 14, 29, 149, 22, 134, 1, 2, 45, 15, 91, 154]),
|
||||
// "SHA-512": new Uint8Array([48, 70, 2, 33, 0, 163, 149, 177, 250, 180, 46, 8, 35, 168, 219, 191, 25, 152, 174, 171, 100, 155, 171, 41, 170, 10, 113, 108, 160, 26, 11, 161, 69, 216, 74, 105, 155, 2, 33, 0, 236, 60, 103, 71, 26, 48, 70, 157, 54, 252, 27, 92, 152, 227, 103, 164, 153, 71, 71, 155, 103, 109, 38, 163, 158, 118, 238, 66, 50, 43, 29, 14])
|
||||
// },
|
||||
// "P-384": {
|
||||
// "SHA-1": new Uint8Array([48, 100, 2, 48, 95, 88, 156, 202, 5, 12, 93, 174, 109, 126, 105, 41, 101, 6, 111, 143, 36, 14, 7, 57, 84, 139, 59, 112, 224, 57, 250, 236, 77, 184, 59, 102, 21, 149, 236, 134, 202, 147, 140, 244, 27, 204, 55, 75, 109, 245, 40, 218, 2, 48, 25, 244, 151, 221, 217, 106, 152, 238, 40, 59, 188, 50, 235, 147, 226, 44, 121, 16, 69, 231, 204, 59, 42, 174, 23, 80, 130, 170, 204, 34, 208, 154, 135, 143, 164, 94, 62, 226, 14, 100, 213, 229, 40, 176, 31, 148, 125, 75]),
|
||||
// "SHA-256": new Uint8Array([48, 102, 2, 49, 0, 171, 16, 188, 253, 115, 108, 16, 69, 39, 187, 21, 188, 22, 86, 146, 2, 212, 145, 7, 120, 218, 186, 149, 139, 205, 55, 114, 208, 25, 183, 127, 2, 198, 234, 151, 193, 94, 12, 173, 170, 234, 130, 83, 193, 214, 110, 108, 72, 2, 49, 0, 136, 132, 142, 128, 157, 111, 141, 240, 49, 203, 203, 32, 121, 165, 57, 138, 81, 95, 64, 235, 251, 241, 59, 203, 214, 169, 17, 153, 112, 115, 91, 51, 66, 206, 172, 143, 39, 0, 217, 68, 242, 172, 86, 155, 174, 24, 39, 155]),
|
||||
// "SHA-384": new Uint8Array([48, 102, 2, 49, 0, 227, 80, 5, 74, 3, 89, 195, 243, 249, 127, 97, 9, 62, 159, 116, 170, 52, 181, 161, 160, 213, 16, 10, 137, 120, 40, 244, 151, 155, 52, 2, 111, 41, 199, 65, 146, 146, 121, 176, 101, 240, 37, 147, 163, 92, 102, 70, 79, 2, 49, 0, 223, 182, 48, 0, 17, 216, 189, 37, 249, 104, 74, 195, 177, 87, 106, 14, 127, 86, 0, 139, 238, 6, 13, 130, 146, 12, 26, 166, 204, 169, 194, 27, 81, 170, 212, 2, 128, 235, 59, 159, 120, 79, 141, 151, 188, 132, 170, 70]),
|
||||
// "SHA-512": new Uint8Array([48, 102, 2, 49, 0, 188, 136, 210, 146, 118, 251, 132, 224, 144, 121, 109, 86, 162, 216, 12, 148, 108, 169, 42, 79, 32, 152, 167, 20, 173, 176, 28, 67, 219, 93, 52, 167, 76, 140, 102, 244, 118, 146, 193, 134, 116, 26, 83, 43, 230, 241, 215, 135, 2, 49, 0, 178, 120, 154, 88, 189, 55, 9, 240, 26, 169, 201, 53, 83, 207, 11, 6, 83, 54, 194, 126, 249, 188, 189, 32, 88, 190, 228, 166, 66, 104, 103, 243, 64, 214, 153, 84, 80, 175, 20, 205, 9, 85, 74, 233, 90, 184, 240, 153])
|
||||
// },
|
||||
// "P-521": {
|
||||
// "SHA-1": new Uint8Array([48, 129, 136, 2, 66, 1, 0, 159, 229, 63, 6, 27, 187, 208, 6, 90, 246, 116, 10, 87, 207, 237, 166, 143, 68, 223, 98, 232, 90, 95, 143, 20, 240, 164, 112, 19, 199, 4, 203, 196, 231, 179, 203, 229, 64, 51, 58, 224, 124, 97, 41, 235, 202, 28, 201, 52, 61, 76, 166, 233, 197, 247, 58, 37, 115, 146, 150, 142, 108, 176, 94, 2, 66, 1, 4, 164, 11, 249, 164, 172, 86, 59, 39, 111, 61, 210, 100, 176, 168, 243, 146, 236, 28, 21, 25, 97, 28, 56, 201, 159, 24, 97, 217, 178, 5, 13, 221, 64, 6, 39, 168, 54, 129, 3, 86, 157, 104, 87, 241, 92, 158, 142, 170, 27, 126, 138, 255, 44, 33, 161, 49, 192, 230, 186, 70, 42, 189, 124, 5]),
|
||||
// "SHA-256": new Uint8Array([48, 129, 134, 2, 65, 115, 189, 109, 44, 118, 67, 34, 176, 16, 126, 246, 157, 34, 188, 209, 65, 231, 207, 180, 139, 53, 97, 110, 157, 19, 55, 35, 134, 90, 160, 20, 252, 130, 210, 179, 22, 76, 3, 142, 212, 71, 48, 251, 64, 18, 148, 199, 234, 163, 193, 120, 13, 153, 63, 174, 253, 58, 34, 130, 88, 138, 194, 248, 173, 53, 2, 65, 63, 0, 229, 139, 245, 33, 197, 245, 98, 139, 59, 87, 144, 16, 220, 183, 237, 125, 136, 134, 143, 146, 195, 0, 209, 105, 217, 20, 121, 76, 64, 87, 232, 86, 87, 136, 117, 237, 39, 83, 248, 3, 50, 236, 152, 121, 37, 116, 93, 91, 241, 235, 152, 95, 177, 217, 45, 247, 66, 193, 248, 131, 205, 132, 74]),
|
||||
// "SHA-384": new Uint8Array([48, 129, 136, 2, 66, 0, 252, 248, 24, 253, 24, 36, 120, 84, 72, 47, 246, 13, 78, 112, 200, 131, 7, 131, 73, 235, 36, 93, 54, 219, 233, 242, 85, 1, 198, 187, 17, 17, 109, 13, 47, 204, 137, 224, 17, 6, 225, 178, 133, 98, 248, 53, 151, 33, 230, 160, 42, 208, 30, 230, 154, 108, 227, 123, 216, 215, 35, 179, 17, 91, 187, 2, 66, 1, 110, 43, 180, 40, 222, 59, 177, 3, 70, 177, 175, 118, 222, 31, 1, 46, 196, 237, 187, 15, 96, 241, 216, 136, 195, 194, 45, 163, 194, 92, 159, 179, 101, 194, 90, 141, 78, 28, 31, 199, 233, 228, 180, 223, 23, 171, 62, 247, 157, 62, 126, 90, 198, 132, 197, 34, 140, 227, 79, 190, 153, 137, 225, 226, 32]),
|
||||
// "SHA-512": new Uint8Array([48, 129, 136, 2, 66, 0, 228, 69, 122, 14, 172, 82, 52, 181, 42, 214, 42, 107, 227, 154, 253, 177, 145, 236, 231, 251, 71, 46, 202, 46, 59, 63, 76, 195, 63, 130, 8, 50, 116, 179, 181, 203, 234, 27, 203, 55, 188, 239, 122, 107, 167, 163, 190, 141, 174, 35, 22, 176, 173, 157, 212, 49, 21, 69, 72, 100, 78, 131, 147, 57, 223, 2, 66, 1, 107, 241, 89, 194, 8, 164, 44, 33, 11, 173, 236, 115, 153, 16, 90, 155, 164, 247, 232, 18, 226, 223, 62, 75, 246, 178, 66, 176, 51, 74, 161, 74, 76, 14, 227, 217, 19, 114, 36, 76, 168, 151, 191, 20, 58, 179, 162, 205, 140, 156, 227, 88, 59, 161, 245, 61, 170, 211, 254, 99, 120, 17, 174, 175, 52])
|
||||
// }
|
||||
// };
|
||||
|
||||
var vectors = [];
|
||||
["P-256", "P-384", "P-521"].forEach(function(curveName) {
|
||||
["SHA-1", "SHA-256", "SHA-384", "SHA-512"].forEach(function(hashName) {
|
||||
var vector = {
|
||||
name: "ECDSA " + curveName + " with " + hashName,
|
||||
publicKeyBuffer: spki[curveName],
|
||||
publicKeyFormat: "spki",
|
||||
publicKey: null,
|
||||
privateKeyBuffer: pkcs8[curveName],
|
||||
privateKeyFormat: "pkcs8",
|
||||
privateKey: null,
|
||||
algorithmName: "ECDSA",
|
||||
namedCurve: curveName,
|
||||
hashName: hashName,
|
||||
plaintext: plaintext,
|
||||
signature: signatures[curveName][hashName]
|
||||
};
|
||||
|
||||
vectors.push(vector);
|
||||
})
|
||||
});
|
||||
|
||||
return vectors;
|
||||
}
|
347
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/hmac.js
Normal file
347
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/hmac.js
Normal file
|
@ -0,0 +1,347 @@
|
|||
|
||||
function run_test() {
|
||||
var subtle = self.crypto.subtle; // Change to test prefixed implementations
|
||||
|
||||
// When are all these tests really done? When all the promises they use have resolved.
|
||||
var all_promises = [];
|
||||
|
||||
// Source file hmac_vectors.js provides the getTestVectors method
|
||||
// for the algorithm that drives these tests.
|
||||
var testVectors = getTestVectors();
|
||||
|
||||
// Test verification first, because signing tests rely on that working
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with an altered buffer after call
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
promise_test(function(test) {
|
||||
var signature = copyBuffer(vector.signature);
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature is not verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
signature[0] = 255 - signature[0];
|
||||
return operation;
|
||||
}, vector.name + " verification with altered signature after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification with altered signature after call");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful verification even if plaintext is altered after call.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
promise_test(function(test) {
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
return operation;
|
||||
}, vector.name + " with altered plaintext after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " with altered plaintext");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to no "verify" usage.
|
||||
testVectors.forEach(function(originalVector) {
|
||||
var vector = Object.assign({}, originalVector);
|
||||
|
||||
var promise = importVectorKeys(vector, ["sign"])
|
||||
.then(function(vector) {
|
||||
promise_test(function(test) {
|
||||
return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext)
|
||||
.then(function(plaintext) {
|
||||
assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " no verify usage");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " no verify usage");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful signing and verification.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
return subtle.sign({name: "HMAC", hash: vector.hash}, vector.key, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
// Can we get the verify the new signature?
|
||||
return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Round trip verifies");
|
||||
return signature;
|
||||
}, function(err) {
|
||||
assert_unreached("verify error for test " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
});
|
||||
}, vector.name + " round trip");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested signing or verifying
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " round trip");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test signing with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"])
|
||||
.then(function(wrongKey) {
|
||||
return importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.sign({name: "HMAC", hash: vector.hash}, wrongKey.privateKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Signing should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " signing with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name");
|
||||
});
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
|
||||
}, "generate wrong key step: " + vector.name + " signing with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var promise = subtle.generateKey({name: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"])
|
||||
.then(function(wrongKey) {
|
||||
return importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, wrongKey.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Verifying should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verifying with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name");
|
||||
});
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
|
||||
}, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Verification should fail if the plaintext is changed
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature is NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to wrong plaintext");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to wrong plaintext");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Verification should fail if the signature is changed
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
var signature = copyBuffer(vector.signature);
|
||||
signature[0] = 255 - signature[0];
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature is NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to wrong signature");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to wrong signature");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Verification should fail if the signature is wrong length
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify", "sign"])
|
||||
.then(function(vector) {
|
||||
var signature = vector.signature.slice(1); // Drop first byte
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature is NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure due to short signature");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure due to short signature");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Promise.all(all_promises)
|
||||
.then(function() {done();})
|
||||
.catch(function() {done();})
|
||||
return;
|
||||
|
||||
// A test vector has all needed fields for signing and verifying, EXCEPT that the
|
||||
// key field may be null. This function replaces that null with the Correct
|
||||
// CryptoKey object.
|
||||
//
|
||||
// Returns a Promise that yields an updated vector on success.
|
||||
function importVectorKeys(vector, keyUsages) {
|
||||
if (vector.key !== null) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(vector);
|
||||
});
|
||||
} else {
|
||||
return subtle.importKey("raw", vector.keyBuffer, {name: "HMAC", hash: vector.hash}, false, keyUsages)
|
||||
.then(function(key) {
|
||||
vector.key = key;
|
||||
return vector;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a copy of the sourceBuffer it is sent.
|
||||
function copyBuffer(sourceBuffer) {
|
||||
var source = new Uint8Array(sourceBuffer);
|
||||
var copy = new Uint8Array(sourceBuffer.byteLength)
|
||||
|
||||
for (var i=0; i<source.byteLength; i++) {
|
||||
copy[i] = source[i];
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("hmac_vectors.js");
|
||||
importScripts("hmac.js");
|
||||
|
||||
run_test();
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
function getTestVectors() {
|
||||
var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
|
||||
|
||||
var raw = {
|
||||
"SHA-1": new Uint8Array([71, 162, 7, 70, 209, 113, 121, 219, 101, 224, 167, 157, 237, 255, 199, 253, 241, 129, 8, 27]),
|
||||
"SHA-256": new Uint8Array([229, 136, 236, 8, 17, 70, 61, 118, 114, 65, 223, 16, 116, 180, 122, 228, 7, 27, 81, 242, 206, 54, 83, 123, 166, 156, 205, 195, 253, 194, 183, 168]),
|
||||
"SHA-384": new Uint8Array([107, 29, 162, 142, 171, 31, 88, 42, 217, 113, 142, 255, 224, 94, 35, 213, 253, 44, 152, 119, 162, 217, 68, 63, 144, 190, 192, 147, 190, 206, 46, 167, 210, 53, 76, 208, 189, 197, 225, 71, 210, 233, 0, 147, 115, 73, 68, 136]),
|
||||
"SHA-512": new Uint8Array([93, 204, 53, 148, 67, 170, 246, 82, 250, 19, 117, 214, 179, 230, 31, 220, 242, 155, 180, 162, 139, 213, 211, 220, 250, 64, 248, 47, 144, 107, 178, 128, 4, 85, 219, 3, 181, 211, 31, 185, 114, 161, 90, 109, 1, 3, 162, 78, 86, 209, 86, 161, 25, 192, 229, 161, 233, 42, 68, 195, 197, 101, 124, 249])
|
||||
};
|
||||
|
||||
var signatures = {
|
||||
"SHA-1": new Uint8Array([5, 51, 144, 42, 153, 248, 82, 78, 229, 10, 240, 29, 56, 222, 220, 225, 51, 217, 140, 160]),
|
||||
"SHA-256": new Uint8Array([133, 164, 12, 234, 46, 7, 140, 40, 39, 163, 149, 63, 251, 102, 194, 123, 41, 26, 71, 43, 13, 112, 160, 0, 11, 69, 216, 35, 128, 62, 235, 84]),
|
||||
"SHA-384": new Uint8Array([33, 124, 61, 80, 240, 186, 154, 109, 110, 174, 30, 253, 215, 165, 24, 254, 46, 56, 128, 181, 130, 164, 13, 6, 30, 144, 153, 193, 224, 38, 239, 88, 130, 84, 139, 93, 92, 236, 221, 85, 152, 217, 155, 107, 111, 48, 87, 255]),
|
||||
"SHA-512": new Uint8Array([97, 251, 39, 140, 63, 251, 12, 206, 43, 241, 207, 114, 61, 223, 216, 239, 31, 147, 28, 12, 97, 140, 37, 144, 115, 36, 96, 89, 57, 227, 249, 162, 198, 244, 175, 105, 11, 218, 52, 7, 220, 47, 87, 112, 246, 160, 164, 75, 149, 77, 100, 163, 50, 227, 238, 8, 33, 171, 248, 43, 127, 62, 153, 193])
|
||||
};
|
||||
|
||||
// Each test vector has the following fields:
|
||||
// name - a unique name for this vector
|
||||
// keyBuffer - an arrayBuffer with the key data
|
||||
// key - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
|
||||
// hashName - the hash function to sign with
|
||||
// plaintext - the text to encrypt
|
||||
// signature - the expected signature
|
||||
var vectors = [];
|
||||
Object.keys(raw).forEach(function(hashName) {
|
||||
vectors.push({
|
||||
name: "HMAC with " + hashName,
|
||||
hash: hashName,
|
||||
keyBuffer: raw[hashName],
|
||||
key: null,
|
||||
plaintext: plaintext,
|
||||
signature: signatures[hashName]
|
||||
});
|
||||
});
|
||||
|
||||
return vectors;
|
||||
}
|
399
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/rsa.js
Normal file
399
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/rsa.js
Normal file
|
@ -0,0 +1,399 @@
|
|||
|
||||
function run_test() {
|
||||
var subtle = self.crypto.subtle; // Change to test prefixed implementations
|
||||
|
||||
// When are all these tests really done? When all the promises they use have resolved.
|
||||
var all_promises = [];
|
||||
|
||||
// Source file [algorithm_name]_vectors.js provides the getTestVectors method
|
||||
// for the algorithm that drives these tests.
|
||||
var testVectors = getTestVectors();
|
||||
|
||||
// Test verification first, because signing tests rely on that working
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with an altered buffer after call
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var signature = copyBuffer(vector.signature);
|
||||
var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
signature[0] = 255 - signature[0];
|
||||
return operation;
|
||||
}, vector.name + " verification with altered signature after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification with altered signature after call");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful verification even if plaintext is altered after call.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Signature verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
return operation;
|
||||
}, vector.name + " with altered plaintext after call");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " with altered plaintext after call");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to using privateKey to verify.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
return subtle.verify(vector.algorithm, vector.privateKey, vector.signature, vector.plaintext)
|
||||
.then(function(plaintext) {
|
||||
assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " using privateKey to verify");
|
||||
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " using privateKey to verify");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to using publicKey to sign.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
return subtle.sign(vector.algorithm, vector.publicKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " using publicKey to sign");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " using publicKey to sign");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for failures due to no "verify" usage.
|
||||
testVectors.forEach(function(originalVector) {
|
||||
var vector = Object.assign({}, originalVector);
|
||||
|
||||
var promise = importVectorKeys(vector, [], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
return subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(plaintext) {
|
||||
assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " no verify usage");
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " no verify usage");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Check for successful signing and verification.
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
// Can we verify the new signature?
|
||||
return subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_true(is_verified, "Round trip verifies");
|
||||
return signature;
|
||||
}, function(err) {
|
||||
assert_unreached("verify error for test " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
})
|
||||
.then(function(priorSignature) {
|
||||
// Will a second signing give us different signature? It should for PSS with non-empty salt
|
||||
return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
if ("saltLength" in vector.algorithm && vector.algorithm.saltLength > 0) {
|
||||
assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures")
|
||||
} else {
|
||||
assert_true(equalBuffers(priorSignature, signature), "Two signings with empty salt give same signature")
|
||||
}
|
||||
}, function(err) {
|
||||
assert_unreached("second time verify error for test " + vector.name + ": '" + err.message + "'");
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'");
|
||||
});
|
||||
}, vector.name + " round trip");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested signing or verifying
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " round trip");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
|
||||
// Test signing with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var alteredVector = Object.assign({}, vector);
|
||||
alteredVector.algorithm = Object.assign({}, vector.algorithm);
|
||||
if (vector.algorithm.name === "RSA-PSS") {
|
||||
alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5";
|
||||
} else {
|
||||
alteredVector.algorithm.name = "RSA-PSS";
|
||||
}
|
||||
|
||||
var promise = importVectorKeys(alteredVector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.sign(vector.algorithm, alteredVector.privateKey, vector.plaintext)
|
||||
.then(function(signature) {
|
||||
assert_unreached("Signing should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " signing with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Test verification with the wrong algorithm
|
||||
testVectors.forEach(function(vector) {
|
||||
// Want to get the key for the wrong algorithm
|
||||
var alteredVector = Object.assign({}, vector);
|
||||
alteredVector.algorithm = Object.assign({}, vector.algorithm);
|
||||
if (vector.algorithm.name === "RSA-PSS") {
|
||||
alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5";
|
||||
} else {
|
||||
alteredVector.algorithm.name = "RSA-PSS";
|
||||
}
|
||||
|
||||
var promise = importVectorKeys(alteredVector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
// Some tests are sign only
|
||||
if (!("signature" in vector)) {
|
||||
return;
|
||||
}
|
||||
promise_test(function(test) {
|
||||
var operation = subtle.verify(vector.algorithm, alteredVector.publicKey, vector.signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_unreached("Verification should not have succeeded for " + vector.name);
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification with wrong algorithm name");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification with wrong algorithm name");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Verification should fail with wrong signature
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var signature = copyBuffer(vector.signature);
|
||||
signature[0] = 255 - signature[0];
|
||||
var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure with altered signature");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure with altered signature");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
// Verification should fail with wrong plaintext
|
||||
testVectors.forEach(function(vector) {
|
||||
var promise = importVectorKeys(vector, ["verify"], ["sign"])
|
||||
.then(function(vectors) {
|
||||
promise_test(function(test) {
|
||||
var plaintext = copyBuffer(vector.plaintext);
|
||||
plaintext[0] = 255 - plaintext[0];
|
||||
var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)
|
||||
.then(function(is_verified) {
|
||||
assert_false(is_verified, "Signature NOT verified");
|
||||
}, function(err) {
|
||||
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
|
||||
});
|
||||
|
||||
return operation;
|
||||
}, vector.name + " verification failure with altered plaintext");
|
||||
|
||||
}, function(err) {
|
||||
// We need a failed test if the importVectorKey operation fails, so
|
||||
// we know we never tested verification.
|
||||
promise_test(function(test) {
|
||||
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
|
||||
}, "importVectorKeys step: " + vector.name + " verification failure with altered plaintext");
|
||||
});
|
||||
|
||||
all_promises.push(promise);
|
||||
});
|
||||
|
||||
|
||||
Promise.all(all_promises)
|
||||
.then(function() {done();})
|
||||
.catch(function() {done();})
|
||||
|
||||
// A test vector has all needed fields for signing and verifying, EXCEPT that the
|
||||
// key field may be null. This function replaces that null with the Correct
|
||||
// CryptoKey object.
|
||||
//
|
||||
// Returns a Promise that yields an updated vector on success.
|
||||
function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) {
|
||||
var publicPromise, privatePromise;
|
||||
|
||||
if (vector.publicKey !== null) {
|
||||
publicPromise = new Promise(function(resolve, reject) {
|
||||
resolve(vector);
|
||||
});
|
||||
} else {
|
||||
publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, publicKeyUsages)
|
||||
.then(function(key) {
|
||||
vector.publicKey = key;
|
||||
return vector;
|
||||
}); // Returns a copy of the sourceBuffer it is sent.
|
||||
}
|
||||
|
||||
if (vector.privateKey !== null) {
|
||||
privatePromise = new Promise(function(resolve, reject) {
|
||||
resolve(vector);
|
||||
});
|
||||
} else {
|
||||
privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, privateKeyUsages)
|
||||
.then(function(key) {
|
||||
vector.privateKey = key;
|
||||
return vector;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.all([publicPromise, privatePromise]);
|
||||
}
|
||||
|
||||
// Returns a copy of the sourceBuffer it is sent.
|
||||
function copyBuffer(sourceBuffer) {
|
||||
var source = new Uint8Array(sourceBuffer);
|
||||
var copy = new Uint8Array(sourceBuffer.byteLength)
|
||||
|
||||
for (var i=0; i<source.byteLength; i++) {
|
||||
copy[i] = source[i];
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("rsa_pkcs_vectors.js");
|
||||
importScripts("rsa.js");
|
||||
|
||||
run_test();
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("rsa_pss_vectors.js");
|
||||
importScripts("rsa.js");
|
||||
|
||||
run_test();
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: sign() and verify() Using ECDSA</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-sign">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-verify">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="ecdsa_vectors.js"></script>
|
||||
<script src="ecdsa.js"></script>
|
||||
|
||||
<h1>sign and verify Tests for ECDSA</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: sign() and verify() Using HMAC</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-sign">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-verify">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="hmac_vectors.js"></script>
|
||||
<script src="hmac.js"></script>
|
||||
|
||||
<h1>sign and verify Tests for HMAC</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: sign() and verify() Using RSASSA-PKCS1-v1_5</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-sign">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-verify">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="rsa_pkcs_vectors.js"></script>
|
||||
<script src="rsa.js"></script>
|
||||
|
||||
<h1>sign and verify Tests for RSASSA-PKCS1-v1_5</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: sign() and verify() Using RSA-PSS</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-sign">
|
||||
<link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-verify">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="rsa_pss_vectors.js"></script>
|
||||
<script src="rsa.js"></script>
|
||||
|
||||
<h1>sign and verify Tests for RSA-PSS</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: wrapKey() and unwrapKey()</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-wrapKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="wrapKey_unwrapKey.js"></script>
|
||||
|
||||
<h1>wrapKey and unwrapKey Tests</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,266 @@
|
|||
// Tests for wrapKey and unwrapKey round tripping
|
||||
|
||||
function run_test() {
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
var wrappers = []; // Things we wrap (and upwrap) keys with
|
||||
var keys = []; // Things to wrap and unwrap
|
||||
|
||||
// Generate all the keys needed, then iterate over all combinations
|
||||
// to test wrapping and unwrapping.
|
||||
Promise.all([generateWrappingKeys(), generateKeysToWrap()])
|
||||
.then(function(results) {
|
||||
wrappers.forEach(function(wrapper) {
|
||||
keys.forEach(function(key) {
|
||||
testWrapping(wrapper, key);
|
||||
})
|
||||
});
|
||||
}, function(err) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("A key failed to generate: " + err.name + ": " + err.message)
|
||||
}, "Could not run all tests")
|
||||
})
|
||||
.then(function() {
|
||||
done();
|
||||
}, function(error) {
|
||||
promise_test(function(test) {
|
||||
assert_unreached("A test failed to run: " + err.name + ": " + err.message)
|
||||
}, "Could not run all tests")
|
||||
});
|
||||
|
||||
|
||||
function generateWrappingKeys() {
|
||||
// There are five algorithms that can be used for wrapKey/unwrapKey.
|
||||
// Generate one key with typical parameters for each kind.
|
||||
//
|
||||
// Note: we don't need cryptographically strong parameters for things
|
||||
// like IV - just any legal value will do.
|
||||
var parameters = [
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
generateParameters: {name: "RSA-OAEP", modulusLength: 4096, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"},
|
||||
wrapParameters: {name: "RSA-OAEP", label: new Uint8Array(8)}
|
||||
},
|
||||
{
|
||||
name: "AES-CTR",
|
||||
generateParameters: {name: "AES-CTR", length: 128},
|
||||
wrapParameters: {name: "AES-CTR", counter: new Uint8Array(16), length: 64}
|
||||
},
|
||||
{
|
||||
name: "AES-CBC",
|
||||
generateParameters: {name: "AES-CBC", length: 128},
|
||||
wrapParameters: {name: "AES-CBC", iv: new Uint8Array(16)}
|
||||
},
|
||||
{
|
||||
name: "AES-GCM",
|
||||
generateParameters: {name: "AES-GCM", length: 128},
|
||||
wrapParameters: {name: "AES-GCM", iv: new Uint8Array(16), additionalData: new Uint8Array(16), tagLength: 64}
|
||||
},
|
||||
{
|
||||
name: "AES-KW",
|
||||
generateParameters: {name: "AES-KW", length: 128},
|
||||
wrapParameters: {name: "AES-KW"}
|
||||
}
|
||||
];
|
||||
|
||||
return Promise.all(parameters.map(function(params) {
|
||||
return subtle.generateKey(params.generateParameters, true, ["wrapKey", "unwrapKey"])
|
||||
.then(function(key) {
|
||||
var wrapper;
|
||||
if (params.name === "RSA-OAEP") { // we have a key pair, not just a key
|
||||
wrapper = {wrappingKey: key.publicKey, unwrappingKey: key.privateKey, parameters: params};
|
||||
} else {
|
||||
wrapper = {wrappingKey: key, unwrappingKey: key, parameters: params};
|
||||
}
|
||||
wrappers.push(wrapper);
|
||||
return true;
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function generateKeysToWrap() {
|
||||
var parameters = [
|
||||
{algorithm: {name: "RSASSA-PKCS1-v1_5", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{algorithm: {name: "RSA-PSS", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{algorithm: {name: "RSA-OAEP", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["decrypt"], publicUsages: ["encrypt"]},
|
||||
{algorithm: {name: "ECDSA", namedCurve: "P-256"}, privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{algorithm: {name: "ECDH", namedCurve: "P-256"}, privateUsages: ["deriveBits"], publicUsages: []},
|
||||
{algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]},
|
||||
{algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]},
|
||||
{algorithm: {name: "HMAC", length: 128, hash: "SHA-256"}, usages: ["sign", "verify"]}
|
||||
];
|
||||
|
||||
return Promise.all(parameters.map(function(params) {
|
||||
var usages;
|
||||
if ("usages" in params) {
|
||||
usages = params.usages;
|
||||
} else {
|
||||
usages = params.publicUsages.concat(params.privateUsages);
|
||||
}
|
||||
|
||||
return subtle.generateKey(params.algorithm, true, usages)
|
||||
.then(function(result) {
|
||||
if (result.constructor === CryptoKey) {
|
||||
keys.push({name: params.algorithm.name, algorithm: params.algorithm, usages: params.usages, key: result});
|
||||
} else {
|
||||
keys.push({name: params.algorithm.name + " public key", algorithm: params.algorithm, usages: params.publicUsages, key: result.publicKey});
|
||||
keys.push({name: params.algorithm.name + " private key", algorithm: params.algorithm, usages: params.privateUsages, key: result.privateKey});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
// Can we successfully "round-trip" (wrap, then unwrap, a key)?
|
||||
function testWrapping(wrapper, toWrap) {
|
||||
var formats;
|
||||
|
||||
if (toWrap.name.includes("private")) {
|
||||
formats = ["pkcs8", "jwk"];
|
||||
} else if (toWrap.name.includes("public")) {
|
||||
formats = ["spki", "jwk"]
|
||||
} else {
|
||||
formats = ["raw", "jwk"]
|
||||
}
|
||||
|
||||
formats.forEach(function(fmt) {
|
||||
var originalExport;
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.exportKey(fmt, toWrap.key)
|
||||
.then(function(exportedKey) {
|
||||
originalExport = exportedKey;
|
||||
return exportedKey;
|
||||
}).then(function(exportedKey) {
|
||||
return subtle.wrapKey(fmt, toWrap.key, wrapper.wrappingKey, wrapper.parameters.wrapParameters);
|
||||
}).then(function(wrappedResult) {
|
||||
return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages)
|
||||
}).then(function(unwrappedResult) {
|
||||
return subtle.exportKey(fmt, unwrappedResult)
|
||||
}).then(function(roundTripExport) {
|
||||
if ("byteLength" in originalExport) {
|
||||
assert_true(equalBuffers(originalExport, roundTripExport), "Post-wrap export matches original export");
|
||||
} else {
|
||||
assert_true(equalJwk(originalExport, roundTripExport), "Post-wrap export matches original export.");
|
||||
}
|
||||
}, function(err) {
|
||||
if (wrappingIsPossible(originalExport, wrapper.parameters.name)) {
|
||||
assert_unreached("Round trip threw an error - " + err.name + ': "' + err.message + '"');
|
||||
} else {
|
||||
assert_true(true, "Skipped test due to key length restrictions");
|
||||
}
|
||||
})
|
||||
}, "Can wrap and unwrap " + toWrap.name + " keys using " + fmt + " and " + wrapper.parameters.name);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// RSA-OAEP can only wrap relatively small payloads. AES-KW can only
|
||||
// wrap payloads a multiple of 8 bytes long.
|
||||
//
|
||||
// Note that JWK payloads will be converted to ArrayBuffer for wrapping,
|
||||
// and should automatically be padded if needed for AES-KW.
|
||||
function wrappingIsPossible(exportedKey, algorithmName) {
|
||||
if ("byteLength" in exportedKey && algorithmName === "AES-KW") {
|
||||
return exportedKey.byteLength % 8 === 0;
|
||||
}
|
||||
|
||||
if ("byteLength" in exportedKey && algorithmName === "RSA-OAEP") {
|
||||
// RSA-OAEP can only encrypt payloads with lengths shorter
|
||||
// than modulusLength - 2*hashLength - 1 bytes long. For
|
||||
// a 4096 bit modulus and SHA-256, that comes to
|
||||
// 4096/8 - 2*(256/8) - 1 = 512 - 2*32 - 1 = 447 bytes.
|
||||
return exportedKey.byteLength <= 446;
|
||||
}
|
||||
|
||||
if ("kty" in exportedKey && algorithmName === "RSA-OAEP") {
|
||||
return JSON.stringify(exportedKey).length <= 478;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Helper methods follow:
|
||||
|
||||
// Are two array buffers the same?
|
||||
function equalBuffers(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
for (var i=0; i<a.byteLength; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are two Jwk objects "the same"? That is, does the object returned include
|
||||
// matching values for each property that was expected? It's okay if the
|
||||
// returned object has extra methods; they aren't checked.
|
||||
function equalJwk(expected, got) {
|
||||
var fields = Object.keys(expected);
|
||||
var fieldName;
|
||||
|
||||
for(var i=0; i<fields.length; i++) {
|
||||
fieldName = fields[i];
|
||||
if (!(fieldName in got)) {
|
||||
return false;
|
||||
}
|
||||
if (objectToString(expected[fieldName]) !== objectToString(got[fieldName])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Character representation of any object we may use as a parameter.
|
||||
function objectToString(obj) {
|
||||
var keyValuePairs = [];
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else if (typeof obj === "object") {
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
|
||||
});
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
} else if (typeof obj === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
var keyValuePairs = [];
|
||||
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
var value = obj[keyName];
|
||||
if (typeof value === "object") {
|
||||
value = objectToString(value);
|
||||
} else if (typeof value === "array") {
|
||||
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
keyValuePairs.push(keyName + ": " + value);
|
||||
});
|
||||
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("wrapKey_unwrapKey.js");
|
||||
|
||||
run_test();
|
Loading…
Add table
Add a link
Reference in a new issue