From f4d841c601c0a17efd5a5d53012788b9324d00bc Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 29 Jun 2024 00:21:29 +0200 Subject: [PATCH] crypto: make deriveBits length parameter optional and nullable PR-URL: https://github.com/nodejs/node/pull/53601 Reviewed-By: Luigi Pinca Reviewed-By: Benjamin Gruenbaum --- doc/api/webcrypto.md | 18 +++++++++++------- lib/internal/crypto/webcrypto.js | 4 ++-- .../parallel/test-webcrypto-derivebits-cfrg.js | 10 ++++++++++ .../parallel/test-webcrypto-derivebits-ecdh.js | 10 ++++++++++ .../parallel/test-webcrypto-derivebits-hkdf.js | 5 +++++ .../pummel/test-webcrypto-derivebits-pbkdf2.js | 5 +++++ test/wpt/status/WebCryptoAPI.json | 8 ++++++++ 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md index 33696e1f7bca14..7198befe225600 100644 --- a/doc/api/webcrypto.md +++ b/doc/api/webcrypto.md @@ -567,11 +567,15 @@ The algorithms currently supported include: * `'AES-CBC'` * `'AES-GCM`' -### `subtle.deriveBits(algorithm, baseKey, length)` +### `subtle.deriveBits(algorithm, baseKey[, length])` @@ -592,12 +596,12 @@ Using the method and parameters specified in `algorithm` and the keying material provided by `baseKey`, `subtle.deriveBits()` attempts to generate `length` bits. -The Node.js implementation requires that when `length` is a -number it must be multiple of `8`. +The Node.js implementation requires that `length`, when a number, is a multiple +of `8`. -When `length` is `null` the maximum number of bits for a given algorithm is -generated. This is allowed for the `'ECDH'`, `'X25519'`, and `'X448'` -algorithms. +When `length` is not provided or `null` the maximum number of bits for a given +algorithm is generated. This is allowed for the `'ECDH'`, `'X25519'`, and `'X448'` +algorithms, for other algorithms `length` is required to be a number. If successful, the returned promise will be resolved with an {ArrayBuffer} containing the generated data. diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index aaf46ce03dd133..8cd27717532344 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -178,12 +178,12 @@ async function generateKey( return result; } -async function deriveBits(algorithm, baseKey, length) { +async function deriveBits(algorithm, baseKey, length = null) { if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto'); webidl ??= require('internal/crypto/webidl'); const prefix = "Failed to execute 'deriveBits' on 'SubtleCrypto'"; - webidl.requiredArguments(arguments.length, 3, { prefix }); + webidl.requiredArguments(arguments.length, 2, { prefix }); algorithm = webidl.converters.AlgorithmIdentifier(algorithm, { prefix, context: '1st argument', diff --git a/test/parallel/test-webcrypto-derivebits-cfrg.js b/test/parallel/test-webcrypto-derivebits-cfrg.js index d92d2a18610767..3e28774d05a9ce 100644 --- a/test/parallel/test-webcrypto-derivebits-cfrg.js +++ b/test/parallel/test-webcrypto-derivebits-cfrg.js @@ -101,6 +101,16 @@ async function prepareKeys() { assert.strictEqual(Buffer.from(bits).toString('hex'), result); } + { + // Default length + const bits = await subtle.deriveBits({ + name, + public: publicKey + }, privateKey); + + assert.strictEqual(Buffer.from(bits).toString('hex'), result); + } + { // Short Result const bits = await subtle.deriveBits({ diff --git a/test/parallel/test-webcrypto-derivebits-ecdh.js b/test/parallel/test-webcrypto-derivebits-ecdh.js index d28899f7f912d7..4dba34d84a7907 100644 --- a/test/parallel/test-webcrypto-derivebits-ecdh.js +++ b/test/parallel/test-webcrypto-derivebits-ecdh.js @@ -122,6 +122,16 @@ async function prepareKeys() { assert.strictEqual(Buffer.from(bits).toString('hex'), result); } + { + // Default length + const bits = await subtle.deriveBits({ + name: 'ECDH', + public: publicKey + }, privateKey); + + assert.strictEqual(Buffer.from(bits).toString('hex'), result); + } + { // Short Result const bits = await subtle.deriveBits({ diff --git a/test/parallel/test-webcrypto-derivebits-hkdf.js b/test/parallel/test-webcrypto-derivebits-hkdf.js index d1ca1567e81faf..bef6abdc19d0d6 100644 --- a/test/parallel/test-webcrypto-derivebits-hkdf.js +++ b/test/parallel/test-webcrypto-derivebits-hkdf.js @@ -271,6 +271,11 @@ async function testDeriveBitsBadLengths( message: 'length cannot be null', name: 'OperationError', }), + assert.rejects( + subtle.deriveBits(algorithm, baseKeys[size]), { + message: 'length cannot be null', + name: 'OperationError', + }), assert.rejects( subtle.deriveBits(algorithm, baseKeys[size], 15), { message: /length must be a multiple of 8/, diff --git a/test/pummel/test-webcrypto-derivebits-pbkdf2.js b/test/pummel/test-webcrypto-derivebits-pbkdf2.js index e6aa0b7ff91ac7..382dadf1b35e45 100644 --- a/test/pummel/test-webcrypto-derivebits-pbkdf2.js +++ b/test/pummel/test-webcrypto-derivebits-pbkdf2.js @@ -459,6 +459,11 @@ async function testDeriveBitsBadLengths( message: 'length cannot be null', name: 'OperationError', }), + assert.rejects( + subtle.deriveBits(algorithm, baseKeys[size]), { + message: 'length cannot be null', + name: 'OperationError', + }), assert.rejects( subtle.deriveBits(algorithm, baseKeys[size], 15), { message: /length must be a multiple of 8/, diff --git a/test/wpt/status/WebCryptoAPI.json b/test/wpt/status/WebCryptoAPI.json index 9f9ba93240be25..69f86168f5a9df 100644 --- a/test/wpt/status/WebCryptoAPI.json +++ b/test/wpt/status/WebCryptoAPI.json @@ -4,5 +4,13 @@ }, "historical.any.js": { "skip": "Not relevant in Node.js context" + }, + "idlharness.https.any.js": { + "fail": { + "note": "WPT not updated for https://github.com/w3c/webcrypto/pull/345 yet", + "expected": [ + "SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier, CryptoKey, unsigned long)" + ] + } } }