Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,3 @@
spec: https://w3c.github.io/webcrypto/
suggested_reviewers:
- twiss

View File

@ -0,0 +1 @@
Directory for Crypto API tests

View File

@ -0,0 +1,213 @@
// META: title=WebCryptoAPI: Properties discard the context in algorithm normalization
let nextTest = 0;
let tests = {};
function closeChild(testId) {
if (tests[testId]) {
let {child, t} = tests[testId];
delete tests[testId];
document.body.removeChild(child);
t.done();
}
}
function runInChild(t, childScript) {
let testId = nextTest++;
const preamble = `
let testId = ${testId};
function closeChildOnAccess(obj, key) {
const oldValue = obj[key];
Object.defineProperty(obj, key, {get: () => {
top.closeChild(testId);
return oldValue;
}});
}
`;
childScript = preamble + childScript;
let child = document.createElement("iframe");
tests[testId] = {t, child};
document.body.appendChild(child);
let script = document.createElement("script");
script.textContent = childScript;
child.contentDocument.body.appendChild(script);
}
async_test((t) => {
const childScript = `
let algorithm = {name: "AES-GCM", length: 128};
closeChildOnAccess(algorithm, "name");
crypto.subtle.generateKey(algorithm, true, ["encrypt", "decrypt"]);`;
runInChild(t, childScript);
}, "Context is discarded in generateKey");
async_test((t) => {
const childScript = `
let algorithm = {name: "AES-GCM"};
closeChildOnAccess(algorithm, "name");
crypto.subtle.importKey("raw", new Uint8Array(16), algorithm, true,
["encrypt", "decrypt"]);`;
runInChild(t, childScript);
}, "Context is discarded in importKey");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
let algorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
closeChildOnAccess(algorithm, "name");
crypto.subtle.encrypt(algorithm, key, new Uint8Array());
})();`;
runInChild(t, childScript);
}, "Context is discarded in encrypt");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
let algorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
let encrypted = await crypto.subtle.encrypt(algorithm, key, new Uint8Array());
closeChildOnAccess(algorithm, "name");
crypto.subtle.decrypt(algorithm, key, encrypted);
})();`;
runInChild(t, childScript);
}, "Context is discarded in decrypt");
async_test((t) => {
const childScript = `
let algorithm = {name: "SHA-256"};
closeChildOnAccess(algorithm, "name");
crypto.subtle.digest(algorithm, new Uint8Array());`;
runInChild(t, childScript);
}, "Context is discarded in digest");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.generateKey(
{name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
let algorithm = {name: "ECDSA", hash: "SHA-256"};
closeChildOnAccess(algorithm, "name");
crypto.subtle.sign(algorithm, key.privateKey, new Uint8Array());
})();`;
runInChild(t, childScript);
}, "Context is discarded in sign");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.generateKey(
{name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
let algorithm = {name: "ECDSA", hash: "SHA-256"};
let data = new Uint8Array();
let signature = await crypto.subtle.sign(algorithm, key.privateKey, data);
closeChildOnAccess(algorithm, "name");
crypto.subtle.verify(algorithm, key.publicKey, signature, data);
})();`;
runInChild(t, childScript);
}, "Context is discarded in verify");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.importKey(
"raw", new Uint8Array(16), "HKDF", false, ["deriveBits"]);
let algorithm = {
name: "HKDF",
hash: "SHA-256",
salt: new Uint8Array(),
info: new Uint8Array(),
};
closeChildOnAccess(algorithm, "name");
crypto.subtle.deriveBits(algorithm, key, 16);
})();`;
runInChild(t, childScript);
}, "Context is discarded in deriveBits");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.importKey(
"raw", new Uint8Array(16), "HKDF", false, ["deriveKey"]);
let algorithm = {
name: "HKDF",
hash: "SHA-256",
salt: new Uint8Array(),
info: new Uint8Array(),
};
let derivedAlgorithm = {name: "AES-GCM", length: 128};
closeChildOnAccess(algorithm, "name");
crypto.subtle.deriveKey(algorithm, key, derivedAlgorithm, true,
["encrypt", "decrypt"]);
})();`;
runInChild(t, childScript);
}, "Context is discarded in deriveKey");
async_test((t) => {
const childScript = `
(async () => {
let key = await crypto.subtle.importKey(
"raw", new Uint8Array(16), "HKDF", false, ["deriveKey"]);
let algorithm = {
name: "HKDF",
hash: "SHA-256",
salt: new Uint8Array(),
info: new Uint8Array(),
};
let derivedAlgorithm = {name: "AES-GCM", length: 128};
closeChildOnAccess(derivedAlgorithm, "name");
crypto.subtle.deriveKey(algorithm, key, derivedAlgorithm, true,
["encrypt", "decrypt"]);
})();`;
runInChild(t, childScript);
}, "Context is discarded in deriveKey (2)");
async_test((t) => {
const childScript = `
(async () => {
let wrapKey = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
let key = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
closeChildOnAccess(wrapAlgorithm, "name");
crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
})();`;
runInChild(t, childScript);
}, "Context is discarded in wrapKey");
async_test((t) => {
const childScript = `
(async () => {
let wrapKey = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
let keyAlgorithm = {name: "AES-GCM", length: 128};
let keyUsages = ["encrypt", "decrypt"];
let key = await crypto.subtle.generateKey(keyAlgorithm, true, keyUsages);
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
let wrapped = await crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
closeChildOnAccess(wrapAlgorithm, "name");
crypto.subtle.unwrapKey(
"raw", wrapped, wrapKey, wrapAlgorithm, keyAlgorithm, true, keyUsages);
})();`;
runInChild(t, childScript);
}, "Context is discarded in unwrapKey");
async_test((t) => {
const childScript = `
(async () => {
let wrapKey = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
let keyAlgorithm = {name: "AES-GCM", length: 128};
let keyUsages = ["encrypt", "decrypt"];
let key = await crypto.subtle.generateKey(keyAlgorithm, true, keyUsages);
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
let wrapped = await crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
closeChildOnAccess(keyAlgorithm, "name");
crypto.subtle.unwrapKey(
"raw", wrapped, wrapKey, wrapAlgorithm, keyAlgorithm, true, keyUsages);
})();`;
runInChild(t, childScript);
}, "Context is discarded in unwrapKey (2)");

View File

@ -0,0 +1,44 @@
// META: title=WebCryptoAPI: CryptoKey cached ECMAScript objects
// https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm
// https://github.com/servo/servo/issues/33908
promise_test(function() {
return self.crypto.subtle.generateKey(
{
name: "AES-CTR",
length: 256,
},
true,
["encrypt"],
).then(
function(key) {
let a = key.algorithm;
let b = key.algorithm;
assert_true(a === b);
},
function(err) {
assert_unreached("generateKey threw an unexpected error: " + err.toString());
}
);
}, "CryptoKey.algorithm getter returns cached object");
promise_test(function() {
return self.crypto.subtle.generateKey(
{
name: "AES-CTR",
length: 256,
},
true,
["encrypt"],
).then(
function(key) {
let a = key.usages;
let b = key.usages;
assert_true(a === b);
},
function(err) {
assert_unreached("generateKey threw an unexpected error: " + err.toString());
}
);
}, "CryptoKey.usages getter returns cached object");

View File

@ -0,0 +1,260 @@
function define_tests_25519() {
return define_tests("X25519");
}
function define_tests_448() {
return define_tests("X448");
}
function define_tests(algorithmName) {
// May want to test prefixed implementations.
var subtle = self.crypto.subtle;
// Verify the derive functions perform checks against the all-zero value results,
// ensuring small-order points are rejected.
// https://www.rfc-editor.org/rfc/rfc7748#section-6.1
{
kSmallOrderPoint[algorithmName].forEach(function(test) {
promise_test(async() => {
let derived;
let privateKey;
let publicKey;
try {
privateKey = await subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveBits", "deriveKey"]);
publicKey = await subtle.importKey("spki", test.vector,
{name: algorithmName},
false, [])
derived = await subtle.deriveBits({name: algorithmName, public: publicKey}, privateKey, 8 * sizes[algorithmName]);
} catch (err) {
assert_true(privateKey !== undefined, "Private key should be valid.");
assert_true(publicKey !== undefined, "Public key should be valid.");
assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + ".");
}
assert_equals(derived, undefined, "Operation succeeded, but should not have.");
}, algorithmName + " key derivation checks for all-zero value result with a key of order " + test.order);
});
}
return importKeys(pkcs8, spki, sizes)
.then(function(results) {
publicKeys = results.publicKeys;
privateKeys = results.privateKeys;
noDeriveBitsKeys = results.noDeriveBitsKeys;
ecdhKeys = results.ecdhKeys;
{
// Basic success case
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.then(function(derivation) {
assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits");
}, function(err) {
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " good parameters");
// Case insensitivity check
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.then(function(derivation) {
assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits");
}, function(err) {
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " mixed case parameters");
// Shorter than entire derivation per algorithm
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 32)
.then(function(derivation) {
assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 32), "Derived correct bits");
}, function(err) {
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " short result");
// Non-multiple of 8
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 11)
.then(function(derivation) {
assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 11), "Derived correct bits");
}, function(err) {
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " non-multiple of 8 bits");
// Errors to test:
// - missing public property TypeError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " missing public property");
// - Non CryptoKey public property TypeError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " public property of algorithm is not a CryptoKey");
// - wrong algorithm
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: ecdhKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " mismatched algorithms");
// - No deriveBits usage in baseKey InvalidAccessError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveBitsKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " no deriveBits usage for base key");
// - Use public key for baseKey InvalidAccessError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " base key is not a private key");
// - Use private key for public property InvalidAccessError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
}, algorithmName + " 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) {
return subtle.deriveBits({name: algorithmName, public: secretKey}, privateKeys[algorithmName], 8 * sizes[algorithmName])
.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);
});
});
}, algorithmName + " public property value is a secret key");
// - Length greater than possible for particular curves OperationError
promise_test(function(test) {
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] + 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);
});
}, algorithmName + " asking for too many bits");
}
});
function importKeys(pkcs8, spki, sizes) {
var privateKeys = {};
var publicKeys = {};
var noDeriveBitsKeys = {};
var ecdhPublicKeys = {};
var promises = [];
{
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveBits", "deriveKey"])
.then(function(key) {
privateKeys[algorithmName] = key;
}, function (err) {
privateKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveKey"])
.then(function(key) {
noDeriveBitsKeys[algorithmName] = key;
}, function (err) {
noDeriveBitsKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("spki", spki[algorithmName],
{name: algorithmName},
false, [])
.then(function(key) {
publicKeys[algorithmName] = key;
}, function (err) {
publicKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("spki", ecSPKI,
{name: "ECDH", namedCurve: "P-256"},
false, [])
.then(function(key) {
ecdhPublicKeys[algorithmName] = key;
});
}
return Promise.all(promises)
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveBitsKeys: noDeriveBitsKeys, ecdhKeys: ecdhPublicKeys}});
}
// 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;
}
}

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves
// META: script=cfrg_curves_bits_fixtures.js
// META: script=cfrg_curves_bits.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests_25519, 'setup - define tests');

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves
// META: script=cfrg_curves_bits_fixtures.js
// META: script=cfrg_curves_bits.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests_448, 'setup - define tests');

View File

@ -0,0 +1,40 @@
var pkcs8 = {
"X25519": new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
"X448": new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158])
};
var spki = {
"X25519": new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
"X448": new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111])
};
var sizes = {
"X25519": 32,
"X448": 56
};
var derivations = {
"X25519": new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 161, 149, 0, 8]),
"X448": new Uint8Array([240, 246, 197, 241, 127, 148, 244, 41, 30, 171, 113, 120, 134, 109, 55, 236, 137, 6, 221, 108, 81, 65, 67, 220, 133, 190, 124, 242, 141, 239, 243, 155, 114, 110, 15, 109, 207, 129, 14, 181, 148, 220, 169, 123, 72, 130, 189, 68, 196, 62, 167, 220, 103, 244, 154, 78])
};
var kSmallOrderPoint = {
"X25519": [
{ order: "0", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) },
{ order: "1", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) },
{ order: "8", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 224, 235, 122, 124, 59, 65, 184, 174, 22, 86, 227, 250, 241, 159, 196, 106, 218, 9, 141, 235, 156, 50, 177, 253, 134, 98, 5, 22, 95, 73, 184, 0]) },
{ order: "p-1 (order 2)", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]) },
{ order: "p (=0, order 4)", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 237, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]) },
{ order: "p+1 (=1, order 1)", vector : new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 238, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]) },
],
"X448": [
{ order: "0", vector : new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) },
{ order: "1", vector : new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) },
{ order: "p-1 (order 2)", vector : new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) },
{ order: "p (=0, order 4)", vector : new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) },
{ order: "p+1 (=1, order 1)", vector : new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) },
]
};
// "P-256":
var ecSPKI = 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]);

View File

