diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index cba3d03b9038fd..ec0ce5730a48f9 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -34,7 +34,7 @@ Last update: - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi - web-locks: https://github.com/web-platform-tests/wpt/tree/10a122a6bc/web-locks -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/0acea989ac/WebCryptoAPI +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/caebe89c3b/WebCryptoAPI - webidl: https://github.com/web-platform-tests/wpt/tree/63ca529a02/webidl - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/2f96fa1996/webidl/ecmascript-binding/es-exceptions - webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.js index f1609403d623fa..de3b4b5920df27 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.js @@ -51,7 +51,6 @@ function define_tests() { var algorithmName = vector.algorithm; var password = vector.password; - // Key for normal operations promises.push( subtle .importKey('raw-secret', password, algorithmName, false, [ @@ -70,20 +69,3 @@ function define_tests() { }); } } - -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aView = new Uint8Array(a); - var bView = new Uint8Array(b); - - for (var i = 0; i < aView.length; i++) { - if (aView[i] !== bView[i]) { - return false; - } - } - - return true; -} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js index 55fb11c995653e..9422c39c958a06 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js @@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: deriveBits() Using Argon2 // META: timeout=long +// META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=argon2_vectors.js // META: script=argon2.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js index 9b9acda5f42d3a..93d26b5eb96980 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js @@ -2,7 +2,6 @@ function getTestData() { // Test vectors from RFC 9106 // https://www.rfc-editor.org/rfc/rfc9106 - // Test vectors from RFC 9106 var testVectors = [ // Argon2d test vector { diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js index 8ab9db7bf71318..1406e8bf0a1928 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js @@ -224,37 +224,4 @@ function define_tests(algorithmName) { .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> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js index 866192e0193bc1..5684d7624076c7 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_bits.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js index 32485c68107e5c..5e482ef0b9d804 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_bits.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js index 62f9e00aa33846..cefc45ac692903 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js @@ -221,37 +221,4 @@ function define_tests(algorithmName) { .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> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js index 91390ba5c2a17a..8bcc201d4e95ec 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_keys.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js index b34e366376a70f..0ed3954ac200b5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_keys.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js index 0aee2e3c172d30..862945c6a316c6 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveBits() tests for the 'length' parameter +// META: script=../util/helpers.js // META: script=derived_bits_length.js // META: script=derived_bits_length_vectors.js // META: script=derived_bits_length_testcases.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js index 37e3eb4324200c..58a0cecd5efed6 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveBits() Using ECDH +// META: script=../util/helpers.js // META: script=ecdh_bits.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js index 36b29c20a282ab..8e79909020d398 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js @@ -230,37 +230,4 @@ function define_tests() { .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> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js index d8235fce5a7412..6464dacfe3aa81 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH +// META: script=../util/helpers.js // META: script=ecdh_keys.js // Define subtests from a `promise_test` to ensure the harness does not diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js index fce76f185530ac..8c3d2aeb5a4976 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js @@ -209,37 +209,4 @@ function define_tests() { .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> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - } diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js index 02492c3741c7d1..3879ddb14b903a 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js @@ -3,6 +3,7 @@ // META: variant=?1001-2000 // META: variant=?2001-3000 // META: variant=?3001-last +// META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=hkdf_vectors.js // META: script=hkdf.js diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js index 0384f88ec73e43..08e8c0c8974617 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js @@ -275,21 +275,4 @@ function define_tests() { }); } - 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 0) { + promise_test(function (test) { + var buffer = new Uint8Array(input); + // Alter the buffer before calling digest + buffer[0] = ~buffer[0]; + return subtle + .digest({ + get name() { + // Alter the buffer back while calling digest + buffer[0] = input[0]; + return alg; + }, + outputLength: outputLength, + customization: customization, + }, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label + ' and altered buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Alter the buffer after calling digest + buffer[0] = ~buffer[0]; + return promise; + }, label + ' and altered buffer after call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + return subtle + .digest({ + get name() { + // Transfer the buffer while calling digest + buffer.buffer.transfer(); + return alg; + }, + outputLength: outputLength, + customization: customization, + }, buffer) + .then(function (result) { + if (customizationEqual(emptyDataVector, customization) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { + assert_true( + equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), + 'digest on transferred buffer should match result for empty buffer' + ); + } else { + assert_equals(result.byteLength, outputLength / 8, + 'digest on transferred buffer should have correct output length'); + } + }); + }, label + ' and transferred buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Transfer the buffer after calling digest + buffer.buffer.transfer(); + return promise; + }, label + ' and transferred buffer after call'); + } + }); +}); diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js index 4ae99791b8c95f..f9f38eadc2c39a 100644 --- a/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js @@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: digest() SHA-3 algorithms +// META: script=../util/helpers.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations @@ -176,17 +177,3 @@ Object.keys(sourceData).forEach(function (size) { } }); }); - -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; -} diff --git a/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js new file mode 100644 index 00000000000000..243931cd119802 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js @@ -0,0 +1,297 @@ +// META: title=WebCryptoAPI: digest() TurboSHAKE algorithms +// META: script=../util/helpers.js +// META: timeout=long + +var subtle = crypto.subtle; // Change to test prefixed implementations + +// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. +function ptn(n) { + var buf = new Uint8Array(n); + for (var i = 0; i < n; i++) + buf[i] = i % 251; + return buf; +} + +function hexToBytes(hex) { + var bytes = new Uint8Array(hex.length / 2); + for (var i = 0; i < hex.length; i += 2) + bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); + return bytes; +} + +// RFC 9861 Section 5 test vectors +// [input, outputLengthBits, expected hex(, domainSeparation)] +var turboSHAKE128Vectors = [ + [new Uint8Array(0), 256, + '1e415f1c5983aff2169217277d17bb53' + + '8cd945a397ddec541f1ce41af2c1b74c'], + [new Uint8Array(0), 512, + '1e415f1c5983aff2169217277d17bb53' + + '8cd945a397ddec541f1ce41af2c1b74c' + + '3e8ccae2a4dae56c84a04c2385c03c15' + + 'e8193bdf58737363321691c05462c8df'], + [ptn(1), 256, + '55cedd6f60af7bb29a4042ae832ef3f5' + + '8db7299f893ebb9247247d856958daa9'], + [ptn(17), 256, + '9c97d036a3bac819db70ede0ca554ec6' + + 'e4c2a1a4ffbfd9ec269ca6a111161233'], + [ptn(Math.pow(17, 2)), 256, + '96c77c279e0126f7fc07c9b07f5cdae1' + + 'e0be60bdbe10620040e75d7223a624d2'], + [ptn(Math.pow(17, 3)), 256, + 'd4976eb56bcf118520582b709f73e1d6' + + '853e001fdaf80e1b13e0d0599d5fb372'], + [ptn(Math.pow(17, 4)), 256, + 'da67c7039e98bf530cf7a37830c6664e' + + '14cbab7f540f58403b1b82951318ee5c'], + [ptn(Math.pow(17, 5)), 256, + 'b97a906fbf83ef7c812517abf3b2d0ae' + + 'a0c4f60318ce11cf103925127f59eecd'], + [ptn(Math.pow(17, 6)), 256, + '35cd494adeded2f25239af09a7b8ef0c' + + '4d1ca4fe2d1ac370fa63216fe7b4c2b1'], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + 'bf323f940494e88ee1c540fe660be8a0' + + 'c93f43d15ec006998462fa994eed5dab', 0x01], + [new Uint8Array([0xff]), 256, + '8ec9c66465ed0d4a6c35d13506718d68' + + '7a25cb05c74cca1e42501abd83874a67', 0x06], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + 'b658576001cad9b1e5f399a9f77723bb' + + 'a05458042d68206f7252682dba3663ed', 0x07], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 256, + '8deeaa1aec47ccee569f659c21dfa8e1' + + '12db3cee37b18178b2acd805b799cc37', 0x0b], + [new Uint8Array([0xff]), 256, + '553122e2135e363c3292bed2c6421fa2' + + '32bab03daa07c7d6636603286506325b', 0x30], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + '16274cc656d44cefd422395d0f9053bd' + + 'a6d28e122aba15c765e5ad0e6eaf26f9', 0x7f], +]; + +var turboSHAKE256Vectors = [ + [new Uint8Array(0), 512, + '367a329dafea871c7802ec67f905ae13' + + 'c57695dc2c6663c61035f59a18f8e7db' + + '11edc0e12e91ea60eb6b32df06dd7f00' + + '2fbafabb6e13ec1cc20d995547600db0'], + [ptn(1), 512, + '3e1712f928f8eaf1054632b2aa0a246e' + + 'd8b0c378728f60bc970410155c28820e' + + '90cc90d8a3006aa2372c5c5ea176b068' + + '2bf22bae7467ac94f74d43d39b0482e2'], + [ptn(17), 512, + 'b3bab0300e6a191fbe61379398359235' + + '78794ea54843f5011090fa2f3780a9e5' + + 'cb22c59d78b40a0fbff9e672c0fbe097' + + '0bd2c845091c6044d687054da5d8e9c7'], + [ptn(Math.pow(17, 2)), 512, + '66b810db8e90780424c0847372fdc957' + + '10882fde31c6df75beb9d4cd9305cfca' + + 'e35e7b83e8b7e6eb4b78605880116316' + + 'fe2c078a09b94ad7b8213c0a738b65c0'], + [ptn(Math.pow(17, 3)), 512, + 'c74ebc919a5b3b0dd1228185ba02d29e' + + 'f442d69d3d4276a93efe0bf9a16a7dc0' + + 'cd4eabadab8cd7a5edd96695f5d360ab' + + 'e09e2c6511a3ec397da3b76b9e1674fb'], + [ptn(Math.pow(17, 4)), 512, + '02cc3a8897e6f4f6ccb6fd46631b1f52' + + '07b66c6de9c7b55b2d1a23134a170afd' + + 'ac234eaba9a77cff88c1f020b7372461' + + '8c5687b362c430b248cd38647f848a1d'], + [ptn(Math.pow(17, 5)), 512, + 'add53b06543e584b5823f626996aee50' + + 'fe45ed15f20243a7165485acb4aa76b4' + + 'ffda75cedf6d8cdc95c332bd56f4b986' + + 'b58bb17d1778bfc1b1a97545cdf4ec9f'], + [ptn(Math.pow(17, 6)), 512, + '9e11bc59c24e73993c1484ec66358ef7' + + '1db74aefd84e123f7800ba9c4853e02c' + + 'fe701d9e6bb765a304f0dc34a4ee3ba8' + + '2c410f0da70e86bfbd90ea877c2d6104'], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + 'd21c6fbbf587fa2282f29aea620175fb' + + '0257413af78a0b1b2a87419ce031d933' + + 'ae7a4d383327a8a17641a34f8a1d1003' + + 'ad7da6b72dba84bb62fef28f62f12424', 0x01], + [new Uint8Array([0xff]), 512, + '738d7b4e37d18b7f22ad1b5313e357e3' + + 'dd7d07056a26a303c433fa3533455280' + + 'f4f5a7d4f700efb437fe6d281405e07b' + + 'e32a0a972e22e63adc1b090daefe004b', 0x06], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + '18b3b5b7061c2e67c1753a00e6ad7ed7' + + 'ba1c906cf93efb7092eaf27fbeebb755' + + 'ae6e292493c110e48d260028492b8e09' + + 'b5500612b8f2578985ded5357d00ec67', 0x07], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 512, + 'bb36764951ec97e9d85f7ee9a67a7718' + + 'fc005cf42556be79ce12c0bde50e5736' + + 'd6632b0d0dfb202d1bbb8ffe3dd74cb0' + + '0834fa756cb03471bab13a1e2c16b3c0', 0x0b], + [new Uint8Array([0xff]), 512, + 'f3fe12873d34bcbb2e608779d6b70e7f' + + '86bec7e90bf113cbd4fdd0c4e2f4625e' + + '148dd7ee1a52776cf77f240514d9ccfc' + + '3b5ddab8ee255e39ee389072962c111a', 0x30], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + 'abe569c1f77ec340f02705e7d37c9ab7' + + 'e155516e4a6a150021d70b6fac0bb40c' + + '069f9a9828a0d575cd99f9bae435ab1a' + + 'cf7ed9110ba97ce0388d074bac768776', 0x7f], +]; + +// Large output tests: verify last 32 bytes of extended output +var largeOutputTests = [ + // [algorithm, outputLengthBits, lastNBytes, expectedLastBytes] + ['TurboSHAKE128', 10032 * 8, 32, + 'a3b9b0385900ce761f22aed548e754da' + + '10a5242d62e8c658e3f3a923a7555607'], + ['TurboSHAKE256', 10032 * 8, 32, + 'abefa11630c661269249742685ec082f' + + '207265dccf2f43534e9c61ba0c9d1d75'], +]; + +largeOutputTests.forEach(function (entry) { + var alg = entry[0]; + var outputLength = entry[1]; + var lastN = entry[2]; + var expected = entry[3]; + + promise_test(function (test) { + return subtle + .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) + .then(function (result) { + var full = new Uint8Array(result); + var last = full.slice(full.length - lastN); + assert_true( + equalBuffers(last.buffer, hexToBytes(expected)), + 'last ' + lastN + ' bytes of digest match expected' + ); + }); + }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); +}); + +function domainSeparationEqual(emptyDataVector, domainSeparation) { + return (domainSeparation ?? 0x1f) === (emptyDataVector[3] ?? 0x1f); +} + +function outputLengthLessOrEqual(emptyDataVector, outputLength) { + return outputLength <= emptyDataVector[1]; +} + +var allVectors = { + TurboSHAKE128: turboSHAKE128Vectors, + TurboSHAKE256: turboSHAKE256Vectors, +}; + +Object.keys(allVectors).forEach(function (alg) { + var emptyDataVector = allVectors[alg][0]; + allVectors[alg].forEach(function (vector, i) { + var input = vector[0]; + var outputLength = vector[1]; + var expected = vector[2]; + var domainSeparation = vector[3]; + + var algorithmParams = { name: alg, outputLength: outputLength }; + if (domainSeparation !== undefined) + algorithmParams.domainSeparation = domainSeparation; + + var label = alg + ' vector #' + (i + 1) + + ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + + (domainSeparation !== undefined ? ', D=0x' + domainSeparation.toString(16) : '') + ')'; + + promise_test(function (test) { + return subtle + .digest(algorithmParams, input) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label); + + if (input.length > 0) { + promise_test(function (test) { + var buffer = new Uint8Array(input); + // Alter the buffer before calling digest + buffer[0] = ~buffer[0]; + return subtle + .digest({ + get name() { + // Alter the buffer back while calling digest + buffer[0] = input[0]; + return alg; + }, + outputLength: outputLength, + domainSeparation: domainSeparation, + }, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label + ' and altered buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Alter the buffer after calling digest + buffer[0] = ~buffer[0]; + return promise; + }, label + ' and altered buffer after call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + return subtle + .digest({ + get name() { + // Transfer the buffer while calling digest + buffer.buffer.transfer(); + return alg; + }, + outputLength: outputLength, + domainSeparation: domainSeparation, + }, buffer) + .then(function (result) { + if (domainSeparationEqual(emptyDataVector, domainSeparation) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { + assert_true( + equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), + 'digest on transferred buffer should match result for empty buffer' + ); + } else { + assert_equals(result.byteLength, outputLength / 8, + 'digest on transferred buffer should have correct output length'); + } + }); + }, label + ' and transferred buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Transfer the buffer after calling digest + buffer.buffer.transfer(); + return promise; + }, label + ' and transferred buffer after call'); + } + }); +}); diff --git a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js index ab112e4d497676..5a669753cd2701 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js @@ -73,7 +73,7 @@ function define_bits_tests() { ); }, algorithmName + ' encapsulateBits basic functionality'); - // Test decapsulateBits operation + // Test encapsulateBits/decapsulateBits round-trip compatibility promise_test(async function (test) { // Generate a key pair for testing var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ @@ -109,30 +109,6 @@ function define_bits_tests() { equalBuffers(decapsulatedBits, encapsulatedBits.sharedKey), 'Decapsulated shared secret should match original' ); - }, algorithmName + ' decapsulateBits basic functionality'); - - // Test round-trip compatibility - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - var decapsulatedBits = await subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ); - - assert_true( - equalBuffers(encapsulatedBits.sharedKey, decapsulatedBits), - 'Encapsulated and decapsulated shared secrets should match' - ); }, algorithmName + ' encapsulateBits/decapsulateBits round-trip compatibility'); @@ -175,19 +151,4 @@ function define_bits_tests() { }); } -// Helper function to compare two ArrayBuffers -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; -} - define_bits_tests(); diff --git a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js index 4ccb0585b84f87..0a45c1fc4e9f6f 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js @@ -38,313 +38,318 @@ function define_key_tests() { variants.forEach(function (algorithmName) { sharedKeyConfigs.forEach(function (config) { - // Test encapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // Test encapsulateKey - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); - - assert_true( - encapsulatedKey instanceof Object, - 'encapsulateKey should return an object' - ); - assert_true( - encapsulatedKey.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedKey.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedKey.sharedKey instanceof CryptoKey, - 'sharedKey should be a CryptoKey' - ); - assert_true( - encapsulatedKey.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); - - // Verify the shared key properties - assert_equals( - encapsulatedKey.sharedKey.type, - 'secret', - 'Shared key should be secret type' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.name, - config.algorithm.name, - 'Shared key algorithm should match' - ); - assert_true( - encapsulatedKey.sharedKey.extractable, - 'Shared key should be extractable as specified' - ); - assert_array_equals( - encapsulatedKey.sharedKey.usages, - config.usages, - 'Shared key should have correct usages' - ); - - // Verify algorithm-specific properties - if (config.algorithm.length) { + [true, false].forEach(function (extractable) { + // Test encapsulateKey operation + promise_test(async function (test) { + // Generate a key pair for testing + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); + + // Test encapsulateKey + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); + + assert_true( + encapsulatedKey instanceof Object, + 'encapsulateKey should return an object' + ); + assert_true( + encapsulatedKey.hasOwnProperty('sharedKey'), + 'Result should have sharedKey property' + ); + assert_true( + encapsulatedKey.hasOwnProperty('ciphertext'), + 'Result should have ciphertext property' + ); + assert_true( + encapsulatedKey.sharedKey instanceof CryptoKey, + 'sharedKey should be a CryptoKey' + ); + assert_true( + encapsulatedKey.ciphertext instanceof ArrayBuffer, + 'ciphertext should be ArrayBuffer' + ); + + // Verify the shared key properties assert_equals( - encapsulatedKey.sharedKey.algorithm.length, - config.algorithm.length, - 'Key length should be 256' + encapsulatedKey.sharedKey.type, + 'secret', + 'Shared key should be secret type' ); - } - if (config.algorithm.hash) { assert_equals( - encapsulatedKey.sharedKey.algorithm.hash.name, - config.algorithm.hash, - 'Hash algorithm should match' + encapsulatedKey.sharedKey.algorithm.name, + config.algorithm.name, + 'Shared key algorithm should match' ); - } - - // Verify ciphertext length based on algorithm variant - var expectedCiphertextLength; - switch (algorithmName) { - case 'ML-KEM-512': - expectedCiphertextLength = 768; - break; - case 'ML-KEM-768': - expectedCiphertextLength = 1088; - break; - case 'ML-KEM-1024': - expectedCiphertextLength = 1568; - break; - } - assert_equals( - encapsulatedKey.ciphertext.byteLength, - expectedCiphertextLength, - 'Ciphertext should be ' + - expectedCiphertextLength + - ' bytes for ' + - algorithmName - ); - }, algorithmName + ' encapsulateKey with ' + config.description); - - // Test decapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // First encapsulate to get ciphertext - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); - - // Then decapsulate using the private key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - config.algorithm, - true, - config.usages - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - config.algorithm.name, - 'Decapsulated key algorithm should match' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - config.usages, - 'Decapsulated key should have correct usages' - ); - - // Extract both keys and verify they are identical - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Decapsulated key material should match original' - ); - - // Verify the key material is 32 bytes (256 bits) - assert_equals( - originalKeyMaterial.byteLength, - 32, - 'Shared key material should be 32 bytes' - ); - }, algorithmName + ' decapsulateKey with ' + config.description); - - // Test round-trip compatibility - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); - - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - config.algorithm, - true, - config.usages - ); - - // Verify keys have the same material - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Encapsulated and decapsulated keys should have the same material' - ); - - // Test that the derived keys can actually be used for their intended purpose - if ( - config.algorithm.name.startsWith('AES') && - config.usages.includes('encrypt') - ) { - await testAESOperation( - encapsulatedKey.sharedKey, - decapsulatedKey, - config.algorithm + assert_equals( + encapsulatedKey.sharedKey.extractable, + extractable, + 'Shared key should have correct extractable property' + ); + assert_array_equals( + encapsulatedKey.sharedKey.usages, + config.usages, + 'Shared key should have correct usages' ); - } else if (config.algorithm.name === 'HMAC') { - await testHMACOperation(encapsulatedKey.sharedKey, decapsulatedKey); - } - }, algorithmName + - ' encapsulateKey/decapsulateKey round-trip with ' + - config.description); - }); - // Test vector-based decapsulation for each shared key config - sharedKeyConfigs.forEach(function (config) { - promise_test(async function (test) { - var vectors = ml_kem_vectors[algorithmName]; - - // Import the private key from the vector's privateSeed - var privateKey = await subtle.importKey( - 'raw-seed', - vectors.privateSeed, - { name: algorithmName }, - false, - ['decapsulateKey'] - ); - - // Decapsulate the sample ciphertext from the vectors to get a shared key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - privateKey, - vectors.sampleCiphertext, - config.algorithm, - true, - config.usages - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - config.algorithm.name, - 'Decapsulated key algorithm should match' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - config.usages, - 'Decapsulated key should have correct usages' - ); - - // Extract the key material and verify it matches the expected shared secret - var keyMaterial = await subtle.exportKey('raw', decapsulatedKey); - assert_equals( - keyMaterial.byteLength, - 32, - 'Shared key material should be 32 bytes' - ); - assert_true( - equalBuffers(keyMaterial, vectors.expectedSharedSecret), - "Decapsulated key material should match vector's expectedSharedSecret" - ); - - // Verify algorithm-specific properties - if (config.algorithm.length) { + // Verify algorithm-specific properties + if (config.algorithm.length) { + assert_equals( + encapsulatedKey.sharedKey.algorithm.length, + config.algorithm.length, + 'Key length should be 256' + ); + } + if (config.algorithm.hash) { + assert_equals( + encapsulatedKey.sharedKey.algorithm.hash.name, + config.algorithm.hash, + 'Hash algorithm should match' + ); + } + + // Verify ciphertext length based on algorithm variant + var expectedCiphertextLength; + switch (algorithmName) { + case 'ML-KEM-512': + expectedCiphertextLength = 768; + break; + case 'ML-KEM-768': + expectedCiphertextLength = 1088; + break; + case 'ML-KEM-1024': + expectedCiphertextLength = 1568; + break; + } + assert_equals( + encapsulatedKey.ciphertext.byteLength, + expectedCiphertextLength, + 'Ciphertext should be ' + + expectedCiphertextLength + + ' bytes for ' + + algorithmName + ); + }, `${algorithmName} encapsulateKey with ${config.description} (extractable=${extractable})`); + + // Test decapsulateKey operation + promise_test(async function (test) { + // Generate a key pair for testing + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); + + // First encapsulate to get ciphertext + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); + + // Then decapsulate using the private key + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + keyPair.privateKey, + encapsulatedKey.ciphertext, + config.algorithm, + extractable, + config.usages + ); + + assert_true( + decapsulatedKey instanceof CryptoKey, + 'decapsulateKey should return a CryptoKey' + ); + assert_equals( + decapsulatedKey.type, + 'secret', + 'Decapsulated key should be secret type' + ); + assert_equals( + decapsulatedKey.algorithm.name, + config.algorithm.name, + 'Decapsulated key algorithm should match' + ); + assert_equals( + decapsulatedKey.extractable, + extractable, + 'Decapsulated key should have correct extractable property' + ); + assert_array_equals( + decapsulatedKey.usages, + config.usages, + 'Decapsulated key should have correct usages' + ); + + if (extractable) { + // Extract both keys and verify they are identical + var originalKeyMaterial = await subtle.exportKey( + 'raw', + encapsulatedKey.sharedKey + ); + var decapsulatedKeyMaterial = await subtle.exportKey( + 'raw', + decapsulatedKey + ); + + assert_true( + equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), + 'Decapsulated key material should match original' + ); + + // Verify the key material is 32 bytes (256 bits) + assert_equals( + originalKeyMaterial.byteLength, + 32, + 'Shared key material should be 32 bytes' + ); + } + }, `${algorithmName} decapsulateKey with ${config.description} (extractable=${extractable})`); + + // Test round-trip compatibility + promise_test(async function (test) { + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); + + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); + + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + keyPair.privateKey, + encapsulatedKey.ciphertext, + config.algorithm, + extractable, + config.usages + ); + + if (extractable) { + // Verify keys have the same material + var originalKeyMaterial = await subtle.exportKey( + 'raw', + encapsulatedKey.sharedKey + ); + var decapsulatedKeyMaterial = await subtle.exportKey( + 'raw', + decapsulatedKey + ); + + assert_true( + equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), + 'Encapsulated and decapsulated keys should have the same material' + ); + } + + // Test that the derived keys can actually be used for their intended purpose + if ( + config.algorithm.name.startsWith('AES') && + config.usages.includes('encrypt') + ) { + await testAESOperation( + encapsulatedKey.sharedKey, + decapsulatedKey, + config.algorithm + ); + } else if (config.algorithm.name === 'HMAC') { + await testHMACOperation(encapsulatedKey.sharedKey, decapsulatedKey); + } + }, `${algorithmName} encapsulateKey/decapsulateKey round-trip with ${config.description} (extractable=${extractable})`); + + // Test vector-based decapsulation + promise_test(async function (test) { + var vectors = ml_kem_vectors[algorithmName]; + + // Import the private key from the vector's privateSeed + var privateKey = await subtle.importKey( + 'raw-seed', + vectors.privateSeed, + { name: algorithmName }, + false, + ['decapsulateKey'] + ); + + // Decapsulate the sample ciphertext from the vectors to get a shared key + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + privateKey, + vectors.sampleCiphertext, + config.algorithm, + extractable, + config.usages + ); + + assert_true( + decapsulatedKey instanceof CryptoKey, + 'decapsulateKey should return a CryptoKey' + ); assert_equals( - decapsulatedKey.algorithm.length, - config.algorithm.length, - 'Key length should be 256' + decapsulatedKey.type, + 'secret', + 'Decapsulated key should be secret type' ); - } - if (config.algorithm.hash) { assert_equals( - decapsulatedKey.algorithm.hash.name, - config.algorithm.hash, - 'Hash algorithm should match' + decapsulatedKey.algorithm.name, + config.algorithm.name, + 'Decapsulated key algorithm should match' + ); + assert_equals( + decapsulatedKey.extractable, + extractable, + 'Decapsulated key should have correct extractable property' + ); + assert_array_equals( + decapsulatedKey.usages, + config.usages, + 'Decapsulated key should have correct usages' ); - } - }, algorithmName + - ' vector-based sampleCiphertext decapsulation with ' + - config.description); + + if (extractable) { + // Extract the key material and verify it matches the expected shared secret + var keyMaterial = await subtle.exportKey('raw', decapsulatedKey); + assert_equals( + keyMaterial.byteLength, + 32, + 'Shared key material should be 32 bytes' + ); + assert_true( + equalBuffers(keyMaterial, vectors.expectedSharedSecret), + "Decapsulated key material should match vector's expectedSharedSecret" + ); + } + + // Verify algorithm-specific properties + if (config.algorithm.length) { + assert_equals( + decapsulatedKey.algorithm.length, + config.algorithm.length, + 'Key length should be 256' + ); + } + if (config.algorithm.hash) { + assert_equals( + decapsulatedKey.algorithm.hash.name, + config.algorithm.hash, + 'Hash algorithm should match' + ); + } + }, `${algorithmName} vector-based sampleCiphertext decapsulation with ${config.description} (extractable=${extractable})`); + }); }); }); } @@ -430,19 +435,4 @@ async function testHMACOperation(key1, key2) { assert_true(verified2, 'HMAC verification should succeed with key2'); } -// Helper function to compare two ArrayBuffers -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; -} - define_key_tests(); diff --git a/test/fixtures/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js b/test/fixtures/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js deleted file mode 100644 index 9167efa63f0ca3..00000000000000 --- a/test/fixtures/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js +++ /dev/null @@ -1,410 +0,0 @@ -// Test implementation for ML-KEM encapsulate and decapsulate operations - -function define_tests() { - var subtle = self.crypto.subtle; - - // Test data for all ML-KEM variants - var variants = ['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']; - - variants.forEach(function (algorithmName) { - var testVector = ml_kem_vectors[algorithmName]; - - // Test encapsulateBits operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // Test encapsulateBits - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - assert_true( - encapsulatedBits instanceof Object, - 'encapsulateBits should return an object' - ); - assert_true( - encapsulatedBits.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedBits.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedBits.sharedKey instanceof ArrayBuffer, - 'sharedKey should be ArrayBuffer' - ); - assert_true( - encapsulatedBits.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); - - // Verify sharedKey length (should be 32 bytes for all ML-KEM variants) - assert_equals( - encapsulatedBits.sharedKey.byteLength, - 32, - 'Shared key should be 32 bytes' - ); - - // Verify ciphertext length based on algorithm variant - var expectedCiphertextLength; - switch (algorithmName) { - case 'ML-KEM-512': - expectedCiphertextLength = 768; - break; - case 'ML-KEM-768': - expectedCiphertextLength = 1088; - break; - case 'ML-KEM-1024': - expectedCiphertextLength = 1568; - break; - } - assert_equals( - encapsulatedBits.ciphertext.byteLength, - expectedCiphertextLength, - 'Ciphertext should be ' + - expectedCiphertextLength + - ' bytes for ' + - algorithmName - ); - }, algorithmName + ' encapsulateBits basic functionality'); - - // Test decapsulateBits operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // First encapsulate to get ciphertext - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - // Then decapsulate using the private key - var decapsulatedBits = await subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ); - - assert_true( - decapsulatedBits instanceof ArrayBuffer, - 'decapsulateBits should return ArrayBuffer' - ); - assert_equals( - decapsulatedBits.byteLength, - 32, - 'Decapsulated bits should be 32 bytes' - ); - - // The decapsulated shared secret should match the original - assert_true( - equalBuffers(decapsulatedBits, encapsulatedBits.sharedKey), - 'Decapsulated shared secret should match original' - ); - }, algorithmName + ' decapsulateBits basic functionality'); - - // Test encapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // Test encapsulateKey with AES-GCM as the shared key algorithm - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - assert_true( - encapsulatedKey instanceof Object, - 'encapsulateKey should return an object' - ); - assert_true( - encapsulatedKey.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedKey.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedKey.sharedKey instanceof CryptoKey, - 'sharedKey should be a CryptoKey' - ); - assert_true( - encapsulatedKey.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); - - // Verify the shared key properties - assert_equals( - encapsulatedKey.sharedKey.type, - 'secret', - 'Shared key should be secret type' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.name, - 'AES-GCM', - 'Shared key algorithm should be AES-GCM' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.length, - 256, - 'Shared key length should be 256' - ); - assert_true( - encapsulatedKey.sharedKey.extractable, - 'Shared key should be extractable as specified' - ); - assert_array_equals( - encapsulatedKey.sharedKey.usages, - ['encrypt', 'decrypt'], - 'Shared key should have correct usages' - ); - }, algorithmName + ' encapsulateKey basic functionality'); - - // Test decapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // First encapsulate to get ciphertext - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - // Then decapsulate using the private key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - 'AES-GCM', - 'Decapsulated key algorithm should be AES-GCM' - ); - assert_equals( - decapsulatedKey.algorithm.length, - 256, - 'Decapsulated key length should be 256' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - ['encrypt', 'decrypt'], - 'Decapsulated key should have correct usages' - ); - - // Extract both keys and verify they are identical - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Decapsulated key material should match original' - ); - }, algorithmName + ' decapsulateKey basic functionality'); - - // Test error cases for encapsulateBits - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // Test with wrong key type (private key instead of public) - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateBits({ name: algorithmName }, keyPair.privateKey), - 'encapsulateBits should reject private key' - ); - - // Test with wrong algorithm name - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateBits({ name: 'AES-GCM' }, keyPair.publicKey), - 'encapsulateBits should reject mismatched algorithm' - ); - }, algorithmName + ' encapsulateBits error cases'); - - // Test error cases for decapsulateBits - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - // Test with wrong key type (public key instead of private) - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateBits( - { name: algorithmName }, - keyPair.publicKey, - encapsulatedBits.ciphertext - ), - 'decapsulateBits should reject public key' - ); - - // Test with wrong algorithm name - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateBits( - { name: 'AES-GCM' }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ), - 'decapsulateBits should reject mismatched algorithm' - ); - - // Test with invalid ciphertext - var invalidCiphertext = new Uint8Array(10); // Wrong size - await promise_rejects_dom( - test, - 'OperationError', - subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - invalidCiphertext - ), - 'decapsulateBits should reject invalid ciphertext' - ); - }, algorithmName + ' decapsulateBits error cases'); - - // Test error cases for encapsulateKey - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // Test with key without encapsulateKey usage - var wrongKeyPair = await subtle.generateKey( - { name: algorithmName }, - false, - ['decapsulateKey'] // Missing encapsulateKey usage - ); - - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateKey( - { name: algorithmName }, - wrongKeyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ), - 'encapsulateKey should reject key without encapsulateKey usage' - ); - }, algorithmName + ' encapsulateKey error cases'); - - // Test error cases for decapsulateKey - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - // Test with key without decapsulateKey usage - var wrongKeyPair = await subtle.generateKey( - { name: algorithmName }, - false, - ['encapsulateKey'] // Missing decapsulateKey usage - ); - - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateKey( - { name: algorithmName }, - wrongKeyPair.privateKey, - encapsulatedKey.ciphertext, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ), - 'decapsulateKey should reject key without decapsulateKey usage' - ); - }, algorithmName + ' decapsulateKey error cases'); - }); -} - -// Helper function to compare two ArrayBuffers -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; -} - -function run_test() { - define_tests(); -} diff --git a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js index 456f66423419c8..879a6efe257e49 100644 --- a/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js +++ b/test/fixtures/wpt/WebCryptoAPI/encrypt_decrypt/aes.js @@ -482,34 +482,5 @@ function run_test() { } } - // 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 { + idl_array.add_objects({ + Crypto: ['crypto'], + SubtleCrypto: ['crypto.subtle'] + }); + } +); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js index 3723b321e542d5..d9257ac6982505 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js @@ -106,44 +106,6 @@ function testFormat(format, algorithm, keyData, keySize, usages, extractable) { // 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; -} - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ('byteLength' in data) { @@ -166,57 +128,3 @@ function parameterString(format, data, algorithm, extractable, 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(', ') + '}'; -} diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js index c264a163148438..ad2f75048556e4 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js @@ -106,44 +106,6 @@ function testFormat(format, algorithm, keyData, keySize, usages, extractable) { // 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; -} - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ('byteLength' in data) { @@ -166,57 +128,3 @@ function parameterString(format, data, algorithm, extractable, 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(', ') + '}'; -} diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js index 6a5cc8d4724b57..3b78bab4e74132 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js @@ -220,44 +220,6 @@ // 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> (8 - remainder) === bBytes[length] >> (8 - remainder); + } + + return true; +} + +// 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