summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilip Skokan <panva.ip@gmail.com>2022-04-02 16:54:35 +0200
committerJuan José Arboleda <soyjuanarbol@gmail.com>2022-04-06 12:25:50 -0500
commit541a1328b031188c4bc8402878a777787744940e (patch)
tree647fd6e6ac72d1c31276046fb215706f824db495
parentf0fc2744a5eb09f002b31fd7ecc6f32b2bed0a30 (diff)
downloadnode-new-541a1328b031188c4bc8402878a777787744940e.tar.gz
crypto: fix webcrypto derive key lengths
PR-URL: https://github.com/nodejs/node/pull/42542 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
-rw-r--r--lib/internal/crypto/webcrypto.js37
-rw-r--r--test/parallel/test-webcrypto-derivekey.js34
2 files changed, 69 insertions, 2 deletions
diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js
index 63dd03bd00..a7916e6ac3 100644
--- a/lib/internal/crypto/webcrypto.js
+++ b/lib/internal/crypto/webcrypto.js
@@ -153,6 +153,41 @@ async function deriveBits(algorithm, baseKey, length) {
throw lazyDOMException('Unrecognized name.');
}
+function getKeyLength({ name, length, hash }) {
+ switch (name) {
+ case 'AES-CTR':
+ case 'AES-CBC':
+ case 'AES-GCM':
+ case 'AES-KW':
+ if (length !== 128 && length !== 192 && length !== 256)
+ throw lazyDOMException('Invalid key length', 'OperationError');
+
+ return length;
+ case 'HMAC':
+ if (length === undefined) {
+ switch (hash?.name) {
+ case 'SHA-1':
+ return 160;
+ case 'SHA-256':
+ return 256;
+ case 'SHA-384':
+ return 384;
+ case 'SHA-512':
+ return 512;
+ }
+ }
+
+ if (typeof length === 'number' && length !== 0) {
+ return length;
+ }
+
+ throw lazyDOMException('Invalid key length', 'OperationError');
+ case 'HKDF':
+ case 'PBKDF2':
+ return null;
+ }
+}
+
async function deriveKey(
algorithm,
baseKey,
@@ -176,7 +211,7 @@ async function deriveKey(
validateBoolean(extractable, 'extractable');
validateArray(keyUsages, 'keyUsages');
- const { length } = derivedKeyAlgorithm;
+ const length = getKeyLength(derivedKeyAlgorithm);
let bits;
switch (algorithm.name) {
case 'ECDH':
diff --git a/test/parallel/test-webcrypto-derivekey.js b/test/parallel/test-webcrypto-derivekey.js
index ee48a61f4a..0c11d38af3 100644
--- a/test/parallel/test-webcrypto-derivekey.js
+++ b/test/parallel/test-webcrypto-derivekey.js
@@ -7,7 +7,7 @@ if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
-const { subtle } = require('crypto').webcrypto;
+const { webcrypto: { subtle }, KeyObject } = require('crypto');
const { internalBinding } = require('internal/test/binding');
@@ -152,3 +152,35 @@ if (typeof internalBinding('crypto').ScryptJob === 'function') {
tests.then(common.mustCall());
}
+
+// Test default key lengths
+{
+ const vectors = [
+ ['PBKDF2', 'deriveKey', 528],
+ ['HKDF', 'deriveKey', 528],
+ [{ name: 'HMAC', hash: 'SHA-1' }, 'sign', 160],
+ [{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 256],
+ [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 384],
+ [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 512],
+ ];
+
+ (async () => {
+ const keyPair = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-521' }, false, ['deriveKey']);
+ for (const [derivedKeyAlgorithm, usage, expected] of vectors) {
+ const derived = await subtle.deriveKey(
+ { name: 'ECDH', public: keyPair.publicKey },
+ keyPair.privateKey,
+ derivedKeyAlgorithm,
+ false,
+ [usage]);
+
+ if (derived.algorithm.name === 'HMAC') {
+ assert.strictEqual(derived.algorithm.length, expected);
+ } else {
+ // KDFs cannot be exportable and do not indicate their length
+ const secretKey = KeyObject.from(derived);
+ assert.strictEqual(secretKey.symmetricKeySize, expected / 8);
+ }
+ }
+ })().then(common.mustCall());
+}