@ -0,0 +1,257 @@
function define_tests_25519() {
return define_tests("X25519");
}
function define_tests_448() {
return define_tests("X448");
}
function define_tests(algorithmName) {
// May want to test prefixed implementations.
var subtle = self.crypto.subtle;
// Verify the derive functions perform checks against the all-zero value results,
// ensuring small-order points are rejected.
// https://www.rfc-editor.org/rfc/rfc7748#section-6.1
// TODO: The spec states that the check must be done on use, but there is discussion about doing it on import.
// https://github.com/WICG/webcrypto-secure-curves/pull/13
{
kSmallOrderPoint[algorithmName].forEach(function(test) {
promise_test(async() => {
let derived;
let privateKey;
let publicKey;
try {
privateKey = await subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveBits", "deriveKey"]);
publicKey = await subtle.importKey("spki", test.vector,
{name: algorithmName},
false, [])
derived = await subtle.deriveKey({name: algorithmName, public: publicKey}, privateKey,
{name: "HMAC", hash: "SHA-256", length: 256}, true,
["sign", "verify"]);
} catch (err) {
assert_false(privateKey === undefined, "Private key should be valid.");
assert_false(publicKey === undefined, "Public key should be valid.");
assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + ".");
}
assert_equals(derived, undefined, "Operation succeeded, but should not have.");
}, algorithmName + " deriveBits checks for all-zero value result with a key of order " + test.order);
});
}
// Ensure the keys generated by each algorithm are valid for key derivation.
{
promise_test(async() => {
let derived;
try {
let key = await subtle.generateKey({name: algorithmName}, true, ["deriveKey", "deriveBits"]);
derived = await subtle.deriveKey({name: algorithmName, public: key.publicKey}, key.privateKey, {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]);
} catch (err) {
assert_unreached("Threw an unexpected error: " + err.toString() + " -");
}
assert_false (derived === undefined, "Key derivation failed.");
}, "Key derivation using a " + algorithmName + " generated keys.");
}
return importKeys(pkcs8, spki, sizes)
.then(function(results) {
publicKeys = results.publicKeys;
privateKeys = results.privateKeys;
noDeriveKeyKeys = results.noDeriveKeyKeys;
ecdhKeys = results.ecdhKeys;
{
// Basic success case
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], {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[algorithmName], 8 * exportedKey.length), "Derived correct key");
}, function(err) {
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " good parameters");
// Case insensitivity check
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], {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[algorithmName], 8 * exportedKey.length), "Derived correct key");
}, function(err) {
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
});
}, algorithmName + " mixed case parameters");
// Errors to test:
// - missing public property TypeError
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName}, privateKeys[algorithmName], {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);
});
}, algorithmName + " missing public property");
// - Non CryptoKey public property TypeError
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], {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);
});
}, algorithmName + " public property of algorithm is not a CryptoKey");
// - wrong algorithm
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: ecdhKeys[algorithmName]}, privateKeys[algorithmName], {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);
});
}, algorithmName + " mismatched algorithms");
// - No deriveKey usage in baseKey InvalidAccessError
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveKeyKeys[algorithmName], {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);
});
}, algorithmName + " no deriveKey usage for base key");
// - Use public key for baseKey InvalidAccessError
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], {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);
});
}, algorithmName + " base key is not a private key");
// - Use private key for public property InvalidAccessError
promise_test(function(test) {
return subtle.deriveKey({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], {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);
});
}, algorithmName + " 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) {
return subtle.deriveKey({name: algorithmName, public: secretKey}, privateKeys[algorithmName], {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);
});
});
}, algorithmName + " public property value is a secret key");
}
});
function importKeys(pkcs8, spki, sizes) {
var privateKeys = {};
var publicKeys = {};
var noDeriveKeyKeys = {};
var ecdhPublicKeys = {};
var promises = [];
{
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveBits", "deriveKey"])
.then(function(key) {
privateKeys[algorithmName] = key;
}, function (err) {
privateKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
{name: algorithmName},
false, ["deriveBits"])
.then(function(key) {
noDeriveKeyKeys[algorithmName] = key;
}, function (err) {
noDeriveKeyKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("spki", spki[algorithmName],
{name: algorithmName},
false, [])
.then(function(key) {
publicKeys[algorithmName] = key;
}, function (err) {
publicKeys[algorithmName] = null;
});
promises.push(operation);
}
{
var operation = subtle.importKey("spki", ecSPKI,
{name: "ECDH", namedCurve: "P-256"},
false, [])
.then(function(key) {
ecdhPublicKeys[algorithmName] = key;
});
}
return Promise.all(promises)
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveKeyKeys: noDeriveKeyKeys, ecdhKeys: ecdhPublicKeys}});
}
// 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;
}
}

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves
// META: script=cfrg_curves_bits_fixtures.js
// META: script=cfrg_curves_keys.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests_25519, 'setup - define tests');

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves
// META: script=cfrg_curves_bits_fixtures.js
// META: script=cfrg_curves_keys.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests_448, 'setup - define tests');

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: deriveKey() Using HKDF and PBKDF2 from an ECDH key
// META: script=derive_key_and_encrypt.js
// META: script=../util/helpers.js
// Test imported from WebKit's source, defined to check the impact of the
// 'Get Key Length' behavior of HKDF and PBKDF2, which should return 'null'
// in both cases, in the 'deriveKey' operation.
// https://bugs.webkit.org/show_bug.cgi?id=282096
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,49 @@
let iv = new Uint8Array(Array(12).keys());
let salt = new Uint8Array(Array(10).keys());
let plaintext = new Uint8Array(Array(100).keys());
function define_tests() {
importKeys().then((keys) => {
// Make sure that ecdh produces the same shared secret and the same encryption results using a key derived from that secret.
keys.forEach(keyData => {
promise_test(async() => {
let hkdfKey = await crypto.subtle.deriveKey({name: "ECDH", public: keyData.publicKey }, keyData.privateKey, { name: "HKDF", hash: "" , salt: new Uint8Array(), info: new Uint8Array() }, false, ["deriveKey"]);
let aesKey = await crypto.subtle.deriveKey({name: "HKDF", hash: "SHA-256", salt: salt, info: plaintext}, hkdfKey, {name:"AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
let result = await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, aesKey, plaintext);
assert_equals(bytesToHexString(result), "a6280c522670eaf82f6564afbeb20a5b3f2d4e13c5596f6df3dcff8c34cb2118d2770fb24d83cfac5079c323118485bb01170292ee41eb82b07208f4840478fea3771d8922785c476ba06c2a0b933fc1661431419530a916ad4468545d1af5004a1149fea241c2ff1582ee58a8b7d79935de5def");
}, "HKDF derivation of a ECDH key " + keyData.test);
promise_test(async() => {
let pkdf2Key = await crypto.subtle.deriveKey({name: "ECDH", public: keyData.publicKey }, keyData.privateKey, { name: "PBKDF2", hash: "" , salt: new Uint8Array(), iterations: 32 }, false, ["deriveKey"]);
let aesKey = await crypto.subtle.deriveKey({name: "PBKDF2", hash: "SHA-256", salt: salt, iterations: 32 }, pkdf2Key, { name:"AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
let result = await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, aesKey, plaintext);
assert_equals(bytesToHexString(result), "c6201dfbb6fa92c1c246f6ce52f8f1c037f087efde41bac7f6485a2a8207623d2d3825b9cbe8ef864a90378667ed25544ce44cd2904bd96c19f0eeb611d626185165a8afb4e52f95700d7880f83939a42712fc4e377f198c01a61b397b76c3a4b93d932c321084bbef33332169dea09458b27df3");
}, "PBKDF2 derivation of a ECDH key " + keyData.test);
});
}, (e) => {
assert_unreached("Setup failed: " + e.message);
});
return Promise.resolve("define_tests");
}
async function importKeys() {
// "ECDSA" with a 'P-256' curve
let keyData = [
hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420fe77a808a7109ba5ceb93ebebad2c84a714d864ad29b62d6537e1969035c0079a144034200042684c752eef1c927a80c74e8b02ce459f848b5977f37fd878b36dae632be9a6cadd56126e404a4f75c535e5769d95b49fb1106f784f3d231b776d1f4d57927ce"),
hexStringToUint8Array("042684c752eef1c927a80c74e8b02ce459f848b5977f37fd878b36dae632be9a6cadd56126e404a4f75c535e5769d95b49fb1106f784f3d231b776d1f4d57927ce"),
hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b020101042067521ccd1f85516118182bca3394c273bab9ce5cd6265105559e325e01f2df1ca144034200043042d8698882f2b59de972390d3fc9277e2e677a6c560148017c9475218fda1b38f76f7645fbcaf3d03e6259d080204fbafb04731b6ad53cb25c3d35d95b7c73"),
hexStringToUint8Array("043042d8698882f2b59de972390d3fc9277e2e677a6c560148017c9475218fda1b38f76f7645fbcaf3d03e6259d080204fbafb04731b6ad53cb25c3d35d95b7c73"),
];
let extractable = true;
var allKeys = await Promise.all([
crypto.subtle.importKey("pkcs8", keyData[0], {name: "ECDH", namedCurve: "P-256"}, extractable, ["deriveKey", 'deriveBits']),
crypto.subtle.importKey("raw", keyData[1], {name: "ECDH", namedCurve: "P-256"}, extractable, []),
crypto.subtle.importKey("pkcs8", keyData[2], {name: "ECDH", namedCurve: "P-256"}, extractable, ["deriveKey", 'deriveBits']),
crypto.subtle.importKey("raw", keyData[3], {name: "ECDH", namedCurve: "P-256"}, extractable, []),
]);
// Test cases defined combining public and private keys of each key-pair.
return [
{ test: 1, publicKey: allKeys[3], privateKey: allKeys[0] },
{ test: 2, publicKey: allKeys[1], privateKey: allKeys[2] }
];
}

View File

@ -0,0 +1,11 @@
// META: title=WebCryptoAPI: deriveBits() tests for the 'length' parameter
// META: script=derived_bits_length.js
// META: script=derived_bits_length_vectors.js
// META: script=derived_bits_length_testcases.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,36 @@
function define_tests() {
// May want to test prefixed implementations.
var subtle = self.crypto.subtle;
Object.keys(testCases).forEach(algorithm => {
let testData = algorithms[algorithm];
testCases[algorithm].forEach(testParam => {
promise_test(async() => {
let derivedBits, privateKey, publicKey;
try {
privateKey = await subtle.importKey(testData.privateKey.format, testData.privateKey.data, testData.importAlg, false, ["deriveBits"]);
if (testData.deriveAlg.public !== undefined) {
publicKey = await subtle.importKey(testData.publicKey.format, testData.publicKey.data, testData.importAlg, false, []);
testData.deriveAlg.public = publicKey;
}
if (testParam.length === "omitted")
derivedBits = await subtle.deriveBits(testData.deriveAlg, privateKey);
else
derivedBits = await subtle.deriveBits(testData.deriveAlg, privateKey, testParam.length);
if (testParam.expected === undefined) {
assert_unreached("deriveBits should have thrown an OperationError exception.");
}
assert_array_equals(new Uint8Array(derivedBits), testParam.expected, "Derived bits do not match the expected result.");
} catch (err) {
if (err instanceof AssertionError || testParam.expected !== undefined) {
throw err;
}
assert_true(privateKey !== undefined, "Key should be valid.");
assert_equals(err.name, "OperationError", "deriveBits correctly threw OperationError: " + err.message);
}
}, algorithm + " derivation with " + testParam.length + " as 'length' parameter");
});
});
return Promise.resolve("define_tests");
}

View File

@ -0,0 +1,38 @@
var testCases = {
"HKDF": [
{length: 256, expected: algorithms["HKDF"].derivation},
{length: 384, expected: algorithms["HKDF"].derivation384},
{length: 230, expected: undefined}, // should throw an exception, not multiple of 8
{length: 0, expected: emptyArray},
{length: null, expected: undefined }, // should throw an exception
{length: undefined, expected: undefined }, // should throw an exception
{length: "omitted", expected: undefined }, // default value is null, so should throw
],
"PBKDF2": [
{length: 256, expected: algorithms["PBKDF2"].derivation},
{length: 384, expected: algorithms["PBKDF2"].derivation384},
{length: 230, expected: undefined}, // should throw an exception, not multiple of 8
{length: 0, expected: emptyArray},
{length: null, expected: undefined }, // should throw an exception
{length: undefined, expected: undefined }, // should throw an exception
{length: "omitted", expected: undefined }, // default value is null, so should throw
],
"ECDH": [
{length: 256, expected: algorithms["ECDH"].derivation},
{length: 384, expected: undefined}, // should throw an exception, bigger than the output size
{length: 230, expected: algorithms["ECDH"].derivation230},
{length: 0, expected: emptyArray},
{length: null, expected: algorithms["ECDH"].derivation},
{length: undefined, expected: algorithms["ECDH"].derivation},
{length: "omitted", expected: algorithms["ECDH"].derivation }, // default value is null
],
"X25519": [
{length: 256, expected: algorithms["X25519"].derivation},
{length: 384, expected: undefined}, // should throw an exception, bigger than the output size
{length: 230, expected: algorithms["X25519"].derivation230},
{length: 0, expected: emptyArray},
{length: null, expected: algorithms["X25519"].derivation},
{length: undefined, expected: algorithms["X25519"].derivation},
{length: "omitted", expected: algorithms["X25519"].derivation }, // default value is null
],
}

View File

@ -0,0 +1,41 @@
const emptyArray = new Uint8Array([]);
const rawKey = 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]);
const salt = 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]);
const info = new Uint8Array([72, 75, 68, 70, 32, 101, 120, 116, 114, 97, 32, 105, 110, 102, 111]);
var algorithms = {
"HKDF": {
importAlg: {name: "HKDF"},
privateKey: {format: "raw", data: rawKey},
deriveAlg: {name: "HKDF", salt: salt, hash: "SHA-256", info: info},
derivation: 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]),
derivation384: 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, 165, 50, 181, 8, 254, 59, 122, 199, 25, 224,146, 248, 105, 105, 75, 84]),
derivation230: undefined,
},
"PBKDF2": {
importAlg: {name: "PBKDF2"},
privateKey: {format: "raw", data: rawKey},
deriveAlg: {name: "PBKDF2", salt: salt, hash: "SHA-256", iterations: 100000},
derivation: 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]),
derivation384: 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, 39, 104, 8, 112, 222, 57, 166, 47, 102, 146, 195, 59, 219, 239, 238, 47]),
derivation230: undefined,
},
"ECDH": {
importAlg: {name: "ECDH", namedCurve: "P-256"},
privateKey: {format: "pkcs8", data: 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])},
publicKey: {format: "spki", data: 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])},
deriveAlg: {name: "ECDH", public: new Uint8Array ([])},
derivation: 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]),
derivation384: undefined,
derivation230: 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, 56]),
},
"X25519": {
importAlg: {name: "X25519"},
privateKey: {format: "pkcs8", data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97])},
publicKey: {format: "spki", data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6])},
deriveAlg: {name: "X25519", public: new Uint8Array ([])},
derivation: new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 161, 149, 0, 8]),
derivation384: undefined,
derivation230: new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 160]),
}
};

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: deriveBits() Using ECDH
// META: script=ecdh_bits.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,266 @@
function define_tests() {
// 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])
};
return 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");
// 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) {
return 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");
});
});
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;
}, function (err) {
privateKeys[namedCurve] = null;
});
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;
}, function (err) {
noDeriveBitsKeys[namedCurve] = null;
});
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;
}, function (err) {
publicKeys[namedCurve] = null;
});
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;
}, function (err) {
ecdsaKeyPairs[namedCurve] = null;
});
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;
}
}

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: deriveKey() Using ECDH
// META: script=ecdh_keys.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,245 @@
function define_tests() {
// 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])
};
return 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) {
return 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");
});
});
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;
}, function (err) {
privateKeys[namedCurve] = null;
});
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;
}, function (err) {
noDeriveKeyKeys[namedCurve] = null;
});
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;
}, function (err) {
publicKeys[namedCurve] = null;
});
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;
}, function (err) {
ecdsaKeyPairs[namedCurve] = null;
});
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;
}
}

View File

@ -0,0 +1,15 @@
// META: title=WebCryptoAPI: deriveBits() and deriveKey() Using HKDF
// META: variant=?1-1000
// META: variant=?1001-2000
// META: variant=?2001-3000
// META: variant=?3001-last
// META: script=/common/subset-tests.js
// META: script=hkdf_vectors.js
// META: script=hkdf.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,295 @@
function define_tests() {
// 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;
return 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], info: infos[infoSize], hash: hashName};
// Check for correct deriveBits result
subsetTest(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
subsetTest(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_unreached("deriveBits failed with error " + err.name + ": " + 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.
subsetTest(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);
subsetTest(promise_test, function(test) {
var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash, info: algorithm.info};
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)
subsetTest(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)
subsetTest(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:
// missing salt (TypeError)
subsetTest(promise_test, function(test) {
return subtle.deriveBits({name: "HKDF", info: infos[infoSize], hash: hashName}, baseKeys[derivedKeySize], 0)
.then(function(derivation) {
assert_equals(derivation.byteLength, 0, "Derived even with missing salt");
}, function(err) {
assert_equals(err.name, "TypeError", "deriveBits missing salt correctly threw OperationError: " + err.message);
});
}, testName + " with missing salt");
// missing info (TypeError)
subsetTest(promise_test, function(test) {
return subtle.deriveBits({name: "HKDF", salt: salts[saltSize], hash: hashName}, baseKeys[derivedKeySize], 0)
.then(function(derivation) {
assert_equals(derivation.byteLength, 0, "Derived even with missing info");
}, function(err) {
assert_equals(err.name, "TypeError", "deriveBits missing info correctly threw OperationError: " + err.message);
});
}, testName + " with missing info");
// length not multiple of 8 (OperationError)
subsetTest(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);
subsetTest(promise_test, function(test) {
var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash, info: algorithm.info};
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)
subsetTest(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)
subsetTest(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];
}
subsetTest(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";
subsetTest(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);
});
});
});
});
});
// 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;
}
}

View File

@ -0,0 +1,184 @@
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([])
};
var infos = {
"normal": new Uint8Array([72, 75, 68, 70, 32, 101, 120, 116, 114, 97, 32, 105, 110, 102, 111]),
"empty": new Uint8Array([])
};
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])
},
"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])
},
"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])
},
"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])
}
},
"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])
},
"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])
},
"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])
},
"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])
}
}
},
"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])
},
"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])
},
"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])
},
"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])
}
},
"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])
},
"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])
},
"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])
},
"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])
}
}
},
"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])
},
"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])
},
"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])
},
"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])
}
},
"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])
},
"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])
},
"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])
},
"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])
}
}
}
};
return {derivedKeys: derivedKeys, salts: salts, derivations: derivations, derivedKeyTypes: derivedKeyTypes, infos: infos};
}

View File

@ -0,0 +1,21 @@
// META: title=WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2
// META: timeout=long
// META: variant=?1-1000
// META: variant=?1001-2000
// META: variant=?2001-3000
// META: variant=?3001-4000
// META: variant=?4001-5000
// META: variant=?5001-6000
// META: variant=?6001-7000
// META: variant=?7001-8000
// META: variant=?8001-last
// META: script=/common/subset-tests.js
// META: script=pbkdf2_vectors.js
// META: script=pbkdf2.js
// Define subtests from a `promise_test` to ensure the harness does not
// complete before the subtests are available. `explicit_done` cannot be used
// for this purpose because the global `done` function is automatically invoked
// by the WPT infrastructure in dedicated worker tests defined using the
// "multi-global" pattern.
promise_test(define_tests, 'setup - define tests');

View File

@ -0,0 +1,291 @@
function define_tests() {
// 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;
return 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
subsetTest(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);
// 0 length
subsetTest(promise_test, function(test) {
return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0)
.then(function(derivation) {
assert_true(equalBuffers(derivation.byteLength, 0, "Derived correctly empty key"));
}, function(err) {
assert_unreached("deriveBits failed with error " + err.name + ": " + 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 " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations";
// Test the particular key derivation.
subsetTest(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);
subsetTest(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)
subsetTest(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)
subsetTest(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");
});
// length not multiple of 8 (OperationError)
subsetTest(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);
subsetTest(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)
subsetTest(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)
subsetTest(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
subsetTest(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";
subsetTest(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";
subsetTest(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";
subsetTest(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);
});
});
});
});
});
// 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;
}
}

View File

@ -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};
}

View File

@ -0,0 +1,166 @@
// META: title=WebCryptoAPI: digest()
// META: timeout=long
var subtle = crypto.subtle; // Change to test prefixed implementations
var sourceData = {
empty: new Uint8Array(0),
short: new Uint8Array([21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255]),
medium: new Uint8Array([182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, 171, 172, 161, 147])
};
sourceData.long = new Uint8Array(1024 * sourceData.medium.byteLength);
for (var i=0; i<1024; i++) {
sourceData.long.set(sourceData.medium, i * sourceData.medium.byteLength);
}
var digestedData = {
"sha-1": {
empty: new Uint8Array([218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]),
short: new Uint8Array([201, 19, 24, 205, 242, 57, 106, 1, 94, 63, 78, 106, 134, 160, 186, 101, 184, 99, 89, 68]),
medium: new Uint8Array([229, 65, 6, 8, 112, 235, 22, 191, 51, 182, 142, 81, 245, 19, 82, 104, 147, 152, 103, 41]),
long: new Uint8Array([48, 152, 181, 0, 55, 236, 208, 46, 189, 101, 118, 83, 178, 191, 160, 30, 238, 39, 162, 234])
},
"sha-256": {
empty: new Uint8Array([227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85]),
short: new Uint8Array([162, 131, 17, 134, 152, 71, 146, 199, 211, 45, 89, 200, 151, 64, 104, 127, 25, 173, 220, 27, 149, 158, 113, 161, 204, 83, 138, 59, 126, 216, 67, 242]),
medium: new Uint8Array([83, 83, 103, 135, 126, 240, 20, 215, 252, 113, 126, 92, 183, 132, 62, 89, 182, 26, 238, 98, 199, 2, 156, 236, 126, 198, 193, 47, 217, 36, 224, 228]),
long: new Uint8Array([20, 205, 234, 157, 199, 95, 90, 98, 116, 217, 252, 30, 100, 0, 153, 18, 241, 220, 211, 6, 180, 143, 232, 233, 207, 18, 45, 230, 113, 87, 23, 129])
},
"sha-384": {
empty: new Uint8Array([56, 176, 96, 167, 81, 172, 150, 56, 76, 217, 50, 126, 177, 177, 227, 106, 33, 253, 183, 17, 20, 190, 7, 67, 76, 12, 199, 191, 99, 246, 225, 218, 39, 78, 222, 191, 231, 111, 101, 251, 213, 26, 210, 241, 72, 152, 185, 91]),
short: new Uint8Array([107, 245, 234, 101, 36, 209, 205, 220, 67, 247, 207, 59, 86, 238, 5, 146, 39, 64, 74, 47, 83, 143, 2, 42, 61, 183, 68, 122, 120, 44, 6, 193, 237, 5, 232, 171, 79, 94, 220, 23, 243, 113, 20, 64, 223, 233, 119, 49]),
medium: new Uint8Array([203, 194, 197, 136, 254, 91, 37, 249, 22, 218, 40, 180, 228, 122, 72, 74, 230, 252, 31, 228, 144, 45, 213, 201, 147, 154, 107, 253, 3, 74, 179, 180, 139, 57, 8, 116, 54, 1, 31, 106, 153, 135, 157, 39, 149, 64, 233, 119]),
long: new Uint8Array([73, 244, 253, 179, 152, 25, 104, 249, 125, 87, 55, 15, 133, 52, 80, 103, 205, 82, 150, 169, 125, 209, 161, 142, 6, 145, 30, 117, 110, 150, 8, 73, 37, 41, 135, 14, 26, 209, 48, 153, 141, 87, 203, 251, 183, 193, 208, 158])
},
"sha-512": {
empty: new Uint8Array([207, 131, 225, 53, 126, 239, 184, 189, 241, 84, 40, 80, 214, 109, 128, 7, 214, 32, 228, 5, 11, 87, 21, 220, 131, 244, 169, 33, 211, 108, 233, 206, 71, 208, 209, 60, 93, 133, 242, 176, 255, 131, 24, 210, 135, 126, 236, 47, 99, 185, 49, 189, 71, 65, 122, 129, 165, 56, 50, 122, 249, 39, 218, 62]),
short: new Uint8Array([55, 82, 72, 190, 95, 243, 75, 231, 76, 171, 79, 241, 195, 188, 141, 198, 139, 213, 248, 223, 244, 2, 62, 152, 248, 123, 134, 92, 255, 44, 114, 66, 146, 223, 24, 148, 67, 166, 79, 244, 19, 74, 101, 205, 70, 53, 185, 212, 245, 220, 13, 63, 182, 117, 40, 0, 42, 99, 172, 242, 108, 157, 165, 117]),
medium: new Uint8Array([185, 16, 159, 131, 158, 142, 164, 60, 137, 15, 41, 60, 225, 29, 198, 226, 121, 141, 30, 36, 49, 241, 228, 185, 25, 227, 178, 12, 79, 54, 48, 59, 163, 156, 145, 109, 179, 6, 196, 90, 59, 101, 118, 31, 245, 190, 133, 50, 142, 234, 244, 44, 56, 48, 241, 217, 94, 122, 65, 22, 91, 125, 45, 54]),
long: new Uint8Array([75, 2, 202, 246, 80, 39, 96, 48, 234, 86, 23, 229, 151, 197, 213, 63, 217, 218, 166, 139, 120, 191, 230, 11, 34, 170, 184, 211, 106, 76, 42, 58, 255, 219, 113, 35, 79, 73, 39, 103, 55, 197, 117, 221, 247, 77, 20, 5, 76, 189, 111, 219, 152, 253, 13, 220, 188, 180, 111, 145, 173, 118, 182, 238])
},
}
// Try every combination of hash with source data size. Variations tested are
// hash name in upper, lower, or mixed case, and upper-case version with the
// source buffer altered after call.
Object.keys(sourceData).forEach(function(size) {
Object.keys(digestedData).forEach(function(alg) {
var upCase = alg.toUpperCase();
var downCase = alg.toLowerCase();
var mixedCase = upCase.substr(0, 1) + downCase.substr(1);
promise_test(function(test) {
var promise = subtle.digest({name: upCase}, sourceData[size])
.then(function(result) {
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
}, function(err) {
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
});
return promise;
}, upCase + " with " + size + " source data");
promise_test(function(test) {
var promise = subtle.digest({name: downCase}, sourceData[size])
.then(function(result) {
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
}, function(err) {
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
});
return promise;
}, downCase + " with " + size + " source data");
promise_test(function(test) {
var promise = subtle.digest({name: mixedCase}, sourceData[size])
.then(function(result) {
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
}, function(err) {
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
});
return promise;
}, mixedCase + " with " + size + " source data");
promise_test(function(test) {
var copiedBuffer = copyBuffer(sourceData[size]);
var promise = subtle.digest({name: upCase}, copiedBuffer)
.then(function(result) {
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
}, function(err) {
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
});
copiedBuffer[0] = 255 - copiedBuffer;
return promise;
}, upCase + " with " + size + " source data and altered buffer after call");
});
});
// Call digest() with bad algorithm names to get an error
var badNames = ["AES-GCM", "RSA-OAEP", "PBKDF2", "AES-KW"];
Object.keys(sourceData).forEach(function(size) {
badNames.forEach(function(badName) {
promise_test(function(test) {
var promise = subtle.digest({name: badName}, sourceData[size])
.then(function(result) {
assert_unreached("digest() should not have worked for " + badName + ":" + size);
}, function(err) {
assert_equals(err.name, "NotSupportedError", "Bad algorithm name should cause NotSupportedError")
});
return promise;
}, badName + " with " + size);
});
});
// Call digest() with empty algorithm object
Object.keys(sourceData).forEach(function(size) {
promise_test(function(test) {
var promise = subtle.digest({}, sourceData[size])
.then(function(result) {
assert_unreached("digest() with missing algorithm name should have thrown a TypeError");
}, function(err) {
assert_equals(err.name, "TypeError", "Missing algorithm name should cause TypeError")
});
return promise;
}, "empty algorithm object with " + size);
});
done();
// 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;
}

View File

