diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md index ce31a590f1138b..0c888564b1f65b 100644 --- a/doc/api/webcrypto.md +++ b/doc/api/webcrypto.md @@ -1869,19 +1869,27 @@ the message. -#### `cShakeParams.customization` +#### `cShakeParams.name` -* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} +* Type: {string} Must be `'cSHAKE128'`[^modern-algos] or `'cSHAKE256'`[^modern-algos] -The `customization` member represents the customization string. -The Node.js Web Crypto API implementation only supports zero-length customization -which is equivalent to not providing customization at all. +#### `cShakeParams.outputLength` + + + +* Type: {number} represents the requested output length in bits. #### `cShakeParams.functionName` @@ -1896,21 +1904,17 @@ functions based on cSHAKE. The Node.js Web Crypto API implementation only supports zero-length functionName which is equivalent to not providing functionName at all. -#### `cShakeParams.length` +#### `cShakeParams.customization` -* Type: {number} represents the requested output length in bits. - -#### `cShakeParams.name` - - +* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} -* Type: {string} Must be `'cSHAKE128'`[^modern-algos] or `'cSHAKE256'`[^modern-algos] +The `customization` member represents the customization string. +The Node.js Web Crypto API implementation only supports zero-length customization +which is equivalent to not providing customization at all. ### Class: `EcdhKeyDeriveParams` @@ -2387,6 +2391,10 @@ added: v24.8.0 #### `kmacParams.algorithm` @@ -2397,25 +2405,25 @@ added: v24.8.0 * Type: {string} Must be `'KMAC128'` or `'KMAC256'`. -#### `kmacParams.customization` +#### `kmacParams.outputLength` -* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} +* Type: {number} -The `customization` member represents the optional customization string. +The length of the output in bytes. This must be a positive integer. -#### `kmacParams.length` +#### `kmacParams.customization` -* Type: {number} +* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} -The length of the output in bytes. This must be a positive integer. +The `customization` member represents the optional customization string. ### Class: `Pbkdf2Params` diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js index 3f34468e55e99f..e549c72fccc4bc 100644 --- a/lib/internal/crypto/hash.js +++ b/lib/internal/crypto/hash.js @@ -223,7 +223,7 @@ async function asyncDigest(algorithm, data) { kCryptoJobAsync, normalizeHashName(algorithm.name), data, - algorithm.length)); + algorithm.outputLength)); } throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError'); diff --git a/lib/internal/crypto/mac.js b/lib/internal/crypto/mac.js index a31c3ddb0d9484..1ad4e27c6a8d39 100644 --- a/lib/internal/crypto/mac.js +++ b/lib/internal/crypto/mac.js @@ -234,7 +234,7 @@ function kmacSignVerify(key, data, algorithm, signature) { key[kKeyObject][kHandle], algorithm.name, algorithm.customization, - algorithm.length / 8, + algorithm.outputLength / 8, data, signature)); } diff --git a/lib/internal/crypto/webidl.js b/lib/internal/crypto/webidl.js index e72931e9c83cca..581f541847faea 100644 --- a/lib/internal/crypto/webidl.js +++ b/lib/internal/crypto/webidl.js @@ -589,14 +589,14 @@ converters.CShakeParams = createDictionaryConverter( 'CShakeParams', [ ...new SafeArrayIterator(dictAlgorithm), { - key: 'length', + key: 'outputLength', converter: (V, opts) => converters['unsigned long'](V, { ...opts, enforceRange: true }), validator: (V, opts) => { // The Web Crypto spec allows for SHAKE output length that are not multiples of // 8. We don't. if (V % 8) - throw lazyDOMException('Unsupported CShakeParams length', 'NotSupportedError'); + throw lazyDOMException('Unsupported CShakeParams outputLength', 'NotSupportedError'); }, required: true, }, @@ -879,13 +879,13 @@ converters.KmacParams = createDictionaryConverter( 'KmacParams', [ ...new SafeArrayIterator(dictAlgorithm), { - key: 'length', + key: 'outputLength', converter: (V, opts) => converters['unsigned long'](V, { ...opts, enforceRange: true }), validator: (V, opts) => { // The Web Crypto spec allows for KMAC output length that are not multiples of 8. We don't. if (V % 8) - throw lazyDOMException('Unsupported KmacParams length', 'NotSupportedError'); + throw lazyDOMException('Unsupported KmacParams outputLength', 'NotSupportedError'); }, required: true, }, diff --git a/test/fixtures/crypto/kmac.js b/test/fixtures/crypto/kmac.js index 86dec424bad9b1..cc1870af2bb04f 100644 --- a/test/fixtures/crypto/kmac.js +++ b/test/fixtures/crypto/kmac.js @@ -13,7 +13,7 @@ module.exports = function() { ]), data: Buffer.from([0x00, 0x01, 0x02, 0x03]), customization: undefined, - length: 256, + outputLength: 256, expected: Buffer.from([ 0xe5, 0x78, 0x0b, 0x0d, 0x3e, 0xa6, 0xf7, 0xd3, 0xa4, 0x29, 0xc5, 0x70, 0x6a, 0xa4, 0x3a, 0x00, 0xfa, 0xdb, 0xd7, 0xd4, 0x96, 0x28, 0x83, 0x9e, @@ -30,7 +30,7 @@ module.exports = function() { ]), data: Buffer.from([0x00, 0x01, 0x02, 0x03]), customization: Buffer.from('My Tagged Application'), - length: 256, + outputLength: 256, expected: Buffer.from([ 0x3b, 0x1f, 0xba, 0x96, 0x3c, 0xd8, 0xb0, 0xb5, 0x9e, 0x8c, 0x1a, 0x6d, 0x71, 0x88, 0x8b, 0x71, 0x43, 0x65, 0x1a, 0xf8, 0xba, 0x0a, 0x70, 0x70, @@ -47,7 +47,7 @@ module.exports = function() { ]), data: Buffer.from(Array.from({ length: 200 }, (_, i) => i)), // 0x00-0xC7 customization: Buffer.from('My Tagged Application'), - length: 256, + outputLength: 256, expected: Buffer.from([ 0x1f, 0x5b, 0x4e, 0x6c, 0xca, 0x02, 0x20, 0x9e, 0x0d, 0xcb, 0x5c, 0xa6, 0x35, 0xb8, 0x9a, 0x15, 0xe2, 0x71, 0xec, 0xc7, 0x60, 0x07, 0x1d, 0xfd, @@ -64,7 +64,7 @@ module.exports = function() { ]), data: Buffer.from([0x00, 0x01, 0x02, 0x03]), customization: Buffer.from('My Tagged Application'), - length: 512, + outputLength: 512, expected: Buffer.from([ 0x20, 0xc5, 0x70, 0xc3, 0x13, 0x46, 0xf7, 0x03, 0xc9, 0xac, 0x36, 0xc6, 0x1c, 0x03, 0xcb, 0x64, 0xc3, 0x97, 0x0d, 0x0c, 0xfc, 0x78, 0x7e, 0x9b, @@ -84,7 +84,7 @@ module.exports = function() { ]), data: Buffer.from(Array.from({ length: 200 }, (_, i) => i)), // 0x00-0xC7 customization: undefined, - length: 512, + outputLength: 512, expected: Buffer.from([ 0x75, 0x35, 0x8c, 0xf3, 0x9e, 0x41, 0x49, 0x4e, 0x94, 0x97, 0x07, 0x92, 0x7c, 0xee, 0x0a, 0xf2, 0x0a, 0x3f, 0xf5, 0x53, 0x90, 0x4c, 0x86, 0xb0, @@ -104,7 +104,7 @@ module.exports = function() { ]), data: Buffer.from(Array.from({ length: 200 }, (_, i) => i)), // 0x00-0xC7 customization: Buffer.from('My Tagged Application'), - length: 512, + outputLength: 512, expected: Buffer.from([ 0xb5, 0x86, 0x18, 0xf7, 0x1f, 0x92, 0xe1, 0xd5, 0x6c, 0x1b, 0x8c, 0x55, 0xdd, 0xd7, 0xcd, 0x18, 0x8b, 0x97, 0xb4, 0xca, 0x4d, 0x99, 0x83, 0x1e, diff --git a/test/fixtures/webcrypto/supports-modern-algorithms.mjs b/test/fixtures/webcrypto/supports-modern-algorithms.mjs index 76d5e805cbc0e7..eafb95c559a0f7 100644 --- a/test/fixtures/webcrypto/supports-modern-algorithms.mjs +++ b/test/fixtures/webcrypto/supports-modern-algorithms.mjs @@ -17,17 +17,17 @@ const X25519 = await subtle.generateKey('X25519', false, ['deriveBits', 'deriveK export const vectors = { 'digest': [ [false, 'cSHAKE128'], - [shake128, { name: 'cSHAKE128', length: 128 }], - [shake128, { name: 'cSHAKE128', length: 128, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }], - [false, { name: 'cSHAKE128', length: 128, functionName: Buffer.alloc(1) }], - [false, { name: 'cSHAKE128', length: 128, customization: Buffer.alloc(1) }], - [false, { name: 'cSHAKE128', length: 127 }], + [shake128, { name: 'cSHAKE128', outputLength: 128 }], + [shake128, { name: 'cSHAKE128', outputLength: 128, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }], + [false, { name: 'cSHAKE128', outputLength: 128, functionName: Buffer.alloc(1) }], + [false, { name: 'cSHAKE128', outputLength: 128, customization: Buffer.alloc(1) }], + [false, { name: 'cSHAKE128', outputLength: 127 }], [false, 'cSHAKE256'], - [shake256, { name: 'cSHAKE256', length: 256 }], - [shake256, { name: 'cSHAKE256', length: 256, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }], - [false, { name: 'cSHAKE256', length: 256, functionName: Buffer.alloc(1) }], - [false, { name: 'cSHAKE256', length: 256, customization: Buffer.alloc(1) }], - [false, { name: 'cSHAKE256', length: 255 }], + [shake256, { name: 'cSHAKE256', outputLength: 256 }], + [shake256, { name: 'cSHAKE256', outputLength: 256, functionName: Buffer.alloc(0), customization: Buffer.alloc(0) }], + [false, { name: 'cSHAKE256', outputLength: 256, functionName: Buffer.alloc(1) }], + [false, { name: 'cSHAKE256', outputLength: 256, customization: Buffer.alloc(1) }], + [false, { name: 'cSHAKE256', outputLength: 255 }], ], 'sign': [ [pqc, 'ML-DSA-44'], @@ -44,8 +44,8 @@ export const vectors = { [false, 'Argon2id'], [false, 'KMAC128'], [false, 'KMAC256'], - [kmac, { name: 'KMAC128', length: 256 }], - [kmac, { name: 'KMAC256', length: 256 }], + [kmac, { name: 'KMAC128', outputLength: 256 }], + [kmac, { name: 'KMAC256', outputLength: 256 }], ], 'generateKey': [ [pqc, 'ML-DSA-44'], diff --git a/test/parallel/test-webcrypto-digest.js b/test/parallel/test-webcrypto-digest.js index 4d22006937f8cb..4a28d88dcd72c3 100644 --- a/test/parallel/test-webcrypto-digest.js +++ b/test/parallel/test-webcrypto-digest.js @@ -19,8 +19,8 @@ const kTests = [ if (!process.features.openssl_is_boringssl) { kTests.push( - [{ name: 'cSHAKE128', length: 256 }, ['shake128', { outputLength: 256 >> 3 }], 256], - [{ name: 'cSHAKE256', length: 512 }, ['shake256', { outputLength: 512 >> 3 }], 512], + [{ name: 'cSHAKE128', outputLength: 256 }, ['shake128', { outputLength: 256 >> 3 }], 256], + [{ name: 'cSHAKE256', outputLength: 512 }, ['shake256', { outputLength: 512 >> 3 }], 512], ['SHA3-256', ['sha3-256'], 256], ['SHA3-384', ['sha3-384'], 384], ['SHA3-512', ['sha3-512'], 512], @@ -223,10 +223,10 @@ async function testDigest(size, alg) { function applyXOF(name) { if (name.match(/cshake128/i)) { - return { name, length: 256 }; + return { name, outputLength: 256 }; } if (name.match(/cshake256/i)) { - return { name, length: 512 }; + return { name, outputLength: 512 }; } return name; @@ -259,13 +259,13 @@ function applyXOF(name) { if (getHashes().includes('shake128')) { (async () => { assert.deepStrictEqual( - new Uint8Array(await subtle.digest({ name: 'cSHAKE128', length: 0 }, Buffer.alloc(1))), + new Uint8Array(await subtle.digest({ name: 'cSHAKE128', outputLength: 0 }, Buffer.alloc(1))), new Uint8Array(0), ); - await assert.rejects(subtle.digest({ name: 'cSHAKE128', length: 7 }, Buffer.alloc(1)), { + await assert.rejects(subtle.digest({ name: 'cSHAKE128', outputLength: 7 }, Buffer.alloc(1)), { name: 'NotSupportedError', - message: 'Unsupported CShakeParams length', + message: 'Unsupported CShakeParams outputLength', }); })().then(common.mustCall()); } diff --git a/test/parallel/test-webcrypto-sign-verify-kmac.js b/test/parallel/test-webcrypto-sign-verify-kmac.js index c30196a94d9fb6..d41095e0893d97 100644 --- a/test/parallel/test-webcrypto-sign-verify-kmac.js +++ b/test/parallel/test-webcrypto-sign-verify-kmac.js @@ -19,7 +19,7 @@ async function testVerify({ algorithm, key, data, customization, - length, + outputLength, expected }) { const [ verifyKey, @@ -46,7 +46,7 @@ async function testVerify({ algorithm, const signParams = { name: algorithm, - length, + outputLength, customization, }; @@ -112,7 +112,7 @@ async function testVerify({ algorithm, { assert(!(await subtle.verify({ ...signParams, - length: length === 256 ? 512 : 256, + outputLength: outputLength === 256 ? 512 : 256, }, verifyKey, expected, data))); } } @@ -121,7 +121,7 @@ async function testSign({ algorithm, key, data, customization, - length, + outputLength, expected }) { const [ signKey, @@ -148,7 +148,7 @@ async function testSign({ algorithm, const signParams = { name: algorithm, - length, + outputLength, customization, }; diff --git a/test/parallel/test-webcrypto-sign-verify.js b/test/parallel/test-webcrypto-sign-verify.js index 8b034e005b29a4..26e66d9aa0fa8b 100644 --- a/test/parallel/test-webcrypto-sign-verify.js +++ b/test/parallel/test-webcrypto-sign-verify.js @@ -118,12 +118,12 @@ if (hasOpenSSL(3)) { const signature = await subtle.sign({ name, - length: 256, + outputLength: 256, }, key, ec.encode(data)); assert(await subtle.verify({ name, - length: 256, + outputLength: 256, }, key, signature, ec.encode(data))); } diff --git a/test/wpt/status/WebCryptoAPI.cjs b/test/wpt/status/WebCryptoAPI.cjs index d23fb1d40453fe..d14c617614af34 100644 --- a/test/wpt/status/WebCryptoAPI.cjs +++ b/test/wpt/status/WebCryptoAPI.cjs @@ -47,6 +47,43 @@ if (!hasOpenSSL(3, 5)) { 'sign_verify/mldsa.tentative.https.any.js'); } +const cshakeExpectedFailures = ['cSHAKE128', 'cSHAKE256'].flatMap((algorithm) => { + return [0, 256, 384, 512].flatMap((length) => { + return ['empty', 'short', 'medium'].flatMap((size) => { + const base = `${algorithm} with ${length} bit output and ${size} source data`; + return [ + base, + `${base} and altered buffer after call`, + ]; + }); + }); +}); + +const kmacVectorNames = [ + 'KMAC128 with no customization', + 'KMAC128 with customization', + 'KMAC128 with large data and customization', + 'KMAC256 with customization and 512-bit output', + 'KMAC256 with large data and no customization', + 'KMAC256 with large data and customization', +]; + +const kmacExpectedFailures = kmacVectorNames.flatMap((name) => { + return [ + `${name} verification`, + `${name} verification with altered signature after call`, + `${name} with altered plaintext after call`, + `${name} no verify usage`, + `${name} round trip`, + `${name} verification failure due to wrong plaintext`, + `${name} verification failure due to wrong signature`, + `${name} verification failure due to short signature`, + `${name} verification failure due to wrong length parameter`, + `${name} signing with wrong algorithm name`, + `${name} verifying with wrong algorithm name`, + ]; +}); + module.exports = { ...conditionalSkips, 'algorithm-discards-context.https.window.js': { @@ -86,4 +123,16 @@ module.exports = { ], }, }, + 'digest/cshake.tentative.https.any.js': { + 'fail': { + 'note': 'WPT still uses CShakeParams.length; implementation moved to CShakeParams.outputLength', + 'expected': cshakeExpectedFailures, + }, + }, + 'sign_verify/kmac.tentative.https.any.js': conditionalSkips['sign_verify/kmac.tentative.https.any.js'] ?? { + 'fail': { + 'note': 'WPT still uses KmacParams.length; implementation moved to KmacParams.outputLength', + 'expected': kmacExpectedFailures, + }, + }, };