Skip to content

Commit 4e7b746

Browse files
panvajuanarbol
authored andcommitted
crypto: fix webcrypto derive key lengths
PR-URL: #42542 Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent f3c3479 commit 4e7b746

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

lib/internal/crypto/webcrypto.js

+36-1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,41 @@ async function deriveBits(algorithm, baseKey, length) {
153153
throw lazyDOMException('Unrecognized name.');
154154
}
155155

156+
function getKeyLength({ name, length, hash }) {
157+
switch (name) {
158+
case 'AES-CTR':
159+
case 'AES-CBC':
160+
case 'AES-GCM':
161+
case 'AES-KW':
162+
if (length !== 128 && length !== 192 && length !== 256)
163+
throw lazyDOMException('Invalid key length', 'OperationError');
164+
165+
return length;
166+
case 'HMAC':
167+
if (length === undefined) {
168+
switch (hash?.name) {
169+
case 'SHA-1':
170+
return 160;
171+
case 'SHA-256':
172+
return 256;
173+
case 'SHA-384':
174+
return 384;
175+
case 'SHA-512':
176+
return 512;
177+
}
178+
}
179+
180+
if (typeof length === 'number' && length !== 0) {
181+
return length;
182+
}
183+
184+
throw lazyDOMException('Invalid key length', 'OperationError');
185+
case 'HKDF':
186+
case 'PBKDF2':
187+
return null;
188+
}
189+
}
190+
156191
async function deriveKey(
157192
algorithm,
158193
baseKey,
@@ -176,7 +211,7 @@ async function deriveKey(
176211
validateBoolean(extractable, 'extractable');
177212
validateArray(keyUsages, 'keyUsages');
178213

179-
const { length } = derivedKeyAlgorithm;
214+
const length = getKeyLength(derivedKeyAlgorithm);
180215
let bits;
181216
switch (algorithm.name) {
182217
case 'ECDH':

test/parallel/test-webcrypto-derivekey.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if (!common.hasCrypto)
77
common.skip('missing crypto');
88

99
const assert = require('assert');
10-
const { subtle } = require('crypto').webcrypto;
10+
const { webcrypto: { subtle }, KeyObject } = require('crypto');
1111

1212
const { internalBinding } = require('internal/test/binding');
1313

@@ -152,3 +152,35 @@ if (typeof internalBinding('crypto').ScryptJob === 'function') {
152152

153153
tests.then(common.mustCall());
154154
}
155+
156+
// Test default key lengths
157+
{
158+
const vectors = [
159+
['PBKDF2', 'deriveKey', 528],
160+
['HKDF', 'deriveKey', 528],
161+
[{ name: 'HMAC', hash: 'SHA-1' }, 'sign', 160],
162+
[{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 256],
163+
[{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 384],
164+
[{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 512],
165+
];
166+
167+
(async () => {
168+
const keyPair = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-521' }, false, ['deriveKey']);
169+
for (const [derivedKeyAlgorithm, usage, expected] of vectors) {
170+
const derived = await subtle.deriveKey(
171+
{ name: 'ECDH', public: keyPair.publicKey },
172+
keyPair.privateKey,
173+
derivedKeyAlgorithm,
174+
false,
175+
[usage]);
176+
177+
if (derived.algorithm.name === 'HMAC') {
178+
assert.strictEqual(derived.algorithm.length, expected);
179+
} else {
180+
// KDFs cannot be exportable and do not indicate their length
181+
const secretKey = KeyObject.from(derived);
182+
assert.strictEqual(secretKey.symmetricKeySize, expected / 8);
183+
}
184+
}
185+
})().then(common.mustCall());
186+
}

0 commit comments

Comments
 (0)