@ -0,0 +1,325 @@
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 aes_XXX_vectors.js provides the getTestVectors method
// for the AES-XXX algorithm that drives these tests.
var vectors = getTestVectors();
var passingVectors = vectors.passing;
var failingVectors = vectors.failing;
var decryptionFailingVectors = vectors.decryptionFailing;
// Check for successful encryption.
passingVectors.forEach(function(vector) {
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext)
.then(function(result) {
assert_true(equalBuffers(result, vector.result), "Should return expected result");
}, function(err) {
assert_unreached("encrypt error for test " + vector.name + ": " + err.message);
});
}, vector.name);
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name);
});
all_promises.push(promise);
});
// Check for successful encryption even if the buffer is changed after calling encrypt.
passingVectors.forEach(function(vector) {
var plaintext = copyBuffer(vector.plaintext);
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
var operation = subtle.encrypt(vector.algorithm, vector.key, plaintext)
.then(function(result) {
assert_true(equalBuffers(result, vector.result), "Should return expected result");
}, function(err) {
assert_unreached("encrypt error for test " + vector.name + ": " + err.message);
});
plaintext[0] = 255 - plaintext[0];
return operation;
}, vector.name + " with altered plaintext");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name + " with altered plaintext");
});
all_promises.push(promise);
});
// Check for successful decryption.
passingVectors.forEach(function(vector) {
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.key, vector.result)
.then(function(result) {
assert_true(equalBuffers(result, vector.plaintext), "Should return expected result");
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": " + err.message);
});
}, vector.name + " decryption");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step for decryption: " + vector.name);
});
all_promises.push(promise);
});
// Check for successful decryption even if ciphertext is altered.
passingVectors.forEach(function(vector) {
var ciphertext = copyBuffer(vector.result);
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
var operation = subtle.decrypt(vector.algorithm, vector.key, ciphertext)
.then(function(result) {
assert_true(equalBuffers(result, vector.plaintext), "Should return expected result");
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": " + err.message);
});
ciphertext[0] = 255 - ciphertext[0];
return operation;
}, vector.name + " decryption with altered ciphertext");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step for decryption: " + vector.name + " with altered ciphertext");
});
all_promises.push(promise);
});
// Everything that succeeded should fail if no "encrypt" usage.
passingVectors.forEach(function(vector) {
// Don't want to overwrite key being used for success tests!
var badVector = Object.assign({}, vector);
badVector.key = null;
var promise = importVectorKey(badVector, ["decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext)
.then(function(result) {
assert_unreached("should have thrown exception for test " + vector.name);
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw an InvalidAccessError instead of " + err.message)
});
}, vector.name + " without encrypt usage");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name + " without encrypt usage");
});
all_promises.push(promise);
});
// Encryption should fail if algorithm of key doesn't match algorithm of function call.
passingVectors.forEach(function(vector) {
var algorithm = Object.assign({}, vector.algorithm);
if (algorithm.name === "AES-CBC") {
algorithm.name = "AES-CTR";
algorithm.counter = new Uint8Array(16);
algorithm.length = 64;
} else {
algorithm.name = "AES-CBC";
algorithm.iv = new Uint8Array(16); // Need syntactically valid parameter to get to error being checked.
}
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.encrypt(algorithm, vector.key, vector.plaintext)
.then(function(result) {
assert_unreached("encrypt succeeded despite mismatch " + vector.name + ": " + err.message);
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Mismatch should cause InvalidAccessError instead of " + err.message);
});
}, vector.name + " with mismatched key and algorithm");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name + " with mismatched key and algorithm");
});
all_promises.push(promise);
});
// Everything that succeeded decrypting should fail if no "decrypt" usage.
passingVectors.forEach(function(vector) {
// Don't want to overwrite key being used for success tests!
var badVector = Object.assign({}, vector);
badVector.key = null;
var promise = importVectorKey(badVector, ["encrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.key, vector.result)
.then(function(result) {
assert_unreached("should have thrown exception for test " + vector.name);
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw an InvalidAccessError instead of " + err.message)
});
}, vector.name + " without decrypt usage");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name + " without decrypt usage");
});
all_promises.push(promise);
});
// Check for OperationError due to data lengths.
failingVectors.forEach(function(vector) {
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext)
.then(function(result) {
assert_unreached("should have thrown exception for test " + vector.name);
}, function(err) {
assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message)
});
}, vector.name);
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: " + vector.name);
});
all_promises.push(promise);
});
// Check for OperationError due to data lengths for decryption, too.
failingVectors.forEach(function(vector) {
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.key, vector.result)
.then(function(result) {
assert_unreached("should have thrown exception for test " + vector.name);
}, function(err) {
assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message)
});
}, vector.name + " decryption");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: decryption " + vector.name);
});
all_promises.push(promise);
});
// Check for decryption failing for algorithm-specific reasons (such as bad
// padding for AES-CBC).
decryptionFailingVectors.forEach(function(vector) {
var promise = importVectorKey(vector, ["encrypt", "decrypt"])
.then(function(vector) {
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.key, vector.result)
.then(function(result) {
assert_unreached("should have thrown exception for test " + vector.name);
}, function(err) {
assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message)
});
}, vector.name);
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importKey failed for " + vector.name);
}, "importKey step: decryption " + vector.name);
});
all_promises.push(promise);
});
promise_test(function() {
return Promise.all(all_promises)
.then(function() {done();})
.catch(function() {done();})
}, "setup");
// A test vector has all needed fields for encryption, 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 importVectorKey(vector, usages) {
if (vector.key !== null) {
return new Promise(function(resolve, reject) {
resolve(vector);
});
} else {
return subtle.importKey("raw", vector.keyBuffer, {name: vector.algorithm.name}, false, usages)
.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;
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: encrypt() Using AES-CBC
// META: script=aes_cbc_vectors.js
// META: script=aes.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,261 @@
// aes_cbc_vectors.js
// 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
// keyBuffer - an arrayBuffer with the key data in raw form
// key - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt
// plaintext - the text to encrypt
// result - the expected result (usually just ciphertext, sometimes with added authentication)
function getTestVectors() {
// Before we can really start, we need to fill a bunch of buffers with data
var plaintext = new Uint8Array([84, 104, 105, 115, 32, 115,
112, 101, 99, 105, 102, 105, 99, 97, 116, 105, 111, 110,
32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32,
74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80,
73, 32, 102, 111, 114, 32, 112, 101, 114, 102, 111, 114,
109, 105, 110, 103, 32, 98, 97, 115, 105, 99, 32, 99, 114,
121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32,
111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105,
110, 32, 119, 101, 98, 32, 97, 112, 112, 108, 105, 99, 97,
116, 105, 111, 110, 115, 44, 32, 115, 117, 99, 104, 32, 97,
115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, 115,
105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110,
101, 114, 97, 116, 105, 111, 110, 32, 97, 110, 100, 32,
118, 101, 114, 105, 102, 105, 99, 97, 116, 105, 111, 110,
44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, 112,
116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99,
114, 121, 112, 116, 105, 111, 110, 46, 32, 65, 100, 100,
105, 116, 105, 111, 110, 97, 108, 108, 121, 44, 32, 105,
116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97,
110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112,
108, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111,
32, 103, 101, 110, 101, 114, 97, 116, 101, 32, 97, 110,
100, 47, 111, 114, 32, 109, 97, 110, 97, 103, 101, 32, 116,
104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97,
116, 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115,
115, 97, 114, 121, 32, 116, 111, 32, 112, 101, 114, 102,
111, 114, 109, 32, 116, 104, 101, 115, 101, 32, 111, 112,
101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115,
101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32,
65, 80, 73, 32, 114, 97, 110, 103, 101, 32, 102, 114, 111,
109, 32, 117, 115, 101, 114, 32, 111, 114, 32, 115, 101,
114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, 110,
116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111,
99, 117, 109, 101, 110, 116, 32, 111, 114, 32, 99, 111,
100, 101, 32, 115, 105, 103, 110, 105, 110, 103, 44, 32,
97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, 102,
105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32,
97, 110, 100, 32, 105, 110, 116, 101, 103, 114, 105, 116,
121, 32, 111, 102, 32, 99, 111, 109, 109, 117, 110, 105,
99, 97, 116, 105, 111, 110, 115, 46]);
// We want some random key bytes of various sizes.
// These were randomly generated from a script.
var keyBytes = {
128: new Uint8Array([222, 192, 212, 252, 191, 60, 71,
65, 200, 146, 218, 189, 28, 212, 192, 78]),
192: new Uint8Array([208, 238, 131, 65, 63, 68, 196, 63, 186, 208,
61, 207, 166, 18, 99, 152, 29, 109, 221, 95, 240, 30, 28, 246]),
256: new Uint8Array([103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236,
233, 204, 58, 249, 16, 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116,
216, 0, 11, 191, 48])
}
// AES-CBC needs a 16 byte (128 bit) IV.
var iv = new Uint8Array([85, 170, 248, 155, 168, 148, 19, 213, 78, 167, 39,
167, 108, 39, 162, 132]);
// Results. These were created using the Python cryptography module.
// AES-CBC produces ciphertext
var ciphertext = {
128: new Uint8Array([35, 127, 3, 254, 231, 8, 114, 231, 143, 174, 193,
72, 221, 189, 1, 189, 119, 203, 150, 227, 56, 30, 244, 236, 226, 175,
234, 23, 167, 175, 211, 124, 203, 228, 97, 223, 156, 77, 88, 174,
166, 187, 186, 225, 176, 92, 250, 177, 225, 41, 135, 124, 215, 86,
198, 134, 124, 49, 154, 60, 224, 93, 165, 12, 190, 245, 241, 164,
247, 220, 227, 69, 242, 105, 208, 108, 222, 193, 223, 0, 226, 217,
39, 160, 78, 147, 191, 38, 153, 232, 206, 221, 254, 25, 185, 249, 7,
181, 215, 104, 98, 163, 194, 161, 103, 161, 237, 167, 10, 242, 37,
80, 2, 255, 173, 96, 20, 106, 170, 110, 80, 38, 136, 127, 16, 85,
244, 78, 172, 56, 106, 3, 115, 130, 58, 186, 129, 236, 255, 251,
178, 112, 24, 159, 82, 252, 1, 178, 132, 92, 40, 125, 18, 135, 116,
64, 178, 31, 174, 87, 114, 114, 218, 78, 111, 0, 239, 252, 79, 63,
119, 58, 118, 78, 55, 249, 36, 130, 225, 205, 13, 76, 97, 214, 250,
174, 232, 67, 103, 211, 178, 206, 32, 129, 188, 243, 100, 71, 63,
154, 159, 200, 125, 34, 138, 39, 73, 130, 75, 97, 203, 204, 111,
244, 75, 186, 181, 43, 207, 175, 146, 98, 207, 27, 23, 90, 144, 161,
19, 235, 199, 93, 98, 238, 72, 134, 157, 220, 207, 66, 167, 236, 94,
57, 0, 3, 202, 250, 55, 26, 163, 20, 133, 191, 67, 20, 63, 150, 203,
87, 216, 44, 57, 188, 236, 64, 80, 111, 68, 26, 12, 10, 163, 82, 3,
191, 19, 71, 186, 196, 177, 84, 244, 7, 78, 41, 172, 203, 27, 225,
231, 108, 206, 141, 221, 253, 204, 220, 134, 20, 130, 54, 113, 81,
127, 197, 27, 101, 121, 159, 223, 193, 115, 190, 12, 153, 174, 231,
196, 92, 142, 156, 61, 189, 3, 18, 153, 206, 190, 58, 255, 154, 115,
66, 23, 107, 94, 220, 156, 220, 228, 241, 66, 6, 184, 44, 238, 249,
51, 240, 109, 142, 208, 189, 11, 117, 70, 170, 217, 170, 216, 66,
231, 18, 175, 121, 221, 16, 29, 139, 55, 103, 91, 239, 111, 29, 108,
94, 179, 138, 134, 73, 130, 29, 69, 182, 192, 249, 150, 165, 79, 47,
91, 203, 226, 63, 87, 52, 60, 172, 191, 190, 179, 171, 155, 205, 88,
172, 111, 59, 40, 198, 250, 209, 148, 177, 115, 200, 40, 43, 165,
167, 67, 116, 64, 159, 240, 81, 253, 235, 137, 132, 49, 223, 214,
172, 53, 7, 47, 184, 223, 120, 59, 51, 33, 124, 147, 221, 27, 60,
16, 254, 24, 115, 115, 214, 75, 73, 97, 136, 214, 209, 177, 106, 71,
254, 211, 94, 57, 104, 170, 168, 35, 37, 93, 203, 199, 38, 28, 84]),
192: new Uint8Array([131, 160, 2, 14, 214, 229, 41, 230, 47, 99, 83,
193, 62, 133, 172, 195, 127, 61, 247, 80, 71, 167, 37, 184, 230,
207, 168, 163, 139, 145, 18, 225, 205, 134, 87, 138, 80, 247, 166,
176, 177, 18, 71, 88, 193, 56, 45, 96, 36, 78, 134, 212, 9, 250, 217,
24, 207, 215, 111, 72, 114, 203, 27, 188, 122, 34, 212, 191, 88, 72,
22, 194, 224, 217, 236, 201, 191, 236, 214, 231, 90, 244, 100, 153,
211, 35, 182, 205, 128, 84, 79, 161, 53, 166, 236, 196, 181, 163,
140, 255, 80, 59, 49, 71, 170, 118, 14, 100, 40, 105, 184, 187, 41,
198, 180, 135, 69, 211, 69, 74, 132, 243, 76, 144, 102, 90, 155,
243, 125, 140, 190, 20, 9, 232, 188, 198, 221, 148, 13, 53, 155, 91,
34, 235, 24, 121, 109, 48, 242, 142, 8, 160, 223, 242, 163, 98, 198,
131, 164, 160, 79, 27, 210, 216, 192, 228, 27, 4, 254, 222, 195, 14,
77, 72, 225, 151, 114, 38, 130, 143, 6, 17, 138, 229, 193, 114, 169,
2, 108, 225, 35, 37, 232, 200, 167, 147, 251, 210, 138, 243, 44, 48,
12, 84, 192, 169, 108, 0, 113, 77, 160, 218, 96, 4, 138, 171, 207,
20, 189, 146, 255, 206, 68, 160, 87, 127, 3, 83, 182, 203, 116, 59,
24, 186, 79, 68, 220, 161, 85, 227, 29, 118, 134, 128, 187, 29, 128,
121, 120, 64, 211, 30, 255, 52, 187, 185, 216, 151, 30, 10, 165,
203, 148, 39, 224, 14, 173, 199, 57, 0, 194, 79, 115, 206, 159, 43,
13, 36, 169, 97, 144, 32, 0, 207, 230, 16, 162, 156, 166, 34, 150,
12, 93, 141, 164, 181, 194, 10, 47, 139, 82, 75, 42, 23, 224, 3, 92,
151, 154, 249, 170, 57, 141, 113, 32, 52, 158, 218, 49, 242, 134,
65, 69, 203, 71, 19, 133, 125, 117, 1, 207, 210, 224, 130, 45, 37,
42, 181, 139, 34, 85, 8, 67, 165, 249, 180, 89, 3, 60, 152, 1, 231,
49, 1, 124, 243, 81, 44, 72, 232, 239, 129, 75, 108, 4, 169, 132,
73, 183, 21, 29, 46, 94, 138, 83, 190, 131, 146, 65, 104, 107, 251,
218, 95, 227, 94, 145, 70, 0, 2, 252, 59, 188, 58, 150, 203, 148,
100, 219, 36, 182, 81, 237, 138, 160, 83, 151, 119, 11, 216, 122,
134, 189, 246, 251, 192, 41, 158, 125, 247, 190, 32, 173, 104, 9,
58, 223, 97, 212, 48, 62, 3, 112, 21, 74, 206, 87, 182, 110, 197,
67, 68, 155, 189, 223, 136, 2, 239, 137, 151, 138, 252, 162, 141,
255, 209, 25, 4, 146, 24, 221, 43, 148, 120, 26, 228, 208, 200, 198,
192, 4, 96, 70, 227, 237, 104, 17, 67, 9, 211]),
256: new Uint8Array([41, 213, 121, 140, 181, 227, 200, 97, 100, 133, 58,
227, 106, 115, 25, 63, 77, 51, 26, 57, 238, 140, 99, 63, 71, 211,
128, 84, 115, 26, 236, 52, 103, 81, 145, 14, 101, 161, 181, 58, 135,
193, 56, 167, 214, 220, 5, 52, 85, 222, 183, 27, 101, 134, 86, 155,
64, 148, 124, 212, 219, 251, 65, 42, 32, 44, 128, 2, 50, 128, 221,
22, 238, 56, 189, 83, 28, 122, 121, 157, 215, 135, 151, 128, 233,
193, 65, 190, 86, 148, 191, 140, 196, 120, 8, 172, 100, 166, 254,
41, 245, 75, 56, 6, 166, 244, 178, 111, 234, 23, 4, 107, 6, 22, 132,
187, 230, 17, 71, 172, 113, 238, 73, 4, 180, 90, 103, 77, 37, 51,
118, 112, 129, 238, 199, 7, 222, 122, 173, 30, 232, 178, 233, 234,
144, 98, 14, 234, 112, 77, 68, 62, 62, 159, 230, 101, 98, 43, 2,
204, 69, 156, 86, 104, 128, 34, 128, 7, 173, 90, 120, 33, 104, 59,
45, 251, 93, 51, 240, 232, 60, 94, 189, 134, 90, 20, 184, 122, 29,
225, 85, 213, 38, 116, 159, 80, 69, 106, 168, 236, 201, 69, 140, 98,
240, 45, 160, 133, 225, 106, 45, 245, 212, 160, 176, 128, 27, 114,
153, 182, 144, 145, 214, 72, 196, 138, 183, 87, 61, 245, 150, 56,
82, 158, 224, 50, 114, 125, 122, 172, 161, 129, 234, 70, 63, 245,
136, 30, 136, 9, 128, 220, 229, 157, 222, 195, 149, 189, 70, 8, 71,
40, 195, 93, 27, 7, 234, 164, 175, 102, 201, 149, 115, 248, 179,
125, 66, 122, 194, 26, 61, 218, 198, 181, 152, 140, 199, 48, 148,
31, 14, 241, 197, 3, 70, 128, 239, 32, 86, 15, 215, 86, 245, 190,
95, 141, 41, 111, 0, 232, 28, 152, 67, 87, 197, 255, 118, 13, 251,
71, 84, 22, 231, 134, 188, 175, 115, 138, 37, 199, 5, 238, 199, 2,
99, 203, 75, 62, 231, 21, 150, 239, 94, 201, 185, 219, 58, 210, 228,
151, 131, 76, 148, 104, 60, 74, 82, 6, 168, 49, 251, 182, 3, 232,
173, 210, 201, 19, 101, 166, 7, 94, 11, 194, 211, 146, 229, 75, 241,
15, 50, 187, 36, 175, 78, 227, 98, 224, 3, 95, 209, 93, 126, 112,
178, 29, 18, 108, 241, 232, 79, 210, 41, 2, 238, 208, 190, 171, 134,
147, 188, 191, 229, 122, 32, 209, 166, 118, 129, 223, 130, 214, 195,
89, 67, 94, 218, 155, 185, 0, 144, 255, 132, 213, 25, 59, 83, 242,
57, 69, 148, 109, 133, 61, 163, 30, 214, 254, 54, 169, 3, 217, 77,
66, 123, 193, 204, 199, 109, 123, 49, 186, 223, 229, 8, 230, 164,
171, 196, 145, 225, 10, 111, 248, 111, 164, 216, 54, 225, 253])
};
// Replace the last block of each ciphertext with bad padding below for decryption errors
var badPadding = {
128: {
"zeroPadChar": new Uint8Array([238, 27, 248, 169, 218, 138, 164, 86, 207, 102, 36, 223, 6, 166, 77, 14]),
"bigPadChar": new Uint8Array([91, 67, 119, 104, 252, 238, 175, 144, 17, 75, 12, 163, 212, 52, 46, 51]),
"inconsistentPadChars": new Uint8Array([135, 101, 112, 208, 3, 106, 226, 20, 25, 219, 79, 94, 58, 212, 242, 192])
},
192: {
"zeroPadChar": new Uint8Array([22, 158, 50, 15, 168, 47, 19, 194, 182, 133, 184, 65, 36, 43, 177, 254]),
"bigPadChar": new Uint8Array([207, 110, 28, 160, 165, 213, 48, 213, 163, 242, 15, 78, 96, 117, 106, 87]),
"inconsistentPadChars": new Uint8Array([143, 227, 12, 112, 216, 207, 136, 167, 78, 137, 93, 30, 50, 75, 102, 101])
},
256: {
"zeroPadChar": new Uint8Array([1, 253, 141, 214, 30, 193, 254, 68, 140, 200, 157, 110, 200, 89, 177, 129]),
"bigPadChar": new Uint8Array([88, 7, 110, 221, 74, 34, 97, 109, 99, 25, 189, 222, 94, 90, 27, 60]),
"inconsistentPadChars": new Uint8Array([152, 54, 60, 148, 59, 136, 193, 21, 77, 140, 170, 67, 120, 74, 106, 62])
}
};
var keyLengths = [128, 192, 256];
// All the scenarios that should succeed, if the key has "encrypt" usage
var passing = [];
keyLengths.forEach(function(keyLength) {
passing.push({
name: "AES-CBC " + keyLength.toString() + "-bit key",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CBC", iv: iv},
plaintext: plaintext,
result: ciphertext[keyLength]
});
});
// Scenarios that should fail because of a bad iv length, causing an OperationError
var failing = [];
keyLengths.forEach(function(keyLength) {
var shortIv = iv.slice(0, 8);
failing.push({
name: "AES-CBC " + keyLength.toString() + "-bit key, 64-bit IV",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CBC", iv: shortIv},
plaintext: plaintext,
result: ciphertext[keyLength]
});
var longIv = new Uint8Array(24);
longIv.set(iv, 0);
longIv.set(iv.slice(0, 8), 16);
failing.push({
name: "AES-CBC " + keyLength.toString() + "-bit key, 192-bit IV",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CBC", iv: longIv},
plaintext: plaintext,
result: ciphertext[keyLength]
});
});
// Scenarios that should fail decryption because of bad padding
var decryptionFailing = [];
keyLengths.forEach(function(keyLength) {
["zeroPadChar", "bigPadChar", "inconsistentPadChars"].forEach(function(paddingProblem) {
var badCiphertext = new Uint8Array(ciphertext[keyLength].byteLength);
badCiphertext.set(ciphertext[keyLength].slice(0, ciphertext[keyLength].byteLength - 16));
badCiphertext.set(badPadding[keyLength][paddingProblem]);
decryptionFailing.push({
name: "AES-CBC " + keyLength.toString() + "-bit key, " + paddingProblem,
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CBC", iv: iv},
plaintext: plaintext,
result: badCiphertext
});
});
});
return {passing: passing, failing: failing, decryptionFailing: decryptionFailing};
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: encrypt() Using AES-CTR
// META: script=aes_ctr_vectors.js
// META: script=aes.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,123 @@
// aes_ctr_vectors.js
// 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
// keyBuffer - an arrayBuffer with the key data in raw form
// key - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt
// plaintext - the text to encrypt
// result - the expected result (usually just ciphertext, sometimes with added authentication)
function getTestVectors() {
// Before we can really start, we need to fill a bunch of buffers with data
var plaintext = new Uint8Array([84, 104, 105, 115, 32, 115,
112, 101, 99, 105, 102, 105, 99, 97, 116, 105, 111, 110,
32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32,
74, 97, 118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80,
73, 32, 102, 111, 114, 32, 112, 101, 114, 102, 111, 114,
109, 105, 110, 103, 32, 98, 97, 115, 105, 99, 32, 99, 114,
121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32,
111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105,
110, 32, 119, 101, 98, 32, 97, 112, 112, 108, 105, 99, 97,
116, 105, 111, 110, 115, 44, 32, 115, 117, 99, 104, 32, 97,
115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32, 115,
105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110,
101, 114, 97, 116, 105, 111, 110, 32, 97, 110, 100, 32,
118, 101, 114, 105, 102, 105, 99, 97, 116, 105, 111, 110,
44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121, 112,
116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99,
114, 121, 112, 116, 105, 111, 110, 46, 32, 65, 100, 100,
105, 116, 105, 111, 110, 97, 108, 108, 121, 44, 32, 105,
116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97,
110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112,
108, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111,
32, 103, 101, 110, 101, 114, 97, 116, 101, 32, 97, 110,
100, 47, 111, 114, 32, 109, 97, 110, 97, 103, 101, 32, 116,
104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97,
116, 101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115,
115, 97, 114, 121, 32, 116, 111, 32, 112, 101, 114, 102,
111, 114, 109, 32, 116, 104, 101, 115, 101, 32, 111, 112,
101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115,
101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32,
65, 80, 73, 32, 114, 97, 110, 103, 101, 32, 102, 114, 111,
109, 32, 117, 115, 101, 114, 32, 111, 114, 32, 115, 101,
114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101, 110,
116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111,
99, 117, 109, 101, 110, 116, 32, 111, 114, 32, 99, 111,
100, 101, 32, 115, 105, 103, 110, 105, 110, 103, 44, 32,
97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110, 102,
105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32,
97, 110, 100, 32, 105, 110, 116, 101, 103, 114, 105, 116,
121, 32, 111, 102, 32, 99, 111, 109, 109, 117, 110, 105,
99, 97, 116, 105, 111, 110, 115, 46]);
// We want some random key bytes of various sizes.
// These were randomly generated from a script.
var keyBytes = {
128: new Uint8Array([222, 192, 212, 252, 191, 60, 71,
65, 200, 146, 218, 189, 28, 212, 192, 78]),
192: new Uint8Array([208, 238, 131, 65, 63, 68, 196, 63, 186, 208,
61, 207, 166, 18, 99, 152, 29, 109, 221, 95, 240, 30, 28, 246]),
256: new Uint8Array([103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236,
233, 204, 58, 249, 16, 229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116,
216, 0, 11, 191, 48])
}
// AES-CTR needs a 16 byte (128 bit) counter.
var counter = new Uint8Array([85, 170, 248, 155, 168, 148, 19, 213, 78, 167, 39,
167, 108, 39, 162, 132]);
// Results. These were created using the Python cryptography module.
// AES-CTR produces ciphertext
var ciphertext = {
128: new Uint8Array([233, 17, 117, 253, 164, 245, 234, 87, 197, 43, 13, 0, 11, 190, 152, 175, 104, 192, 165, 144, 88, 174, 237, 138, 181, 183, 6, 53, 3, 161, 206, 71, 13, 121, 218, 209, 116, 249, 10, 170, 250, 165, 68, 157, 132, 141, 200, 178, 197, 87, 209, 231, 250, 75, 154, 65, 162, 251, 30, 159, 234, 20, 20, 181, 147, 218, 180, 12, 4, 241, 75, 79, 129, 64, 15, 228, 60, 147, 153, 1, 129, 176, 150, 161, 85, 97, 22, 154, 234, 23, 127, 16, 4, 22, 226, 11, 104, 16, 176, 14, 225, 176, 79, 239, 103, 243, 190, 222, 40, 186, 244, 212, 29, 57, 125, 175, 21, 17, 233, 2, 13, 119, 102, 233, 230, 4, 16, 222, 56, 225, 67, 45, 191, 250, 15, 153, 45, 193, 240, 212, 117, 101, 68, 232, 199, 101, 175, 125, 247, 6, 249, 14, 0, 157, 185, 56, 76, 51, 228, 77, 234, 84, 60, 42, 119, 187, 213, 32, 34, 222, 65, 231, 215, 26, 73, 141, 231, 254, 185, 118, 14, 180, 126, 80, 51, 102, 200, 141, 204, 45, 26, 56, 119, 136, 222, 45, 143, 120, 231, 44, 43, 221, 136, 21, 188, 138, 84, 232, 208, 238, 226, 117, 104, 60, 165, 4, 18, 144, 240, 49, 173, 90, 68, 84, 239, 161, 124, 196, 144, 119, 24, 243, 239, 75, 117, 254, 219, 209, 53, 131, 37, 79, 68, 26, 21, 168, 163, 50, 59, 18, 244, 11, 143, 190, 188, 129, 108, 249, 180, 104, 216, 215, 165, 160, 251, 84, 132, 152, 195, 154, 110, 216, 70, 21, 248, 148, 146, 152, 56, 174, 248, 227, 1, 102, 15, 118, 182, 50, 73, 63, 35, 112, 159, 237, 253, 94, 16, 127, 120, 38, 127, 51, 27, 96, 163, 140, 20, 111, 151, 16, 72, 74, 74, 205, 239, 241, 16, 179, 183, 116, 95, 248, 58, 168, 203, 93, 233, 225, 91, 17, 226, 10, 120, 85, 114, 4, 31, 40, 82, 161, 152, 17, 86, 237, 207, 7, 228, 110, 182, 65, 68, 68, 156, 206, 116, 185, 204, 148, 22, 58, 111, 218, 138, 225, 146, 25, 114, 29, 96, 183, 87, 181, 181, 236, 113, 141, 171, 213, 9, 84, 182, 230, 163, 147, 246, 86, 246, 52, 111, 64, 34, 157, 12, 80, 224, 28, 21, 112, 31, 42, 79, 229, 210, 90, 23, 78, 223, 155, 144, 238, 12, 14, 191, 158, 6, 181, 254, 0, 85, 134, 56, 161, 234, 55, 129, 64, 59, 12, 146, 6, 217, 232, 20, 214, 167, 159, 183, 165, 96, 96, 225, 199, 23, 106, 243, 108, 106, 26, 214, 53, 152, 26, 155, 253, 128, 7, 216, 207, 109, 159, 147, 240, 232, 226, 43, 147, 169, 162, 204, 215, 9, 10, 177, 223, 99, 206, 163, 240, 64]),
192: new Uint8Array([98, 123, 235, 65, 14, 86, 80, 133, 88, 104, 244, 125, 165, 185, 163, 4, 3, 230, 62, 58, 113, 222, 46, 210, 17, 155, 95, 19, 125, 125, 70, 234, 105, 54, 23, 246, 114, 9, 237, 191, 9, 194, 34, 254, 156, 11, 50, 216, 80, 178, 185, 221, 132, 154, 27, 85, 82, 49, 241, 123, 23, 106, 119, 134, 203, 0, 151, 66, 149, 218, 124, 247, 227, 233, 236, 184, 88, 234, 174, 250, 83, 168, 33, 15, 122, 26, 96, 213, 210, 4, 52, 92, 20, 12, 64, 12, 209, 197, 69, 100, 15, 56, 60, 63, 241, 52, 18, 189, 93, 146, 47, 60, 33, 200, 218, 243, 43, 169, 17, 108, 19, 199, 174, 33, 107, 186, 57, 95, 167, 138, 180, 187, 53, 113, 208, 148, 190, 48, 167, 53, 209, 52, 153, 184, 231, 63, 168, 54, 179, 238, 93, 130, 125, 3, 149, 119, 60, 25, 142, 150, 183, 193, 29, 18, 3, 219, 235, 219, 26, 116, 217, 196, 108, 6, 96, 103, 212, 48, 227, 91, 124, 77, 181, 169, 18, 111, 123, 83, 26, 169, 230, 88, 103, 185, 153, 93, 143, 152, 142, 231, 41, 226, 226, 156, 179, 206, 212, 67, 18, 193, 187, 53, 252, 214, 15, 228, 246, 131, 170, 101, 134, 212, 100, 170, 146, 47, 57, 125, 50, 230, 51, 246, 74, 175, 129, 196, 178, 206, 176, 52, 153, 39, 77, 24, 186, 99, 137, 83, 105, 111, 168, 35, 176, 24, 29, 170, 223, 74, 160, 138, 247, 12, 102, 233, 136, 59, 172, 228, 242, 84, 13, 34, 155, 80, 80, 87, 180, 143, 129, 61, 213, 54, 41, 8, 183, 102, 126, 179, 127, 77, 55, 176, 152, 41, 131, 85, 86, 225, 87, 216, 139, 226, 196, 195, 210, 34, 33, 161, 249, 153, 205, 197, 128, 41, 28, 121, 6, 159, 25, 211, 168, 137, 26, 217, 249, 113, 81, 141, 18, 1, 250, 228, 68, 238, 74, 54, 99, 167, 236, 176, 199, 148, 161, 143, 156, 51, 189, 204, 59, 240, 151, 170, 85, 63, 23, 38, 152, 199, 12, 81, 217, 244, 178, 231, 249, 159, 224, 107, 214, 58, 127, 116, 143, 219, 155, 80, 55, 213, 171, 80, 127, 235, 20, 247, 12, 104, 228, 147, 202, 124, 143, 110, 223, 76, 221, 154, 175, 143, 185, 237, 222, 189, 104, 218, 72, 244, 55, 253, 138, 183, 92, 231, 68, 176, 239, 171, 100, 10, 63, 61, 194, 228, 15, 133, 216, 45, 60, 135, 203, 142, 127, 153, 172, 223, 213, 230, 220, 189, 223, 234, 156, 134, 238, 220, 251, 104, 209, 117, 175, 47, 46, 148, 6, 61, 216, 215, 39, 30, 116, 212, 45, 112, 202, 227, 198, 98, 253, 97, 177, 120, 74, 238, 68, 99, 240, 96, 43, 88, 166]),
256: new Uint8Array([55, 82, 154, 67, 47, 80, 186, 78, 83, 56, 95, 130, 102, 236, 61, 236, 204, 236, 234, 222, 122, 226, 147, 149, 233, 41, 16, 118, 201, 91, 185, 162, 79, 71, 146, 252, 221, 110, 165, 137, 75, 129, 94, 219, 93, 94, 64, 34, 250, 190, 5, 90, 6, 177, 167, 224, 25, 121, 85, 91, 87, 152, 56, 100, 191, 35, 1, 156, 177, 179, 127, 253, 173, 176, 87, 247, 40, 207, 178, 175, 10, 51, 209, 70, 52, 76, 251, 160, 172, 203, 77, 191, 97, 58, 123, 238, 82, 60, 166, 214, 134, 14, 71, 74, 156, 15, 77, 6, 141, 76, 10, 205, 148, 204, 85, 203, 242, 30, 66, 133, 202, 21, 17, 108, 151, 2, 15, 44, 51, 180, 88, 80, 8, 248, 254, 151, 201, 226, 156, 6, 39, 197, 212, 124, 72, 217, 75, 232, 139, 155, 22, 199, 242, 223, 116, 10, 141, 42, 7, 85, 99, 5, 184, 43, 145, 159, 122, 135, 202, 46, 209, 157, 178, 114, 98, 194, 119, 194, 19, 242, 167, 236, 162, 94, 90, 106, 219, 234, 67, 11, 162, 225, 6, 17, 152, 23, 16, 84, 40, 90, 255, 158, 8, 105, 198, 56, 220, 213, 36, 203, 241, 242, 85, 218, 103, 90, 202, 214, 215, 134, 121, 169, 149, 139, 122, 143, 155, 178, 29, 217, 197, 128, 173, 25, 111, 154, 14, 76, 106, 101, 0, 215, 187, 33, 223, 116, 205, 89, 52, 206, 60, 77, 141, 31, 57, 211, 74, 42, 219, 88, 210, 36, 196, 128, 151, 136, 124, 222, 157, 59, 225, 70, 163, 234, 59, 173, 228, 198, 134, 76, 249, 228, 69, 181, 196, 194, 179, 239, 78, 43, 143, 94, 234, 10, 177, 192, 185, 171, 231, 164, 254, 91, 44, 11, 29, 148, 223, 107, 18, 149, 61, 50, 115, 38, 14, 128, 189, 9, 77, 236, 151, 163, 23, 122, 156, 236, 11, 80, 66, 190, 24, 4, 4, 12, 148, 57, 64, 59, 143, 114, 247, 66, 111, 167, 86, 173, 98, 102, 207, 44, 134, 89, 231, 64, 50, 157, 208, 210, 79, 159, 133, 73, 118, 98, 202, 215, 57, 247, 29, 97, 116, 1, 28, 119, 248, 243, 31, 180, 66, 38, 40, 141, 251, 134, 129, 126, 241, 113, 22, 50, 28, 113, 187, 158, 217, 125, 182, 233, 144, 246, 32, 88, 88, 15, 0, 102, 131, 67, 31, 34, 150, 98, 241, 213, 227, 205, 175, 254, 3, 53, 70, 124, 167, 38, 53, 104, 140, 147, 158, 200, 179, 45, 100, 101, 246, 81, 166, 53, 247, 60, 10, 78, 127, 10, 173, 176, 232, 31, 91, 203, 250, 236, 38, 113, 172, 151, 253, 194, 253, 50, 242, 76, 148, 23, 117, 195, 122, 104, 16, 212, 177, 113, 188, 138, 186, 144, 168, 102, 3])
};
var keyLengths = [128, 192, 256];
// All the scenarios that should succeed, if the key has "encrypt" usage
var passing = [];
keyLengths.forEach(function(keyLength) {
passing.push({
name: "AES-CTR " + keyLength.toString() + "-bit key",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CTR", counter: counter, length: 64},
plaintext: plaintext,
result: ciphertext[keyLength]
});
});
// Scenarios that should fail because of a bad length parameter, causing an OperationError
var failing = [];
keyLengths.forEach(function(keyLength) {
failing.push({
name: "AES-CTR " + keyLength.toString() + "-bit key, 0-bit counter",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CTR", counter: counter, length: 0},
plaintext: plaintext,
result: ciphertext[keyLength]
});
failing.push({
name: "AES-CTR " + keyLength.toString() + "-bit key, 129-bit counter",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-CTR", counter: counter, length: 129},
plaintext: plaintext,
result: ciphertext[keyLength]
});
});
return {passing: passing, failing: failing, decryptionFailing: []};
}

View File

@ -0,0 +1,7 @@
// META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 96-bit iv
// META: script=aes_gcm_96_iv_fixtures.js
// META: script=aes_gcm_vectors.js
// META: script=aes.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,7 @@
// META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 256-bit iv
// META: script=aes_gcm_256_iv_fixtures.js
// META: script=aes_gcm_vectors.js
// META: script=aes.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,210 @@
function getFixtures() {
// Before we can really start, we need to fill a bunch of buffers with data
var plaintext = new Uint8Array([
84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105,
111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97,
118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32,
112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99,
32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111,
112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98,
32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115,
117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32,
115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97,
116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99,
97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121,
112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112,
116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108,
108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115,
32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105,
99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114,
97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103,
101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116,
101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32,
116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115,
101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115,
101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32,
114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32,
111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101,
110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109,
101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110,
105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110,
102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100,
32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111,
109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46,
]);
// We want some random key bytes of various sizes.
// These were randomly generated from a script.
var keyBytes = {
128: new Uint8Array([
222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78,
]),
192: new Uint8Array([
208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152,
29, 109, 221, 95, 240, 30, 28, 246,
]),
256: new Uint8Array([
103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16,
229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48,
]),
};
// AES-GCM needs an IV of no more than 2^64 - 1 bytes. Arbitrary 32 bytes is okay then.
var iv = new Uint8Array([
58, 146, 115, 42, 166, 234, 57, 191, 57, 134, 224, 199, 63, 169, 32, 0, 32,
33, 117, 56, 94, 248, 173, 234, 194, 200, 115, 53, 235, 146, 141, 212,
]);
// Authenticated encryption via AES-GCM requires additional data that
// will be checked. We use the ASCII encoded Editorial Note
// following the Abstract of the Web Cryptography API recommendation.
var additionalData = new Uint8Array([
84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116,
104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111,
116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109,
101, 110, 116, 46,
]);
// The length of the tag defaults to 16 bytes (128 bit).
var tag = {
128: new Uint8Array([
194, 226, 198, 253, 239, 28, 197, 240, 123, 216, 176, 151, 239, 200, 184,
183,
]),
192: new Uint8Array([
183, 57, 32, 144, 164, 76, 121, 77, 58, 86, 62, 132, 53, 130, 96, 225,
]),
256: new Uint8Array([
188, 239, 241, 48, 159, 21, 213, 0, 241, 42, 85, 76, 194, 28, 49, 60,
]),
};
var tag_with_empty_ad = {
128: new Uint8Array([
222, 51, 11, 23, 36, 222, 250, 248, 27, 98, 30, 81, 150, 35, 220, 198,
]),
192: new Uint8Array([
243, 11, 130, 112, 169, 239, 114, 238, 185, 219, 93, 1, 95, 108, 184, 183,
]),
256: new Uint8Array([
244, 186, 86, 203, 154, 37, 191, 248, 246, 57, 139, 130, 224, 47, 217,
238,
]),
};
// Results. These were created using the Python cryptography module.
// AES-GCM produces ciphertext and a tag.
var ciphertext = {
128: new Uint8Array([
180, 241, 40, 183, 105, 52, 147, 238, 224, 175, 175, 236, 168, 244, 241,
121, 9, 202, 225, 237, 56, 216, 253, 254, 186, 102, 111, 207, 228, 190,
130, 177, 159, 246, 6, 53, 249, 113, 228, 254, 81, 126, 253, 191, 100, 43,
251, 147, 107, 91, 166, 231, 201, 241, 180, 214, 112, 47, 123, 164, 186,
134, 54, 65, 22, 181, 201, 82, 236, 59, 52, 139, 172, 39, 41, 89, 123, 62,
102, 167, 82, 150, 250, 93, 96, 169, 135, 89, 245, 255, 164, 192, 169,
159, 25, 16, 139, 145, 76, 4, 144, 131, 148, 197, 204, 46, 23, 110, 193,
228, 127, 120, 242, 24, 54, 240, 181, 162, 98, 244, 249, 68, 134, 122,
126, 151, 38, 108, 116, 68, 150, 109, 38, 194, 21, 159, 140, 205, 183, 35,
97, 151, 186, 120, 145, 22, 235, 22, 210, 223, 187, 143, 162, 183, 93,
196, 104, 51, 96, 53, 234, 250, 184, 76, 237, 157, 37, 203, 226, 87, 222,
75, 240, 95, 218, 222, 64, 81, 165, 75, 201, 216, 190, 13, 116, 217, 69,
66, 47, 161, 68, 247, 74, 253, 157, 181, 162, 121, 53, 32, 91, 124, 230,
105, 224, 17, 187, 50, 61, 77, 103, 79, 71, 57, 163, 116, 234, 149, 27,
105, 24, 31, 159, 3, 128, 130, 42, 94, 125, 200, 142, 251, 148, 201, 17,
149, 232, 84, 50, 17, 18, 203, 186, 226, 164, 227, 202, 76, 65, 16, 163,
224, 132, 52, 31, 101, 129, 72, 171, 159, 42, 177, 253, 98, 86, 201, 95,
117, 62, 12, 205, 78, 36, 126, 196, 121, 89, 185, 37, 161, 66, 181, 117,
186, 71, 124, 132, 110, 120, 27, 246, 163, 18, 13, 90, 200, 127, 82, 209,
241, 170, 73, 247, 137, 96, 244, 254, 251, 119, 71, 156, 27, 107, 53, 33,
45, 22, 0, 144, 48, 32, 11, 116, 21, 125, 246, 217, 171, 158, 224, 142,
234, 141, 242, 168, 89, 154, 66, 227, 161, 182, 96, 1, 88, 78, 12, 7, 239,
30, 206, 31, 89, 111, 107, 42, 37, 241, 148, 232, 1, 8, 251, 117, 146,
183, 9, 48, 39, 94, 59, 70, 230, 26, 165, 97, 156, 140, 141, 31, 62, 10,
206, 55, 48, 207, 0, 197, 202, 197, 108, 133, 175, 80, 4, 16, 154, 223,
255, 4, 196, 188, 178, 240, 29, 13, 120, 5, 225, 202, 3, 35, 225, 158, 92,
152, 73, 205, 107, 157, 224, 245, 99, 194, 171, 156, 245, 247, 183, 165,
40, 62, 200, 110, 29, 151, 206, 100, 175, 88, 36, 242, 90, 4, 82, 73, 250,
140, 245, 217, 9, 153, 35, 242, 206, 78, 197, 121, 115, 15, 80, 128, 101,
191, 240, 91, 151, 249, 62, 62, 244, 18, 3, 17, 135, 222, 210, 93, 149,
123,
]),
192: new Uint8Array([
126, 160, 166, 112, 227, 212, 106, 186, 175, 70, 24, 28, 86, 149, 31, 154,
156, 190, 244, 132, 44, 61, 149, 242, 105, 67, 17, 136, 7, 146, 153, 170,
200, 214, 142, 205, 170, 225, 85, 44, 241, 159, 255, 234, 10, 13, 37, 48,
255, 21, 141, 176, 60, 117, 73, 130, 247, 204, 144, 102, 167, 89, 203,
235, 229, 129, 122, 253, 124, 179, 115, 118, 163, 157, 67, 141, 122, 146,
209, 11, 112, 5, 230, 117, 123, 184, 243, 99, 83, 10, 31, 166, 96, 1, 121,
44, 10, 241, 24, 43, 184, 187, 25, 239, 246, 176, 108, 230, 127, 25, 42,
67, 202, 140, 179, 104, 159, 75, 103, 43, 248, 98, 166, 179, 67, 0, 163,
227, 84, 40, 129, 227, 198, 205, 7, 156, 16, 185, 24, 166, 59, 218, 197,
114, 74, 34, 126, 22, 226, 226, 85, 212, 69, 83, 163, 185, 68, 109, 182,
54, 209, 237, 96, 184, 32, 53, 127, 175, 13, 146, 141, 115, 164, 184, 98,
245, 174, 223, 46, 32, 167, 39, 103, 19, 210, 80, 131, 254, 103, 249, 247,
29, 120, 31, 105, 241, 103, 169, 249, 93, 153, 74, 56, 53, 239, 157, 132,
236, 169, 246, 242, 24, 113, 97, 128, 238, 152, 148, 31, 84, 8, 52, 105,
198, 116, 103, 132, 48, 199, 23, 90, 24, 29, 63, 41, 117, 191, 57, 31,
209, 128, 60, 119, 175, 84, 141, 177, 165, 169, 195, 35, 163, 105, 146,
157, 209, 93, 149, 105, 160, 93, 231, 78, 201, 92, 235, 200, 89, 37, 50,
181, 30, 213, 242, 59, 156, 219, 19, 158, 17, 224, 81, 108, 52, 87, 248,
101, 23, 39, 107, 67, 151, 103, 230, 126, 202, 184, 118, 226, 18, 29, 93,
37, 208, 40, 82, 113, 35, 157, 145, 152, 50, 253, 140, 47, 141, 192, 1,
148, 114, 40, 10, 112, 79, 227, 16, 105, 247, 31, 49, 102, 195, 75, 183,
172, 254, 188, 42, 89, 77, 38, 104, 1, 180, 106, 61, 71, 70, 35, 160, 103,
101, 244, 26, 226, 37, 159, 155, 4, 107, 222, 219, 136, 37, 24, 246, 44,
23, 44, 248, 132, 108, 59, 179, 99, 145, 132, 82, 53, 203, 111, 150, 55,
123, 51, 214, 165, 108, 124, 179, 131, 174, 139, 224, 114, 96, 218, 181,
243, 128, 198, 98, 115, 92, 95, 165, 23, 229, 108, 146, 14, 244, 162, 37,
85, 201, 33, 44, 92, 106, 112, 185, 16, 189, 42, 114, 109, 59, 124, 131,
16, 211, 31, 97, 29, 135, 61, 150, 75, 250, 207, 129, 38, 205, 187, 186,
55, 207, 232, 24, 48, 232, 49, 226, 16, 12, 27, 70, 31, 124, 128, 218,
100, 91, 200, 184, 78, 252, 100, 235, 62, 43, 69, 214, 163, 65, 14, 44,
180,
]),
256: new Uint8Array([
8, 97, 235, 113, 70, 32, 135, 131, 210, 209, 124, 160, 255, 182, 9, 29,
125, 193, 27, 240, 129, 46, 2, 137, 169, 142, 61, 7, 145, 54, 170, 207,
159, 111, 39, 95, 87, 63, 162, 27, 6, 18, 219, 215, 116, 34, 90, 57, 114,
244, 102, 145, 67, 6, 51, 152, 247, 165, 242, 116, 100, 219, 177, 72, 177,
17, 110, 67, 93, 219, 100, 217, 20, 207, 89, 154, 45, 37, 105, 83, 67,
162, 140, 235, 129, 40, 177, 202, 174, 54, 148, 55, 156, 193, 232, 249,
134, 163, 195, 51, 114, 116, 65, 38, 73, 99, 96, 249, 224, 69, 17, 119,
186, 188, 181, 43, 78, 156, 76, 138, 226, 63, 5, 248, 9, 94, 26, 1, 2,
235, 39, 174, 74, 47, 183, 22, 40, 47, 47, 13, 100, 119, 12, 67, 178, 184,
56, 167, 238, 143, 13, 44, 208, 185, 151, 108, 6, 17, 52, 122, 182, 210,
207, 42, 219, 37, 74, 94, 126, 36, 249, 37, 32, 4, 218, 44, 238, 69, 56,
219, 31, 77, 173, 46, 187, 103, 36, 112, 213, 252, 40, 87, 164, 240, 163,
159, 32, 129, 125, 178, 108, 47, 28, 31, 36, 42, 115, 36, 14, 145, 195,
156, 191, 46, 163, 249, 181, 31, 90, 73, 30, 72, 57, 223, 63, 60, 79, 140,
14, 117, 31, 145, 222, 156, 121, 237, 32, 145, 143, 96, 12, 254, 35, 21,
21, 59, 168, 171, 154, 217, 0, 59, 202, 175, 103, 214, 192, 175, 26, 18,
43, 54, 176, 222, 75, 22, 7, 122, 253, 224, 145, 61, 42, 208, 73, 237, 84,
141, 209, 213, 228, 46, 244, 59, 9, 68, 6, 35, 88, 189, 10, 62, 9, 85, 28,
44, 82, 19, 153, 160, 178, 240, 56, 160, 244, 201, 173, 77, 61, 20, 227,
30, 180, 167, 16, 105, 185, 193, 95, 207, 41, 23, 134, 78, 198, 182, 93,
24, 89, 247, 231, 75, 233, 194, 137, 242, 114, 194, 190, 130, 138, 238,
94, 137, 193, 194, 115, 137, 190, 207, 169, 83, 155, 14, 210, 160, 129,
195, 161, 234, 221, 255, 114, 67, 98, 12, 93, 41, 65, 183, 244, 103, 247,
101, 82, 246, 125, 87, 125, 78, 21, 186, 102, 205, 20, 40, 32, 201, 174,
15, 52, 240, 217, 180, 162, 108, 6, 211, 41, 18, 135, 232, 184, 18, 188,
169, 157, 190, 76, 166, 75, 176, 127, 39, 251, 22, 203, 153, 80, 49, 241,
124, 137, 151, 123, 204, 43, 159, 190, 177, 196, 18, 117, 169, 46, 152,
251, 45, 25, 164, 27, 145, 214, 228, 55, 15, 2, 131, 216, 80, 255, 204,
175, 100, 59, 145, 15, 103, 40, 33, 45, 255, 200, 254, 172, 138, 20, 58,
87, 182, 192, 148, 219, 41, 88, 230, 229, 70, 249,
]),
};
return {
plaintext,
keyBytes,
iv,
additionalData,
tag,
tag_with_empty_ad,
ciphertext,
};
}

View File

@ -0,0 +1,209 @@
function getFixtures() {
// Before we can really start, we need to fill a bunch of buffers with data
var plaintext = new Uint8Array([
84, 104, 105, 115, 32, 115, 112, 101, 99, 105, 102, 105, 99, 97, 116, 105,
111, 110, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115, 32, 97, 32, 74, 97,
118, 97, 83, 99, 114, 105, 112, 116, 32, 65, 80, 73, 32, 102, 111, 114, 32,
112, 101, 114, 102, 111, 114, 109, 105, 110, 103, 32, 98, 97, 115, 105, 99,
32, 99, 114, 121, 112, 116, 111, 103, 114, 97, 112, 104, 105, 99, 32, 111,
112, 101, 114, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 119, 101, 98,
32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 115, 44, 32, 115,
117, 99, 104, 32, 97, 115, 32, 104, 97, 115, 104, 105, 110, 103, 44, 32,
115, 105, 103, 110, 97, 116, 117, 114, 101, 32, 103, 101, 110, 101, 114, 97,
116, 105, 111, 110, 32, 97, 110, 100, 32, 118, 101, 114, 105, 102, 105, 99,
97, 116, 105, 111, 110, 44, 32, 97, 110, 100, 32, 101, 110, 99, 114, 121,
112, 116, 105, 111, 110, 32, 97, 110, 100, 32, 100, 101, 99, 114, 121, 112,
116, 105, 111, 110, 46, 32, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108,
108, 121, 44, 32, 105, 116, 32, 100, 101, 115, 99, 114, 105, 98, 101, 115,
32, 97, 110, 32, 65, 80, 73, 32, 102, 111, 114, 32, 97, 112, 112, 108, 105,
99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, 103, 101, 110, 101, 114,
97, 116, 101, 32, 97, 110, 100, 47, 111, 114, 32, 109, 97, 110, 97, 103,
101, 32, 116, 104, 101, 32, 107, 101, 121, 105, 110, 103, 32, 109, 97, 116,
101, 114, 105, 97, 108, 32, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32,
116, 111, 32, 112, 101, 114, 102, 111, 114, 109, 32, 116, 104, 101, 115,
101, 32, 111, 112, 101, 114, 97, 116, 105, 111, 110, 115, 46, 32, 85, 115,
101, 115, 32, 102, 111, 114, 32, 116, 104, 105, 115, 32, 65, 80, 73, 32,
114, 97, 110, 103, 101, 32, 102, 114, 111, 109, 32, 117, 115, 101, 114, 32,
111, 114, 32, 115, 101, 114, 118, 105, 99, 101, 32, 97, 117, 116, 104, 101,
110, 116, 105, 99, 97, 116, 105, 111, 110, 44, 32, 100, 111, 99, 117, 109,
101, 110, 116, 32, 111, 114, 32, 99, 111, 100, 101, 32, 115, 105, 103, 110,
105, 110, 103, 44, 32, 97, 110, 100, 32, 116, 104, 101, 32, 99, 111, 110,
102, 105, 100, 101, 110, 116, 105, 97, 108, 105, 116, 121, 32, 97, 110, 100,
32, 105, 110, 116, 101, 103, 114, 105, 116, 121, 32, 111, 102, 32, 99, 111,
109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 115, 46,
]);
// We want some random key bytes of various sizes.
// These were randomly generated from a script.
var keyBytes = {
128: new Uint8Array([
222, 192, 212, 252, 191, 60, 71, 65, 200, 146, 218, 189, 28, 212, 192, 78,
]),
192: new Uint8Array([
208, 238, 131, 65, 63, 68, 196, 63, 186, 208, 61, 207, 166, 18, 99, 152,
29, 109, 221, 95, 240, 30, 28, 246,
]),
256: new Uint8Array([
103, 105, 56, 35, 251, 29, 88, 7, 63, 145, 236, 233, 204, 58, 249, 16,
229, 83, 38, 22, 164, 210, 123, 19, 235, 123, 116, 216, 0, 11, 191, 48,
]),
};
// AES-GCM specification recommends that the IV should be 96 bits long.
var iv = new Uint8Array([
58, 146, 115, 42, 166, 234, 57, 191, 57, 134, 224, 199,
]);
// Authenticated encryption via AES-GCM requires additional data that
// will be checked. We use the ASCII encoded Editorial Note
// following the Abstract of the Web Cryptography API recommendation.
var additionalData = new Uint8Array([
84, 104, 101, 114, 101, 32, 97, 114, 101, 32, 55, 32, 102, 117, 114, 116,
104, 101, 114, 32, 101, 100, 105, 116, 111, 114, 105, 97, 108, 32, 110, 111,
116, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 100, 111, 99, 117, 109,
101, 110, 116, 46,
]);
// The length of the tag defaults to 16 bytes (128 bit).
var tag = {
128: new Uint8Array([
180, 165, 14, 180, 121, 113, 220, 168, 254, 117, 18, 66, 110, 98, 146,
240,
]),
192: new Uint8Array([
43, 102, 63, 121, 1, 120, 252, 2, 95, 149, 99, 207, 161, 10, 139, 159,
]),
256: new Uint8Array([
53, 0, 70, 11, 217, 64, 250, 241, 175, 160, 37, 78, 92, 160, 107, 38,
]),
};
var tag_with_empty_ad = {
128: new Uint8Array([
168, 116, 195, 94, 178, 179, 227, 160, 158, 207, 188, 132, 23, 137, 246,
129,
]),
192: new Uint8Array([
111, 84, 157, 153, 12, 219, 247, 161, 220, 24, 0, 74, 203, 228, 83, 201,
]),
256: new Uint8Array([
125, 85, 225, 240, 220, 112, 144, 9, 168, 179, 251, 128, 126, 147, 131,
244,
]),
};
// Results. These were created using OpenSSL.
// AES-GCM produces ciphertext and a tag.
var ciphertext = {
128: new Uint8Array([
46, 244, 139, 198, 120, 180, 9, 39, 83, 58, 203, 107, 69, 71, 8, 165, 132,
200, 94, 31, 228, 120, 170, 81, 241, 29, 38, 175, 99, 215, 241, 157, 144,
97, 35, 42, 36, 231, 2, 94, 214, 140, 67, 48, 189, 242, 21, 208, 110, 179,
30, 90, 181, 105, 242, 17, 244, 42, 42, 36, 125, 228, 82, 250, 87, 199,
95, 168, 210, 57, 174, 20, 220, 188, 107, 65, 242, 43, 217, 122, 145, 160,
100, 139, 54, 135, 175, 139, 115, 89, 15, 236, 234, 83, 2, 135, 51, 125,
63, 168, 184, 235, 148, 68, 132, 124, 166, 171, 53, 68, 94, 187, 31, 68,
119, 47, 252, 73, 63, 138, 154, 84, 167, 0, 54, 33, 11, 200, 22, 91, 245,
62, 64, 192, 7, 180, 210, 52, 233, 23, 24, 181, 50, 230, 63, 118, 228, 24,
1, 242, 75, 62, 196, 222, 122, 154, 227, 125, 89, 73, 112, 100, 154, 249,
61, 141, 126, 145, 46, 247, 102, 242, 62, 148, 94, 172, 128, 181, 110, 6,
7, 209, 58, 222, 51, 169, 83, 189, 200, 47, 22, 80, 49, 169, 227, 245,
165, 24, 96, 152, 228, 14, 252, 199, 193, 148, 46, 84, 49, 248, 198, 7, 0,
134, 255, 174, 151, 103, 48, 154, 178, 198, 103, 45, 226, 118, 19, 41, 85,
2, 55, 71, 7, 6, 0, 24, 150, 145, 227, 162, 126, 102, 248, 134, 116, 174,
215, 217, 166, 160, 140, 129, 21, 220, 131, 110, 242, 94, 249, 103, 151,
154, 81, 225, 35, 111, 131, 129, 111, 172, 214, 168, 30, 169, 71, 210, 64,
68, 56, 228, 223, 248, 233, 234, 140, 86, 145, 121, 29, 232, 55, 165, 61,
175, 147, 66, 33, 92, 6, 209, 241, 149, 73, 77, 9, 104, 2, 154, 247, 92,
87, 159, 191, 113, 82, 122, 148, 89, 28, 122, 111, 93, 110, 60, 42, 34,
70, 161, 14, 50, 153, 238, 189, 173, 99, 10, 118, 252, 1, 28, 67, 151,
114, 46, 78, 181, 78, 233, 183, 6, 254, 57, 29, 53, 118, 175, 80, 97, 156,
237, 219, 196, 71, 80, 161, 248, 139, 96, 124, 181, 154, 124, 149, 219,
47, 90, 11, 98, 63, 21, 64, 144, 77, 161, 204, 127, 209, 209, 7, 86, 65,
39, 142, 251, 183, 43, 227, 120, 155, 72, 70, 204, 89, 227, 199, 203, 28,
128, 23, 104, 188, 215, 32, 190, 18, 156, 57, 105, 7, 179, 155, 136, 236,
82, 173, 156, 170, 124, 210, 22, 11, 27, 182, 236, 109, 200, 172, 227, 72,
37, 1, 175, 9, 214, 227, 23, 141, 169, 215, 77, 134, 76, 229, 169, 241,
116, 222, 157, 77, 158, 213, 118, 223, 17, 31, 212, 97, 21, 237, 83, 2,
218, 239, 59, 147, 30, 169, 97, 12,
]),
192: new Uint8Array([
129, 16, 61, 38, 99, 56, 226, 139, 71, 251, 211, 15, 91, 152, 159, 219,
112, 147, 210, 73, 97, 204, 203, 240, 183, 243, 104, 241, 37, 67, 169,
198, 56, 76, 96, 202, 250, 212, 177, 157, 93, 115, 247, 176, 19, 3, 229,
102, 75, 200, 252, 222, 197, 58, 31, 44, 123, 151, 9, 191, 88, 123, 35,
48, 47, 25, 149, 35, 191, 219, 223, 94, 251, 152, 109, 171, 225, 31, 236,
252, 223, 174, 128, 238, 173, 32, 32, 79, 22, 100, 112, 215, 153, 128, 63,
158, 247, 18, 215, 81, 247, 208, 91, 28, 223, 222, 170, 9, 135, 210, 143,
47, 247, 132, 183, 252, 84, 19, 78, 85, 17, 215, 20, 51, 32, 124, 149,
172, 129, 202, 161, 217, 207, 24, 45, 177, 11, 106, 17, 108, 17, 12, 6,
62, 90, 132, 2, 54, 96, 90, 30, 239, 216, 173, 76, 67, 7, 221, 62, 124,
228, 156, 243, 31, 111, 160, 192, 188, 87, 107, 182, 138, 95, 122, 152,
202, 51, 118, 100, 124, 67, 220, 116, 52, 99, 15, 39, 2, 14, 209, 173,
119, 88, 6, 174, 106, 236, 150, 28, 189, 112, 161, 224, 186, 58, 110, 91,
54, 211, 132, 149, 7, 188, 77, 232, 118, 197, 43, 107, 101, 179, 44, 195,
159, 4, 124, 5, 30, 48, 227, 251, 199, 72, 98, 177, 206, 234, 228, 58,
191, 150, 28, 211, 29, 182, 138, 141, 249, 152, 142, 244, 203, 210, 128,
143, 244, 44, 187, 251, 221, 101, 152, 31, 119, 194, 51, 27, 167, 215,
122, 244, 193, 224, 191, 198, 210, 2, 143, 185, 207, 145, 228, 193, 153,
207, 119, 167, 75, 145, 43, 17, 1, 42, 146, 164, 21, 15, 164, 221, 216,
140, 122, 248, 49, 19, 246, 84, 214, 176, 226, 118, 140, 130, 123, 163,
217, 61, 198, 243, 182, 217, 52, 127, 190, 127, 135, 18, 239, 163, 195,
102, 136, 227, 128, 38, 244, 49, 208, 229, 249, 126, 157, 100, 72, 246,
10, 102, 163, 241, 155, 112, 165, 95, 32, 61, 66, 24, 233, 123, 236, 190,
124, 214, 65, 135, 114, 118, 122, 222, 196, 47, 120, 120, 64, 117, 253,
165, 28, 17, 152, 104, 119, 10, 53, 140, 109, 79, 246, 246, 28, 104, 228,
175, 102, 71, 246, 183, 79, 30, 31, 186, 32, 64, 146, 72, 228, 1, 175,
252, 115, 254, 95, 66, 87, 196, 134, 41, 115, 165, 206, 253, 245, 147,
137, 163, 230, 235, 238, 77, 218, 74, 157, 65, 97, 43, 198, 130, 190, 195,
142, 22, 166, 4, 179, 184, 167, 254, 156, 243, 38, 46, 66, 68, 252, 252,
161, 209, 83, 177, 128, 115, 92, 158, 182, 177, 185, 23, 39, 138, 245, 29,
216, 17, 178, 142, 225, 135, 8, 115,
]),
256: new Uint8Array([
191, 72, 167, 1, 122, 218, 148, 218, 15, 239, 202, 129, 96, 108, 229, 157,
138, 161, 232, 71, 80, 188, 118, 61, 75, 105, 120, 201, 14, 102, 102, 240,
111, 131, 180, 83, 95, 73, 2, 138, 205, 56, 9, 137, 227, 235, 73, 71, 200,
62, 246, 0, 223, 209, 3, 255, 113, 112, 63, 103, 41, 154, 77, 13, 149, 89,
94, 79, 132, 193, 114, 40, 158, 33, 55, 242, 130, 109, 136, 69, 124, 130,
150, 40, 69, 211, 224, 154, 209, 243, 65, 58, 230, 253, 31, 21, 72, 102,
18, 250, 139, 230, 235, 11, 108, 184, 133, 108, 181, 138, 188, 189, 91,
91, 115, 216, 68, 9, 229, 30, 154, 132, 118, 219, 183, 235, 177, 197, 221,
58, 13, 90, 126, 198, 74, 87, 162, 226, 7, 51, 184, 15, 209, 81, 86, 138,
169, 154, 12, 206, 58, 187, 228, 177, 68, 65, 62, 68, 141, 93, 241, 105,
29, 239, 20, 102, 222, 49, 209, 18, 162, 247, 200, 240, 122, 244, 204,
148, 67, 58, 118, 164, 95, 230, 68, 242, 203, 138, 145, 132, 6, 224, 206,
234, 131, 183, 137, 249, 2, 11, 254, 123, 235, 70, 14, 136, 207, 76, 57,
22, 38, 49, 197, 219, 123, 43, 241, 191, 64, 211, 152, 178, 140, 165, 1,
189, 52, 79, 184, 213, 56, 215, 182, 27, 27, 70, 243, 101, 255, 50, 108,
210, 105, 13, 22, 218, 176, 238, 36, 113, 251, 18, 218, 138, 214, 193, 21,
122, 224, 125, 118, 134, 161, 174, 130, 86, 233, 149, 151, 33, 31, 88, 63,
91, 63, 209, 145, 158, 109, 42, 176, 43, 23, 151, 49, 101, 199, 35, 101,
158, 139, 198, 219, 209, 125, 221, 205, 99, 69, 142, 165, 139, 110, 220,
184, 226, 238, 149, 161, 175, 171, 167, 170, 65, 19, 156, 166, 219, 231,
87, 20, 226, 58, 210, 134, 110, 160, 176, 118, 250, 73, 86, 213, 116, 53,
114, 24, 101, 34, 185, 59, 237, 47, 39, 206, 67, 12, 74, 236, 130, 7, 249,
217, 203, 245, 122, 14, 230, 53, 203, 126, 93, 131, 51, 2, 0, 231, 161,
111, 42, 126, 173, 121, 80, 179, 59, 186, 133, 236, 252, 188, 149, 99,
221, 182, 55, 5, 38, 83, 132, 43, 123, 233, 174, 208, 140, 165, 77, 1,
202, 46, 6, 183, 207, 246, 125, 37, 110, 226, 61, 155, 194, 198, 153, 107,
1, 8, 0, 23, 124, 18, 4, 144, 235, 146, 77, 220, 123, 152, 114, 219, 127,
59, 126, 10, 79, 106, 198, 11, 27, 111, 11, 155, 1, 137, 38, 74, 3, 248,
225, 221, 203, 86, 4, 148, 25, 88, 144, 185, 38, 114, 139, 48, 74, 82,
172, 36, 115, 193, 223, 220, 144, 69, 91, 5, 83, 56, 138, 63,
]),
};
return {
plaintext,
keyBytes,
iv,
additionalData,
tag,
tag_with_empty_ad,
ciphertext,
};
}

View File

@ -0,0 +1,76 @@
// aes_gcm_vectors.js
// 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
// keyBuffer - an arrayBuffer with the key data in raw form
// key - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt
// plaintext - the text to encrypt
// result - the expected result (usually just ciphertext, sometimes with added authentication)
function getTestVectors() {
const {
plaintext,
keyBytes,
iv,
additionalData,
tag,
tag_with_empty_ad,
ciphertext,
} = getFixtures();
var keyLengths = [128, 192, 256];
var tagLengths = [32, 64, 96, 104, 112, 120, 128];
// All the scenarios that should succeed, if the key has "encrypt" usage
var passing = [];
keyLengths.forEach(function(keyLength) {
tagLengths.forEach(function(tagLength) {
var byteCount = tagLength / 8;
var result = new Uint8Array(ciphertext[keyLength].byteLength + byteCount);
result.set(ciphertext[keyLength], 0);
result.set(tag[keyLength].slice(0, byteCount), ciphertext[keyLength].byteLength);
passing.push({
name: "AES-GCM " + keyLength.toString() + "-bit key, " + tagLength.toString() + "-bit tag, " + (iv.byteLength << 3).toString() + "-bit iv",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-GCM", iv: iv, additionalData: additionalData, tagLength: tagLength},
plaintext: plaintext,
result: result
});
var noadresult = new Uint8Array(ciphertext[keyLength].byteLength + byteCount);
noadresult.set(ciphertext[keyLength], 0);
noadresult.set(tag_with_empty_ad[keyLength].slice(0, byteCount), ciphertext[keyLength].byteLength);
passing.push({
name: "AES-GCM " + keyLength.toString() + "-bit key, no additional data, " + tagLength.toString() + "-bit tag, " + (iv.byteLength << 3).toString() + "-bit iv",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-GCM", iv: iv, tagLength: tagLength},
plaintext: plaintext,
result: noadresult
});
});
});
// Scenarios that should fail because of a bad tag length, causing an OperationError
var failing = [];
keyLengths.forEach(function(keyLength) {
// First, make some tests for bad tag lengths
[24, 48, 72, 95, 129].forEach(function(badTagLength) {
failing.push({
name: "AES-GCM " + keyLength.toString() + "-bit key, " + (iv.byteLength << 3).toString() + "-bit iv, " + "illegal tag length " + badTagLength.toString() + "-bits",
keyBuffer: keyBytes[keyLength],
key: null,
algorithm: {name: "AES-GCM", iv: iv, additionalData: additionalData, tagLength: badTagLength},
plaintext: plaintext,
result: ciphertext[keyLength]
});
});
});
return {passing: passing, failing: failing, decryptionFailing: []};
}

View File

@ -0,0 +1,378 @@
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 rsa_vectors.js provides the getTestVectors method
// for the RSA-OAEP algorithm that drives these tests.
var vectors = getTestVectors();
var passingVectors = vectors.passing;
var failingVectors = vectors.failing;
// Test decryption, first, because encryption tests rely on that working
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
// Get a one byte longer plaintext to encrypt
if (!("ciphertext" in vector)) {
return;
}
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.privateKey, vector.ciphertext)
.then(function(plaintext) {
assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works"));
}, function(err) {
assert_unreached("Decryption should not throw error " + vector.name + ": " + err.message + "'");
});
}, vector.name + " decryption");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " decryption");
});
all_promises.push(promise);
});
// Test decryption with an altered buffer
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
// Get a one byte longer plaintext to encrypt
if (!("ciphertext" in vector)) {
return;
}
promise_test(function(test) {
var ciphertext = copyBuffer(vector.ciphertext);
var operation = subtle.decrypt(vector.algorithm, vector.privateKey, ciphertext)
.then(function(plaintext) {
assert_true(equalBuffers(plaintext, vector.plaintext, "Decryption works"));
}, function(err) {
assert_unreached("Decryption should not throw error " + vector.name + ": " + err.message + "'");
});
ciphertext[0] = 255 - ciphertext[0];
return operation;
}, vector.name + " decryption with altered ciphertext");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " decryption with altered ciphertext");
});
all_promises.push(promise);
});
// Check for failures due to using publicKey to decrypt.
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.publicKey, vector.ciphertext)
.then(function(plaintext) {
assert_unreached("Should have thrown error for using publicKey to decrypt in " + vector.name + ": " + err.message + "'");
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of " + err.message);
});
}, vector.name + " using publicKey to decrypt");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " using publicKey to decrypt");
});
all_promises.push(promise);
});
// Check for failures due to no "decrypt" usage.
passingVectors.forEach(function(originalVector) {
var vector = Object.assign({}, originalVector);
var promise = importVectorKeys(vector, ["encrypt"], ["unwrapKey"])
.then(function(vectors) {
// Get a one byte longer plaintext to encrypt
promise_test(function(test) {
return subtle.decrypt(vector.algorithm, vector.publicKey, vector.ciphertext)
.then(function(plaintext) {
assert_unreached("Should have thrown error for no decrypt usage in " + vector.name + ": " + err.message + "'");
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of " + err.message);
});
}, vector.name + " no decrypt usage");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " no decrypt usage");
});
all_promises.push(promise);
});
// Check for successful encryption even if plaintext is altered after call.
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
promise_test(function(test) {
var plaintext = copyBuffer(vector.plaintext);
var operation = subtle.encrypt(vector.algorithm, vector.publicKey, plaintext)
.then(function(ciphertext) {
assert_equals(ciphertext.byteLength * 8, vector.privateKey.algorithm.modulusLength, "Ciphertext length matches modulus length");
// Can we get the original plaintext back via decrypt?
return subtle.decrypt(vector.algorithm, vector.privateKey, ciphertext)
.then(function(result) {
assert_true(equalBuffers(result, vector.plaintext), "Round trip returns original plaintext");
return ciphertext;
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": " + err.message + "'");
});
})
.then(function(priorCiphertext) {
// Will a second encrypt give us different ciphertext, as it should?
return subtle.encrypt(vector.algorithm, vector.publicKey, vector.plaintext)
.then(function(ciphertext) {
assert_false(equalBuffers(priorCiphertext, ciphertext), "Two encrypts give different results")
}, function(err) {
assert_unreached("second time encrypt error for test " + vector.name + ": '" + err.message + "'");
});
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": '" + err.message + "'");
});
plaintext[0] = 255 - plaintext[0];
return operation;
}, vector.name + " with altered plaintext");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
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 successful encryption.
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.publicKey, vector.plaintext)
.then(function(ciphertext) {
assert_equals(ciphertext.byteLength * 8, vector.privateKey.algorithm.modulusLength, "Ciphertext length matches modulus length");
// Can we get the original plaintext back via decrypt?
return subtle.decrypt(vector.algorithm, vector.privateKey, ciphertext)
.then(function(result) {
assert_true(equalBuffers(result, vector.plaintext), "Round trip returns original plaintext");
return ciphertext;
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": " + err.message + "'");
});
})
.then(function(priorCiphertext) {
// Will a second encrypt give us different ciphertext, as it should?
return subtle.encrypt(vector.algorithm, vector.publicKey, vector.plaintext)
.then(function(ciphertext) {
assert_false(equalBuffers(priorCiphertext, ciphertext), "Two encrypts give different results")
}, function(err) {
assert_unreached("second time encrypt error for test " + vector.name + ": '" + err.message + "'");
});
}, function(err) {
assert_unreached("decrypt error for test " + vector.name + ": '" + err.message + "'");
});
}, vector.name);
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name);
});
all_promises.push(promise);
});
// Check for failures due to too long plaintext.
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
// Get a one byte longer plaintext to encrypt
var plaintext = new Uint8Array(vector.plaintext.byteLength + 1);
plaintext.set(plaintext, 0);
plaintext.set(new Uint8Array([32]), vector.plaintext.byteLength);
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.publicKey, plaintext)
.then(function(ciphertext) {
assert_unreached("Should have thrown error for too long plaintext in " + vector.name + ": " + err.message + "'");
}, function(err) {
assert_equals(err.name, "OperationError", "Should throw OperationError instead of " + err.message);
});
}, vector.name + " too long plaintext");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " too long plaintext");
});
all_promises.push(promise);
});
// Check for failures due to using privateKey to encrypt.
passingVectors.forEach(function(vector) {
var promise = importVectorKeys(vector, ["encrypt"], ["decrypt"])
.then(function(vectors) {
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.privateKey, vector.plaintext)
.then(function(ciphertext) {
assert_unreached("Should have thrown error for using privateKey to encrypt in " + vector.name + ": " + err.message + "'");
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of " + err.message);
});
}, vector.name + " using privateKey to encrypt");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " using privateKey to encrypt");
});
all_promises.push(promise);
});
// Check for failures due to no "encrypt usage".
passingVectors.forEach(function(originalVector) {
var vector = Object.assign({}, originalVector);
var promise = importVectorKeys(vector, [], ["decrypt"])
.then(function(vectors) {
// Get a one byte longer plaintext to encrypt
promise_test(function(test) {
return subtle.encrypt(vector.algorithm, vector.publicKey, vector.plaintext)
.then(function(ciphertext) {
assert_unreached("Should have thrown error for no encrypt usage in " + vector.name + ": " + err.message + "'");
}, function(err) {
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of " + err.message);
});
}, vector.name + " no encrypt usage");
}, function(err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested encryption
promise_test(function(test) {
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
}, "importVectorKeys step: " + vector.name + " no encrypt usage");
});
all_promises.push(promise);
});
promise_test(function() {
return Promise.all(all_promises)
.then(function() {done();})
.catch(function() {done();})
}, "setup");
// A test vector has all needed fields for encryption, 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.
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;
}
}
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;
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: encrypt() Using RSA-OAEP
// META: script=rsa_vectors.js
// META: script=rsa.js
// META: timeout=long
run_test();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,228 @@
function run_test(algorithmNames) {
var subtle = crypto.subtle; // Change to test prefixed implementations
setup({explicit_timeout: true});
// These tests check that generateKey throws an error, and that
// the error is of the right type, for a wide set of incorrect parameters.
//
// Error testing occurs by setting the parameter that should trigger the
// error to an invalid value, then combining that with all valid
// parameters that should be checked earlier by generateKey, and all
// valid and invalid parameters that should be checked later by
// generateKey.
//
// There are a lot of combinations of possible parameters for both
// success and failure modes, resulting in a very large number of tests
// performed.
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var allTestVectors = [ // Parameters that should work for generateKey
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
];
var testVectors = [];
if (algorithmNames && !Array.isArray(algorithmNames)) {
algorithmNames = [algorithmNames];
};
allTestVectors.forEach(function(vector) {
if (!algorithmNames || algorithmNames.includes(vector.name)) {
testVectors.push(vector);
}
});
function parameterString(algorithm, extractable, usages) {
if (typeof algorithm !== "object" && typeof algorithm !== "string") {
alert(algorithm);
}
var result = "(" +
objectToString(algorithm) + ", " +
objectToString(extractable) + ", " +
objectToString(usages) +
")";
return result;
}
// Test that a given combination of parameters results in an error,
// AND that it is the correct kind of error.
//
// Expected error is either a number, tested against the error code,
// or a string, tested against the error name.
function testError(algorithm, extractable, usages, expectedError, testTag) {
promise_test(function(test) {
return crypto.subtle.generateKey(algorithm, extractable, usages)
.then(function(result) {
assert_unreached("Operation succeeded, but should not have");
}, function(err) {
if (typeof expectedError === "number") {
assert_equals(err.code, expectedError, testTag + " not supported");
} else {
assert_equals(err.name, expectedError, testTag + " not supported");
}
});
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
}
// Given an algorithm name, create several invalid parameters.
function badAlgorithmPropertySpecifiersFor(algorithmName) {
var results = [];
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
// Specifier properties are name and length
[64, 127, 129, 255, 257, 512].forEach(function(length) {
results.push({name: algorithmName, length: length});
});
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
[new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
});
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
["P-512", "Curve25519"].forEach(function(curveName) {
results.push({name: algorithmName, namedCurve: curveName});
});
}
return results;
}
// Don't create an exhaustive list of all invalid usages,
// because there would usually be nearly 2**8 of them,
// way too many to test. Instead, create every singleton
// of an illegal usage, and "poison" every valid usage
// with an illegal one.
function invalidUsages(validUsages, mandatoryUsages) {
var results = [];
var illegalUsages = [];
["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
if (!validUsages.includes(usage)) {
illegalUsages.push(usage);
}
});
var goodUsageCombinations = allValidUsages(validUsages, false, mandatoryUsages);
illegalUsages.forEach(function(illegalUsage) {
results.push([illegalUsage]);
goodUsageCombinations.forEach(function(usageCombination) {
results.push(usageCombination.concat([illegalUsage]));
});
});
return results;
}
// Now test for properly handling errors
// - Unsupported algorithm
// - Bad usages for algorithm
// - Bad key lengths
// Algorithm normalization should fail with "Not supported"
var badAlgorithmNames = [
"AES",
{name: "AES"},
{name: "AES", length: 128},
{name: "AES-CMAC", length: 128}, // Removed after CR
{name: "AES-CFB", length: 128}, // Removed after CR
{name: "HMAC", hash: "MD5"},
{name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
{name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
{name: "EC", namedCurve: "P521"}
];
// Algorithm normalization failures should be found first
// - all other parameters can be good or bad, should fail
// due to NotSupportedError.
badAlgorithmNames.forEach(function(algorithm) {
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
.forEach(function(usages) {
[false, true, "RED", 7].forEach(function(extractable){
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
});
});
});
// Empty algorithm should fail with TypeError
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
.forEach(function(usages) {
[false, true, "RED", 7].forEach(function(extractable){
testError({}, extractable, usages, "TypeError", "Empty algorithm");
});
});
// Algorithms normalize okay, but usages bad (though not empty).
// It shouldn't matter what other extractable is. Should fail
// due to SyntaxError
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
[true].forEach(function(extractable) {
testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
});
});
});
});
// Other algorithm properties should be checked next, so try good
// algorithm names and usages, but bad algorithm properties next.
// - Special case: normally bad usage [] isn't checked until after properties,
// so it's included in this test case. It should NOT cause an error.
testVectors.forEach(function(vector) {
var name = vector.name;
badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
allValidUsages(vector.usages, true, vector.mandatoryUsages)
.forEach(function(usages) {
[false, true].forEach(function(extractable) {
if (name.substring(0,2) === "EC") {
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
} else {
testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
}
});
});
});
});
// The last thing that should be checked is empty usages (disallowed for secret and private keys).
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
var usages = [];
[false, true].forEach(function(extractable) {
testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
});
});
});
}

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["AES-CBC"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["AES-CTR"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["AES-GCM"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["AES-KW"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["ECDH"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["ECDSA"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["Ed25519"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["Ed448"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["HMAC"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["RSA-OAEP"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["RSA-PSS"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["RSASSA-PKCS1-v1_5"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["X25519"]);

View File

@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["X448"]);

View File

@ -0,0 +1,115 @@
function run_test(algorithmNames, slowTest) {
var subtle = crypto.subtle; // Change to test prefixed implementations
setup({explicit_timeout: true});
// These tests check that generateKey successfully creates keys
// when provided any of a wide set of correct parameters
// and that they can be exported afterwards.
//
// There are a lot of combinations of possible parameters,
// resulting in a very large number of tests
// performed.
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var allTestVectors = [ // Parameters that should work for generateKey
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
];
var testVectors = [];
if (algorithmNames && !Array.isArray(algorithmNames)) {
algorithmNames = [algorithmNames];
};
allTestVectors.forEach(function(vector) {
if (!algorithmNames || algorithmNames.includes(vector.name)) {
testVectors.push(vector);
}
});
function parameterString(algorithm, extractable, usages) {
var result = "(" +
objectToString(algorithm) + ", " +
objectToString(extractable) + ", " +
objectToString(usages) +
")";
return result;
}
// Test that a given combination of parameters is successful
function testSuccess(algorithm, extractable, usages, resultType, testTag) {
// algorithm, extractable, and usages are the generateKey parameters
// resultType is the expected result, either the CryptoKey object or "CryptoKeyPair"
// testTag is a string to prepend to the test name.
promise_test(function(test) {
return subtle.generateKey(algorithm, extractable, usages)
.then(function(result) {
if (resultType === "CryptoKeyPair") {
assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
assert_goodCryptoKey(result.publicKey, algorithm, true, usages, "public");
} else {
assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
}
return result;
}, function(err) {
assert_unreached("generateKey threw an unexpected error: " + err.toString());
})
.then(async function (result) {
if (resultType === "CryptoKeyPair") {
await Promise.all([
subtle.exportKey('jwk', result.publicKey),
subtle.exportKey('spki', result.publicKey),
result.publicKey.algorithm.name.startsWith('RSA') ? undefined : subtle.exportKey('raw', result.publicKey),
...(extractable ? [
subtle.exportKey('jwk', result.privateKey),
subtle.exportKey('pkcs8', result.privateKey),
] : [])
]);
} else {
if (extractable) {
await Promise.all([
subtle.exportKey('raw', result),
subtle.exportKey('jwk', result),
]);
}
}
}, function(err) {
assert_unreached("exportKey threw an unexpected error: " + err.toString());
})
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
}
// Test all valid sets of parameters for successful
// key generation.
testVectors.forEach(function(vector) {
allNameVariants(vector.name, slowTest).forEach(function(name) {
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) {
[false, true].forEach(function(extractable) {
subsetTest(testSuccess, algorithm, extractable, usages, vector.resultType, "Success");
});
});
});
});
});
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["AES-CBC"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["AES-CTR"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["AES-GCM"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["AES-KW"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["ECDH"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["ECDSA"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["Ed25519"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["Ed448"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["HMAC"]);

View File

@ -0,0 +1,22 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: variant=?1-10
// META: variant=?11-20
// META: variant=?21-30
// META: variant=?31-40
// META: variant=?41-50
// META: variant=?51-60
// META: variant=?61-70
// META: variant=?71-80
// META: variant=?81-90
// META: variant=?91-100
// META: variant=?101-110
// META: variant=?111-120
// META: variant=?121-130
// META: variant=?131-140
// META: variant=?141-150
// META: variant=?151-last
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["RSA-OAEP"]);

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: variant=?1-10
// META: variant=?11-20
// META: variant=?21-30
// META: variant=?31-last
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["RSA-PSS"]);

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: variant=?1-10
// META: variant=?11-20
// META: variant=?21-30
// META: variant=?31-last
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["RSASSA-PKCS1-v1_5"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["X25519"]);

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["X448"]);

View File

@ -0,0 +1,77 @@
// Step 1.
test(function() {
assert_throws_dom("TypeMismatchError", function() {
self.crypto.getRandomValues(new Float16Array(6))
}, "Float16Array")
assert_throws_dom("TypeMismatchError", function() {
const len = 65536 / Float16Array.BYTES_PER_ELEMENT + 1;
self.crypto.getRandomValues(new Float16Array(len));
}, "Float16Array (too long)")
}, "Float16 arrays");
test(function() {
assert_throws_dom("TypeMismatchError", function() {
self.crypto.getRandomValues(new Float32Array(6))
}, "Float32Array")
assert_throws_dom("TypeMismatchError", function() {
self.crypto.getRandomValues(new Float64Array(6))
}, "Float64Array")
assert_throws_dom("TypeMismatchError", function() {
const len = 65536 / Float32Array.BYTES_PER_ELEMENT + 1;
self.crypto.getRandomValues(new Float32Array(len));
}, "Float32Array (too long)")
assert_throws_dom("TypeMismatchError", function() {
const len = 65536 / Float64Array.BYTES_PER_ELEMENT + 1;
self.crypto.getRandomValues(new Float64Array(len))
}, "Float64Array (too long)")
}, "Float arrays");
test(function() {
assert_throws_dom("TypeMismatchError", function() {
self.crypto.getRandomValues(new DataView(new ArrayBuffer(6)))
}, "DataView")
assert_throws_dom("TypeMismatchError", function() {
self.crypto.getRandomValues(new DataView(new ArrayBuffer(65536 + 1)))
}, "DataView (too long)")
}, "DataView");
const arrays = [
'Int8Array',
'Int16Array',
'Int32Array',
'BigInt64Array',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array',
'BigUint64Array',
];
for (const array of arrays) {
const ctor = globalThis[array];
test(function() {
assert_equals(self.crypto.getRandomValues(new ctor(8)).constructor,
ctor, "crypto.getRandomValues(new " + array + "(8))")
}, "Integer array: " + array);
test(function() {
const maxlength = 65536 / ctor.BYTES_PER_ELEMENT;
assert_throws_dom("QuotaExceededError", function() {
self.crypto.getRandomValues(new ctor(maxlength + 1))
}, "crypto.getRandomValues length over 65536")
}, "Large length: " + array);
test(function() {
assert_true(self.crypto.getRandomValues(new ctor(0)).length == 0)
}, "Null arrays: " + array);
test(function() {
class Buffer extends ctor {}
// Must not throw for the test to pass
self.crypto.getRandomValues(new Buffer(256));
}, "Subclass of " + array);
}

View File

@ -0,0 +1,18 @@
// META: global=window,dedicatedworker,sharedworker
//
// Do not run this in a service worker as that's always in a secure context
test(() => {
assert_equals(self.crypto.subtle, undefined);
assert_false("subtle" in self.crypto);
}, "Non-secure context window does not have access to crypto.subtle");
test(() => {
assert_equals(self.SubtleCrypto, undefined);
assert_false("SubtleCrypto" in self);
}, "Non-secure context window does not have access to SubtleCrypto")
test(() => {
assert_equals(self.CryptoKey, undefined);
assert_false("CryptoKey" in self);
}, "Non-secure context window does not have access to CryptoKey")

View File

@ -0,0 +1,16 @@
// META: script=/resources/WebIDLParser.js
// META: script=/resources/idlharness.js
// META: timeout=long
// https://w3c.github.io/webcrypto/Overview.html
idl_test(
['webcrypto'],
['html', 'dom'],
idl_array => {
idl_array.add_objects({
Crypto: ['crypto'],
SubtleCrypto: ['crypto.subtle']
});
}
);

View File

@ -0,0 +1,17 @@
// META: title=WebCryptoAPI: Assure promise returned by importKey is settled.
// META: timeout=long
// META: script=/common/gc.js
'use strict';
promise_test(async () => {
const jwkKey = {};
const extractable = true;
crypto.subtle.importKey("jwk", jwkKey, {name: "UNSUPPORTED", hash: "SHA-224"}, extractable, []).then(
() => { assert_unreached("Unsupported algorithm should cause promise rejection")},
(err) => {
assert_equals(err.name, "NotSupportedError");
});
await garbageCollect();
})

View File

@ -0,0 +1,293 @@
// META: title=WebCryptoAPI: importKey() for EC keys
// META: timeout=long
// META: script=../util/helpers.js
// Test importKey and exportKey for EC algorithms. Only "happy paths" are
// currently tested - those where the operation should succeed.
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]),
spki_compressed: new Uint8Array([48, 88, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 68, 0, 3, 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]),
raw: new Uint8Array([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]),
raw_compressed: new Uint8Array([3, 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]),
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]),
spki_compressed: new Uint8Array([48, 57, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 34, 0, 2, 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]),
raw: new Uint8Array([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]),
raw_compressed: new Uint8Array([2, 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]),
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]),
spki_compressed: new Uint8Array([48, 70, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 50, 0, 2, 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]),
raw: new Uint8Array([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]),
raw_compressed: new Uint8Array([2, 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]),
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
allValidUsages(vector.publicUsages, true).forEach(function(usages) {
['spki', 'spki_compressed', 'jwk', 'raw', 'raw_compressed'].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);
if (vector.name === 'ECDH' && format === 'jwk') {
testEcdhJwkAlg(algorithm, { ...data.jwk, alg: 'any alg works here' }, curve, usages, extractable);
}
});
});
// Next, test private keys
['pkcs8', 'jwk'].forEach(function(format) {
var algorithm = {name: vector.name, namedCurve: curve};
var data = keyData[curve];
allValidUsages(vector.privateUsages).forEach(function(usages) {
testFormat(format, algorithm, data, curve, usages, extractable);
if (vector.name === 'ECDH' && format === 'jwk') {
testEcdhJwkAlg(algorithm, { ...data.jwk, alg: 'any alg works here' }, curve, usages, extractable);
}
});
testEmptyUsages(format, algorithm, data, curve, 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, data, keySize, usages, extractable) {
const keyData = data[format];
const compressed = format.endsWith("_compressed");
if (compressed) {
[format] = format.split("_compressed");
}
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData.d)) ? 'private' : 'public');
if (!extractable) {
return;
}
return subtle.exportKey(format, key).
then(function(result) {
if (format !== "jwk") {
assert_true(equalBuffers(data[format], result), "Round trip works");
} else {
assert_true(equalJwk(data[format], result), "Round trip works");
}
}, function(err) {
assert_unreached("Threw an unexpected error: " + err.toString());
});
}, function(err) {
if (compressed && err.name === "DataError") {
assert_implements_optional(false, "Compressed point format not supported: " + err.toString());
} else {
assert_unreached("Threw an unexpected error: " + err.toString());
}
});
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages));
}
// Test importKey with a given key format and other parameters but with empty usages.
// Should fail with SyntaxError
function testEmptyUsages(format, algorithm, data, keySize, extractable) {
const keyData = data[format];
const usages = [];
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_unreached("importKey succeeded but should have failed with SyntaxError");
}, function(err) {
assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
});
}, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages));
}
// Test ECDH importKey with a JWK format
// Should succeed with any "alg" value
function testEcdhJwkAlg(algorithm, keyData, keySize, usages, extractable) {
const format = "jwk";
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
assert_goodCryptoKey(key, algorithm, extractable, usages, keyData.d ? 'private' : 'public');
}, function(err) {
assert_unreached("Threw an unexpected error: " + err.toString());
});
}, "ECDH any JWK alg: " + keySize.toString() + " bits " + parameterString(format, false, 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, "");
}
// Convert method parameters to a string to uniquely name each test
function parameterString(format, compressed, data, algorithm, extractable, usages) {
if ("byteLength" in data) {
data = "buffer(" + data.byteLength.toString() + (compressed ? ", compressed" : "") + ")";
} 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(", ") + "}";
}

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=ec_importKey_failures_fixtures.js
// META: script=importKey_failures.js
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
run_test(["ECDH"]);

View File

@ -0,0 +1,10 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=ec_importKey_failures_fixtures.js
// META: script=importKey_failures.js
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
run_test(["ECDSA"]);

View File

@ -0,0 +1,225 @@
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
function getValidKeyData(algorithm) {
return validKeyData[algorithm.namedCurve];
}
function getBadKeyLengthData(algorithm) {
return badKeyLengthData[algorithm.namedCurve];
}
function getMissingJWKFieldKeyData(algorithm) {
// The curve doesn't affect when testing for missing JWK fields.
return missingJWKFieldKeyData["P-521"];
}
function getMismatchedJWKKeyData(algorithm) {
// TODO: Implement test cases where the public key doesn't match the private key.
return [];
}
function getMismatchedKtyField(algorithm) {
return mismatchedKtyField[algorithm.name];
}
function getMismatchedCrvField(algorithm) {
return mismatchedCrvField[algorithm.name];
}
var validKeyData = {
"P-521": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format:"pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-521",
x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_",
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
}
}
],
"P-256": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-256",
x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE",
y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg",
d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo"
}
},
],
"P-384": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-384",
x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1",
y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo",
d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz"
}
}
]
};
// Removed just the last byte.
var badKeyLengthData = {
"P-521": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format:"pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-521",
x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU",
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
}
}
],
"P-256": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-256",
x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXd",
y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg",
d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo"
}
},
],
"P-384": [
{
format: "spki",
data: 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]),
},
{
format: "raw",
data: new Uint8Array([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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
kty: "EC",
crv: "P-384",
x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ",
y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo",
d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz"
}
}
]
};
var missingJWKFieldKeyData = {
"P-521": [
{
param: "x",
data: {
kty: "EC",
crv: "P-521",
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
}
},
{
param: "kty",
data: {
crv: "P-521",
x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_",
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
}
},
{
param: "crv",
data: {
kty: "EC",
x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_",
y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7",
d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0"
}
}
]
};
// The 'kty' field doesn't match the key algorithm.
var mismatchedKtyField = {
"P-521": "OKP",
"P-256": "OKP",
"P-384": "OKP",
}
// The 'kty' field doesn't match the key algorithm.
var mismatchedCrvField = {
"P-521": "P-256",
"P-256": "P-384",
"P-384": "P-521",
}

View File

@ -0,0 +1,289 @@
function run_test(algorithmNames) {
var subtle = crypto.subtle; // Change to test prefixed implementations
setup({explicit_timeout: true});
// These tests check that importKey and exportKey throw an error, and that
// the error is of the right type, for a wide set of incorrect parameters.
// Error testing occurs by setting the parameter that should trigger the
// error to an invalid value, then combining that with all valid
// parameters that should be checked earlier by importKey, and all
// valid and invalid parameters that should be checked later by
// importKey.
//
// There are a lot of combinations of possible parameters for both
// success and failure modes, resulting in a very large number of tests
// performed.
var allTestVectors = [ // Parameters that should work for importKey / exportKey
{name: "Ed25519", privateUsages: ["sign"], publicUsages: ["verify"]},
{name: "Ed448", privateUsages: ["sign"], publicUsages: ["verify"]},
{name: "ECDSA", privateUsages: ["sign"], publicUsages: ["verify"]},
{name: "X25519", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
{name: "X448", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
{name: "ECDH", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}
];
var testVectors = [];
if (algorithmNames && !Array.isArray(algorithmNames)) {
algorithmNames = [algorithmNames];
};
allTestVectors.forEach(function(vector) {
if (!algorithmNames || algorithmNames.includes(vector.name)) {
testVectors.push(vector);
}
});
function parameterString(format, algorithm, extractable, usages, data) {
if (typeof algorithm !== "object" && typeof algorithm !== "string") {
alert(algorithm);
}
var jwk_label = "";
if (format === "jwk")
jwk_label = data.d === undefined ? " (public) " : "(private)";
var result = "(" +
objectToString(format) + jwk_label + ", " +
objectToString(algorithm) + ", " +
objectToString(extractable) + ", " +
objectToString(usages) +
")";
return result;
}
// Test that a given combination of parameters results in an error,
// AND that it is the correct kind of error.
//
// Expected error is either a number, tested against the error code,
// or a string, tested against the error name.
function testError(format, algorithm, keyData, keySize, usages, extractable, expectedError, testTag) {
promise_test(async() => {
let key;
try {
key = await subtle.importKey(format, keyData, algorithm, extractable, usages);
} catch(err) {
let actualError = typeof expectedError === "number" ? err.code : err.name;
assert_equals(actualError, expectedError, testTag + " not supported.");
}
assert_equals(key, undefined, "Operation succeeded, but should not have.");
}, testTag + ": importKey" + parameterString(format, algorithm, extractable, usages, keyData));
}
// Don't create an exhaustive list of all invalid usages,
// because there would usually be nearly 2**8 of them,
// way too many to test. Instead, create every singleton
// of an illegal usage, and "poison" every valid usage
// with an illegal one.
function invalidUsages(validUsages, mandatoryUsages) {
var results = [];
var illegalUsages = [];
["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
if (!validUsages.includes(usage)) {
illegalUsages.push(usage);
}
});
var goodUsageCombinations = validUsages.length === 0 ? [] : allValidUsages(validUsages, false, mandatoryUsages);
illegalUsages.forEach(function(illegalUsage) {
results.push([illegalUsage]);
goodUsageCombinations.forEach(function(usageCombination) {
results.push(usageCombination.concat([illegalUsage]));
});
});
return results;
}
function validUsages(usages, format, data) {
if (format === 'spki' || format === 'raw') return usages.publicUsages
if (format === 'pkcs8') return usages.privateUsages
if (format === 'jwk') {
if (data === undefined)
return [];
return data.d === undefined ? usages.publicUsages : usages.privateUsages;
}
return [];
}
function isPrivateKey(data) {
return data.d !== undefined;
}
// Now test for properly handling errors
// - Unsupported algorithm
// - Bad usages for algorithm
// - Bad key lengths
// - Lack of a mandatory format field
// - Incompatible keys pair
// Algorithms normalize okay, but usages bad (though not empty).
// It shouldn't matter what other extractable is. Should fail
// due to SyntaxError
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
invalidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) {
[true, false].forEach(function(extractable) {
testError(test.format, algorithm, test.data, name, usages, extractable, "SyntaxError", "Bad usages");
});
});
});
});
});
// Algorithms normalize okay, but usages bad (empty).
// Should fail due to SyntaxError
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && isPrivateKey(test.data))).forEach(function(test) {
[true, false].forEach(function(extractable) {
testError(test.format, algorithm, test.data, name, [/* Empty usages */], extractable, "SyntaxError", "Empty usages");
});
});
});
});
// Algorithms normalize okay, usages ok. The length of the key must throw a DataError exception.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getBadKeyLengthData(algorithm).forEach(function(test) {
allValidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) {
[true, false].forEach(function(extractable) {
testError(test.format, algorithm, test.data, name, usages, extractable, "DataError", "Bad key length");
});
});
});
});
});
// Algorithms normalize okay, usages ok and valid key. The lack of the mandatory JWK parameter must throw a DataError exception.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getMissingJWKFieldKeyData(algorithm).forEach(function(test) {
allValidUsages(validUsages(vector, 'jwk', test.data)).forEach(function(usages) {
[true, false].forEach(function(extractable) {
testError('jwk', algorithm, test.data, name, usages, extractable, "DataError", "Missing JWK '" + test.param + "' parameter");
});
});
});
});
});
// Algorithms normalize okay, usages ok and valid key. The public key is not compatible with the private key.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getMismatchedJWKKeyData(algorithm).forEach(function(data) {
allValidUsages(vector.privateUsages).forEach(function(usages) {
[true].forEach(function(extractable) {
testError('jwk', algorithm, data, name, usages, extractable, "DataError", "Invalid key pair");
});
});
});
});
});
// Missing mandatory "name" field on algorithm
testVectors.forEach(function(vector) {
var name = vector.name;
// We just need *some* valid keydata, so pick the first available algorithm.
var algorithm = allAlgorithmSpecifiersFor(name)[0];
getValidKeyData(algorithm).forEach(function(test) {
validUsages(vector, test.format, test.data).forEach(function(usages) {
[true, false].forEach(function(extractable) {
testError(test.format, {}, test.data, name, usages, extractable, "TypeError", "Missing algorithm name");
});
});
});
});
// The 'kty' field is not correct.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
if (test.format === "jwk") {
var data = {crv: test.data.crv, kty: test.data.kty, d: test.data.d, x: test.data.x, y: test.data.y};
data.kty = getMismatchedKtyField(algorithm);
var usages = validUsages(vector, 'jwk', test.data);
testError('jwk', algorithm, data, name, usages, true, "DataError", "Invalid 'kty' field");
}
});
});
});
// The 'ext' field is not correct.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
if (test.format === "jwk") {
var data = {crv: test.data.crv, kty: test.data.kty, d: test.data.d, x: test.data.x, y: test.data.y};
data.ext = false;
var usages = validUsages(vector, 'jwk', test.data);
testError('jwk', algorithm, data, name, usages, true, "DataError", "Import from a non-extractable");
}
});
});
});
// The 'use' field is incorrect.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
if (test.format === "jwk") {
var data = {crv: test.data.crv, kty: test.data.kty, d: test.data.d, x: test.data.x, d: test.data.d};
data.use = "invalid";
var usages = validUsages(vector, 'jwk', test.data);
if (usages.length !== 0)
testError('jwk', algorithm, data, name, usages, true, "DataError", "Invalid 'use' field");
}
});
});
});
// The 'crv' field is incorrect.
testVectors.forEach(function(vector) {
var name = vector.name;
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
if (test.format === "jwk") {
var data = {crv: test.data.crv, kty: test.data.kty, d: test.data.d, x: test.data.x, y: test.data.y};
data.crv = getMismatchedCrvField(algorithm)
var usages = validUsages(vector, 'jwk', test.data);
testError('jwk', algorithm, data, name, usages, true, "DataError", "Invalid 'crv' field");
}
});
});
});
// Use an 'alg' field with incorrect casing.
testVectors.forEach(function(vector) {
var name = vector.name;
if (name !== "Ed25519" && name !== "Ed448")
return; // The rest ignore the 'alg' field.
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
getValidKeyData(algorithm).forEach(function(test) {
if (test.format === "jwk") {
var data = {crv: test.data.crv, kty: test.data.kty, d: test.data.d, x: test.data.x, y: test.data.y};
var usages = validUsages(vector, 'jwk', test.data);
[name.toLowerCase(), name.toUpperCase()].forEach(function(algName) {
data.alg = algName;
testError('jwk', algorithm, data, name, usages, true, "DataError", "Invalid 'alg' field '" + data.alg + "'");
});
}
});
});
});
}

View File

@ -0,0 +1,220 @@
var subtle = crypto.subtle;
function runTests(algorithmName) {
var algorithm = {name: algorithmName};
var data = keyData[algorithmName];
var jwkData = {jwk: {kty: data.jwk.kty, crv: data.jwk.crv, x: data.jwk.x}};
[true, false].forEach(function(extractable) {
// Test public keys first
allValidUsages(data.publicUsages, true).forEach(function(usages) {
['spki', 'jwk', 'raw'].forEach(function(format) {
if (format === "jwk") { // Not all fields used for public keys
testFormat(format, algorithm, jwkData, algorithmName, usages, extractable);
// Test for https://github.com/w3c/webcrypto/pull/401
if (extractable) {
testJwkAlgBehaviours(algorithm, jwkData.jwk, algorithmName, usages);
}
} else {
testFormat(format, algorithm, data, algorithmName, usages, extractable);
}
});
});
// Next, test private keys
allValidUsages(data.privateUsages).forEach(function(usages) {
['pkcs8', 'jwk'].forEach(function(format) {
testFormat(format, algorithm, data, algorithmName, usages, extractable);
// Test for https://github.com/w3c/webcrypto/pull/401
if (format === "jwk" && extractable) {
testJwkAlgBehaviours(algorithm, data.jwk, algorithmName, usages);
}
});
});
});
}
// 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) {
[algorithm, algorithm.name].forEach((alg) => {
promise_test(function(test) {
return subtle.importKey(format, keyData[format], alg, extractable, usages).
then(function(key) {
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData[format].d)) ? 'private' : 'public');
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], alg, extractable, usages));
});
}
// Test importKey/exportKey "alg" behaviours (https://github.com/w3c/webcrypto/pull/401)
// - alg is ignored for ECDH import
// - TODO: alg is checked to be the algorithm.name or EdDSA for Ed25519 and Ed448 import
// - alg is missing for ECDH export
// - alg is the algorithm name for Ed25519 and Ed448 export
function testJwkAlgBehaviours(algorithm, keyData, crv, usages) {
[algorithm, algorithm.name].forEach((alg) => {
(crv.startsWith('Ed') ? [algorithm.name, 'EdDSA'] : ['this is ignored']).forEach((jwkAlg) => {
promise_test(function(test) {
return subtle.importKey('jwk', { ...keyData, alg: jwkAlg }, alg, true, usages).
then(function(key) {
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
return subtle.exportKey('jwk', key).
then(function(result) {
let expectedKeys = crv.startsWith('Ed') ? 6 : 5
if (keyData.d) expectedKeys++
assert_equals(Object.keys(result).length, expectedKeys, "Correct number of JWK members");
assert_equals(result.alg, crv.startsWith('Ed') ? algorithm.name : undefined, 'Expected JWK "alg" member');
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 with JWK alg' + (crv.startsWith('Ed') ? ` ${jwkAlg}: ` : ': ') + crv.toString() + " " + parameterString('jwk', keyData, alg, true, usages, jwkAlg));
});
});
}
// 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, "");
}
// 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(", ") + "}";
}

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: importKey() for OKP keys
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_fixtures.js
// META: script=okp_importKey.js
// Test importKey and exportKey for OKP algorithms.
runTests("Ed25519");

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: importKey() for OKP keys
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_fixtures.js
// META: script=okp_importKey.js
// Test importKey and exportKey for OKP algorithms.
runTests("Ed448");

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: importKey() for OKP keys
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_fixtures.js
// META: script=okp_importKey.js
// Test importKey and exportKey for OKP algorithms.
runTests("X25519");

View File

@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: importKey() for OKP keys
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_fixtures.js
// META: script=okp_importKey.js
// Test importKey and exportKey for OKP algorithms.
runTests("X448");

View File

@ -0,0 +1,7 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures_fixtures.js
// META: script=importKey_failures.js
run_test(["Ed25519"]);

View File

@ -0,0 +1,8 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures_fixtures.js
// META: script=importKey_failures.js
run_test(["Ed448"]);

View File

@ -0,0 +1,8 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures_fixtures.js
// META: script=importKey_failures.js
run_test(["X25519"]);

View File

@ -0,0 +1,8 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures_fixtures.js
// META: script=importKey_failures.js
run_test(["X448"]);

View File

@ -0,0 +1,438 @@
// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
function getValidKeyData(algorithm) {
return validKeyData[algorithm.name];
}
function getBadKeyLengthData(algorithm) {
return badKeyLengthData[algorithm.name];
}
function getMissingJWKFieldKeyData(algorithm) {
return missingJWKFieldKeyData[algorithm.name];
}
function getMismatchedJWKKeyData(algorithm) {
return mismatchedJWKKeyData[algorithm.name];
}
function getMismatchedKtyField(algorithm) {
return mismatchedKtyField[algorithm.name];
}
function getMismatchedCrvField(algorithm) {
return mismatchedCrvField[algorithm.name];
}
var validKeyData = {
"Ed25519": [
{
format: "spki",
data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204])
},
{
format: "pkcs8",
data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31])
},
{
format: "raw",
data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204])
},
{
format: "jwk",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed25519",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
},
}
],
"Ed448": [
{
format: "spki",
data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]),
},
{
format: "raw",
data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]),
},
{
format: "jwk",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed448",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
],
"X25519": [
{
format: "spki",
data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
},
{
format: "raw",
data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
},
{
format: "jwk",
data: {
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "X25519",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
kty: "OKP"
},
},
],
"X448": [
{
format: "spki",
data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]),
},
{
format: "raw",
data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]),
},
{
format: "jwk",
data: {
crv: "X448",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "X448",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
kty: "OKP"
},
},
],
};
// Removed just the last byte.
var badKeyLengthData = {
"Ed25519": [
{
format: "spki",
data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61])
},
{
format: "pkcs8",
data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168])
},
{
format: "raw",
data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61])
},
{
format: "jwk",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
}
},
{
format: "jwk",
data: {
crv: "Ed25519",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPc",
kty: "OKP"
}
}
],
"Ed448": [
{
format: "spki",
data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29]),
},
{
format: "raw",
data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]),
},
{
format: "jwk",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed448",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalq",
kty: "OKP"
},
},
],
"X25519": [
{
format: "spki",
data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255]),
},
{
format: "raw",
data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]),
},
{
format: "jwk",
data: {
crv: "X25519",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lw",
kty: "OKP"
}
},
{
format: "jwk",
data: {
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
kty: "OKP"
},
},
],
"X448": [
{
format: "spki",
data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]),
},
{
format: "pkcs8",
data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146]),
},
{
format: "raw",
data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]),
},
{
format: "jwk",
data: {
crv: "X448",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "X448",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm",
kty: "OKP"
},
},
],
};
var missingJWKFieldKeyData = {
"Ed25519": [
{
param: "x",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
kty: "OKP"
},
},
{
param: "kty",
data: {
crv: "Ed25519",
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
},
},
{
param: "crv",
data: {
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
kty: "OKP"
},
}
],
"Ed448": [
{
param: "x",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
kty: "OKP"
}
},
{
param: "kty",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
}
},
{
param: "crv",
data: {
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
}
}
],
"X25519": [
{
param: "x",
data: {
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
kty: "OKP"
},
},
{
param: "kty",
data: {
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
},
},
{
param: "crv",
data: {
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
kty: "OKP"
},
}
],
"X448": [
{
param: "x",
data: {
crv: "X448",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
kty: "OKP"
}
},
{
param: "kty",
data: {
crv: "X448",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
}
},
{
param: "crv",
data: {
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
kty: "OKP"
}
}
],
};
// The public key doesn't match the private key.
var mismatchedJWKKeyData = {
"Ed25519": [
{
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
kty: "OKP"
},
],
"Ed448": [
{
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA",
kty: "OKP"
},
],
"X25519": [
{
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
x: "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo",
kty: "OKP"
},
],
"X448": [
{
crv: "X448",
kty: "OKP",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
x: "mwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3+A5TLEH6A",
},
],
}
// The 'kty' field doesn't match the key algorithm.
var mismatchedKtyField = {
"Ed25519": "EC",
"X25519": "EC",
"Ed448": "EC",
"X448": "EC",
}
// The 'kty' field doesn't match the key algorithm.
var mismatchedCrvField = {
"Ed25519": "X25519",
"X25519": "Ed448",
"Ed448": "X25519",
"X448": "Ed25519",
}

View File

@ -0,0 +1,58 @@
var keyData = {
"Ed25519": {
privateUsages: ["sign"],
publicUsages: ["verify"],
spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]),
raw: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]),
pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]),
jwk: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
}
},
"Ed448": {
privateUsages: ["sign"],
publicUsages: ["verify"],
spki: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]),
raw: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]),
pkcs8: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]),
jwk: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
}
},
"X25519": {
privateUsages: ["deriveKey", "deriveBits"],
publicUsages: [],
spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
raw: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
jwk: {
crv: "X25519",
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
kty: "OKP"
}
},
"X448": {
privateUsages: ["deriveKey", "deriveBits"],
publicUsages: [],
spki: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]),
raw: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]),
pkcs8: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]),
jwk: {
crv: "X448",
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
kty: "OKP"
}
},
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,222 @@
// META: title=WebCryptoAPI: importKey() for symmetric keys
// META: timeout=long
// META: script=../util/helpers.js
// Test importKey and exportKey for non-PKC algorithms. Only "happy paths" are
// currently tested - those where the operation should succeed.
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) {
// 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);
}
// Generate all combinations of valid usages for testing
allValidUsages(vector.legalUsages).forEach(function(usages) {
testFormat(format, algorithm, data, keyData.length * 8, usages, extractable);
});
testEmptyUsages(format, algorithm, data, keyData.length * 8, extractable);
});
});
});
});
function hasLength(algorithm) {
return algorithm.name === 'HMAC' || algorithm.name.startsWith('AES');
}
// 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");
assert_goodCryptoKey(key, hasLength(key.algorithm) ? { length: keySize, ...algorithm } : algorithm, extractable, usages, 'secret');
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));
}
// Test importKey with a given key format and other parameters but with empty usages.
// Should fail with SyntaxError
function testEmptyUsages(format, algorithm, keyData, keySize, extractable) {
const usages = [];
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_unreached("importKey succeeded but should have failed with SyntaxError");
}, function(err) {
assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
});
}, "Empty Usages: " + 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, "");
}
// 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(", ") + "}";
}

View File

@ -0,0 +1,42 @@
// Run for enough iterations that we're likely to catch edge-cases, like
// failing to set a reserved bit:
const iterations = 256;
// Track all the UUIDs generated during test run, bail if we ever collide:
const uuids = new Set()
function randomUUID() {
const uuid = self.crypto.randomUUID();
if (uuids.has(uuid)) {
throw new Error(`uuid collision ${uuid}`)
}
uuids.add(uuid);
return uuid;
}
// UUID is in namespace format (16 bytes separated by dashes):
test(function() {
const UUIDRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
for (let i = 0; i < iterations; i++) {
assert_true(UUIDRegex.test(randomUUID()));
}
}, "namespace format");
// Set the 4 most significant bits of array[6], which represent the UUID
// version, to 0b0100:
test(function() {
for (let i = 0; i < iterations; i++) {
let value = parseInt(randomUUID().split('-')[2].slice(0, 2), 16);
value &= 0b11110000;
assert_true(value === 0b01000000);
}
}, "version set");
// Set the 2 most significant bits of array[8], which represent the UUID
// variant, to 0b10:
test(function() {
for (let i = 0; i < iterations; i++) {
// Grab the byte representing array[8]:
let value = parseInt(randomUUID().split('-')[3].slice(0, 2), 16);
value &= 0b11000000
assert_true(value === 0b10000000);
}
}, "variant set");

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<script>
async_test(function(t) {
assert_not_equals(typeof crypto.subtle, 'undefined');
t.done();
}, "Secure context window has access to crypto.subtle");
async_test(function(t) {
var w = new Worker('../util/worker-report-crypto-subtle-presence.js');
w.onmessage = t.step_func(function (e) {
if (e.data.msg_type == 'subtle_crypto_found') {
assert_equals(e.data.msg_value, true);
t.done();
}
});
}, "Secure context worker has access to crypto.subtle");
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: sign() and verify() Using ECDSA
// META: script=ecdsa_vectors.js
// META: script=ecdsa.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,509 @@
function run_test() {
setup({explicit_done: true});
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();
var invalidTestVectors = getInvalidTestVectors();
// 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);
});
// Test invalid signatures
invalidTestVectors.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_false(is_verified, "Signature unexpectedly 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);
});
promise_test(function() {
return Promise.all(all_promises)
.then(function() {done();})
.catch(function() {done();})
}, "setup");
// 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;
}

View File

@ -0,0 +1,139 @@
// 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])
}
}
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;
}
// Additional test vectors, using the same format as getTestVectors, but the
// signatures are invalid.
function getInvalidTestVectors() {
var vectors = [];
for (const validVector of getTestVectors()) {
{
const vector = structuredClone(validVector);
vector.name = `${vector.name} - The signature was truncated by 1 byte`;
vector.signature = vector.signature.subarray(0, vector.signature.byteLength - 1);
vectors.push(vector);
}
// The signature was made with a different algorithm
for (const hashName of ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]) {
if (validVector.hashName === hashName) continue;
const vector = structuredClone(validVector);
vector.name = `${vector.name} - The signature was made using ${vector.hashName}, however verification is being done using ${hashName}`;
vector.hashName = hashName;
vectors.push(vector);
}
{
// Excess padding
const vector = structuredClone(validVector);
vector.name = `${vector.name} - Signature has excess padding`;
const r = vector.signature.subarray(0, vector.signature.byteLength / 2);
const s = vector.signature.subarray(vector.signature.byteLength);
vector.signature = new Uint8Array([
0, ...r,
0, ...s,
]);
vectors.push(vector);
}
{
// Empty signature
const vector = structuredClone(validVector);
vector.name = `${vector.name} - The signature is empty`;
vector.signature = new Uint8Array();
vectors.push(vector);
}
{
// Zeroed signature
const vector = structuredClone(validVector);
vector.name = `${vector.name} - The signature is all zeroes`;
vector.signature = new Uint8Array(vector.signature.byteLength);
vectors.push(vector);
}
}
return vectors;
}

View File

@ -0,0 +1,233 @@
function run_test(algorithmName) {
var subtle = self.crypto.subtle; // Change to test prefixed implementations
// Source file [algorithm_name]_vectors.js provides the getTestVectors method
// for the algorithm that drives these tests.
var testVectors = getTestVectors(algorithmName);
testVectors.forEach(function(vector) {
var algorithm = {name: vector.algorithmName};
// Test verification first, because signing tests rely on that working
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data)
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_true(isVerified, "Signature verified");
}, vector.name + " verification");
// Test verification with an altered buffer after call
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
var signature = copyBuffer(vector.signature);
[isVerified] = await Promise.all([
subtle.verify(algorithm, key, signature, vector.data),
signature[0] = 255 - signature[0]
]);
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_true(isVerified, "Signature verified");
}, vector.name + " verification with altered signature after call");
// Check for successful verification even if data is altered after call.
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
var data = copyBuffer(vector.data);
[isVerified] = await Promise.all([
subtle.verify(algorithm, key, vector.signature, data),
data[0] = 255 - data[0]
]);
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_true(isVerified, "Signature verified");
}, vector.name + " with altered data after call");
// Check for failures due to using privateKey to verify.
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]);
isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data)
assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name);
} catch (err) {
if (err instanceof AssertionError)
throw err;
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
};
assert_false(isVerified, "Signature verified");
}, vector.name + " using privateKey to verify");
// Check for failures due to using publicKey to sign.
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
let signature = await subtle.sign(algorithm, key, vector.data);
assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name);
} catch (err) {
if (err instanceof AssertionError)
throw err;
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
};
}, vector.name + " using publicKey to sign");
// Check for failures due to no "verify" usage.
promise_test(async() => {
let isVerified = false;
let key;
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, []);
isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data)
assert_unreached("Should have thrown error for no verify usage in " + vector.name);
} catch (err) {
if (err instanceof AssertionError)
throw err;
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'");
};
assert_false(isVerified, "Signature verified");
}, vector.name + " no verify usage");
// Check for successful signing and verification.
var algorithm = {name: vector.algorithmName};
promise_test(async() => {
let isVerified = false;
let privateKey, publicKey;
let signature;
try {
privateKey = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]);
publicKey = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
signature = await subtle.sign(algorithm, privateKey, vector.data);
isVerified = await subtle.verify(algorithm, publicKey, vector.signature, vector.data)
} catch (err) {
assert_false(publicKey === undefined || privateKey === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_false(signature === undefined, "sign error for test " + vector.name + ": '" + err.message + "'");
assert_unreached("verify error for test " + vector.name + ": " + err.message + "'");
};
assert_true(isVerified, "Round trip verification works");
}, vector.name + " round trip");
// Test signing with the wrong algorithm
var algorithm = {name: vector.algorithmName};
promise_test(async() => {
let wrongKey;
try {
wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"])
let signature = await subtle.sign(algorithm, wrongKey, vector.data);
assert_unreached("Signing should not have succeeded for " + vector.name);
} catch (err) {
if (err instanceof AssertionError)
throw err;
assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
};
}, vector.name + " signing with wrong algorithm name");
// Test verification with the wrong algorithm
var algorithm = {name: vector.algorithmName};
promise_test(async() => {
let wrongKey;
try {
wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"])
let isVerified = await subtle.verify(algorithm, wrongKey, vector.signature, vector.data)
assert_unreached("Verifying should not have succeeded for " + vector.name);
} catch (err) {
if (err instanceof AssertionError)
throw err;
assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'");
assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'");
};
}, vector.name + " verifying with wrong algorithm name");
// Test verification fails with wrong signature
var algorithm = {name: vector.algorithmName};
promise_test(async() => {
let key;
let isVerified = true;
var signature = copyBuffer(vector.signature);
signature[0] = 255 - signature[0];
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
isVerified = await subtle.verify(algorithm, key, signature, vector.data)
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_false(isVerified, "Signature verified");
}, vector.name + " verification failure due to altered signature");
// Test verification fails with short (odd length) signature
promise_test(async() => {
let key;
let isVerified = true;
var signature = vector.signature.slice(1); // Skip the first byte
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
isVerified = await subtle.verify(algorithm, key, signature, vector.data)
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_false(isVerified, "Signature verified");
}, vector.name + " verification failure due to shortened signature");
// Test verification fails with wrong data
promise_test(async() => {
let key;
let isVerified = true;
var data = copyBuffer(vector.data);
data[0] = 255 - data[0];
try {
key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]);
isVerified = await subtle.verify(algorithm, key, vector.signature, data)
} catch (err) {
assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''");
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
};
assert_false(isVerified, "Signature verified");
}, vector.name + " verification failure due to altered data");
// Test that generated keys are valid for signing and verifying.
promise_test(async() => {
let key = await subtle.generateKey(algorithm, false, ["sign", "verify"]);
let signature = await subtle.sign(algorithm, key.privateKey, vector.data);
let isVerified = await subtle.verify(algorithm, key.publicKey, signature, vector.data);
assert_true(isVerified, "Verificaton failed.");
}, "Sign and verify using generated " + vector.algorithmName + " keys.");
});
// 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;
}
return;
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: sign() and verify() Using EdDSA
// META: script=eddsa_vectors.js
// META: script=eddsa.js
// META: timeout=long
run_test("Ed25519");

Some files were not shown because too many files have changed in this diff Show More