crypto: require HMAC key length with SHA-3 hashes in Web Cryptography

PR-URL: https://github.com/nodejs/node/pull/59567
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
Filip Skokan 2025-08-23 12:25:50 +02:00 committed by GitHub
parent fb07edc82f
commit 0fab11805f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 28 deletions

View File

@ -629,11 +629,13 @@ function getBlockSize(name) {
case 'SHA-512':
return 1024;
case 'SHA3-256':
return 1088;
// Fall through
case 'SHA3-384':
return 832;
// Fall through
case 'SHA3-512':
return 576;
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
throw lazyDOMException('Explicit algorithm length member is required', 'NotSupportedError');
}
}

View File

@ -9,6 +9,7 @@ const {
ReflectConstruct,
StringPrototypeRepeat,
StringPrototypeSlice,
StringPrototypeStartsWith,
SymbolToStringTag,
} = primordials;
@ -1235,7 +1236,6 @@ function check(op, alg, length) {
case 'sign':
case 'verify':
case 'digest':
case 'generateKey':
case 'importKey':
case 'exportKey':
case 'wrapKey':
@ -1260,6 +1260,17 @@ function check(op, alg, length) {
return true;
}
case 'generateKey': {
if (
normalizedAlgorithm.name === 'HMAC' &&
normalizedAlgorithm.length === undefined &&
StringPrototypeStartsWith(normalizedAlgorithm.hash.name, 'SHA3-')
) {
return false;
}
return true;
}
default: {
const assert = require('internal/assert');
assert.fail('Unreachable code');

View File

@ -19,16 +19,18 @@ export const vectors = {
[!boringSSL, 'SHA3-512'],
],
'generateKey': [
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256' }],
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
[!boringSSL, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }],
[!boringSSL, { name: 'RSA-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
[!boringSSL, { name: 'RSA-OAEP', hash: 'SHA3-256', ...RSA_KEY_GEN }],
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256' }],
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 0 }],
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
[false, { name: 'HMAC', hash: 'SHA3-256' }],
],
'deriveKey': [
[!boringSSL,
@ -36,7 +38,7 @@ export const vectors = {
{ name: 'AES-CBC', length: 128 }],
[!boringSSL,
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
{ name: 'HMAC', hash: 'SHA3-256' }],
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false,
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
'HKDF'],
@ -45,14 +47,29 @@ export const vectors = {
{ name: 'AES-CBC', length: 128 }],
[!boringSSL,
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
{ name: 'HMAC', hash: 'SHA3-256' }],
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false,
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
'HKDF'],
[!boringSSL,
{ name: 'X25519', public: X25519.publicKey },
{ name: 'HMAC', hash: 'SHA3-256' }],
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[!boringSSL,
{ name: 'ECDH', public: ECDH.publicKey },
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
[false,
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
{ name: 'HMAC', hash: 'SHA3-256' }],
[false,
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
{ name: 'HMAC', hash: 'SHA3-256' }],
[false,
{ name: 'X25519', public: X25519.publicKey },
{ name: 'HMAC', hash: 'SHA3-256' }],
[false,
{ name: 'ECDH', public: ECDH.publicKey },
{ name: 'HMAC', hash: 'SHA3-256' }],
],

View File

@ -157,9 +157,14 @@ const { KeyObject } = require('crypto');
// Not long enough secret generated by ECDH
[{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 1088],
[{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 832],
[{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 576],
[{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256],
[{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384],
[{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512],
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
// [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256],
// [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384],
// [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512],
];
(async () => {
@ -196,9 +201,14 @@ const { KeyObject } = require('crypto');
[{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512],
[{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 1088],
[{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 832],
[{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 576],
[{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256],
[{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384],
[{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512],
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
// [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256],
// [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384],
// [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512],
];
(async () => {

View File

@ -614,9 +614,6 @@ if (hasOpenSSL(3, 5)) {
case 'SHA-256': length = 512; break;
case 'SHA-384': length = 1024; break;
case 'SHA-512': length = 1024; break;
case 'SHA3-256': length = 1088; break;
case 'SHA3-384': length = 832; break;
case 'SHA3-512': length = 576; break;
}
}
@ -642,20 +639,24 @@ if (hasOpenSSL(3, 5)) {
}
const kTests = [
[ undefined, 'SHA-1', ['sign', 'verify']],
[ undefined, 'SHA-256', ['sign', 'verify']],
[ undefined, 'SHA-384', ['sign', 'verify']],
[ undefined, 'SHA-512', ['sign', 'verify']],
[ 128, 'SHA-256', ['sign', 'verify']],
[ 1024, 'SHA-512', ['sign', 'verify']],
[undefined, 'SHA-1', ['sign', 'verify']],
[undefined, 'SHA-256', ['sign', 'verify']],
[undefined, 'SHA-384', ['sign', 'verify']],
[undefined, 'SHA-512', ['sign', 'verify']],
[128, 'SHA-256', ['sign', 'verify']],
[1024, 'SHA-512', ['sign', 'verify']],
];
if (!process.features.openssl_is_boringssl) {
kTests.push(
[ undefined, 'SHA3-256', ['sign', 'verify']],
[ undefined, 'SHA3-384', ['sign', 'verify']],
[ undefined, 'SHA3-512', ['sign', 'verify']],
[256, 'SHA3-256', ['sign', 'verify']],
[384, 'SHA3-384', ['sign', 'verify']],
[512, 'SHA3-512', ['sign', 'verify']],
// This interaction is not defined for now.
// https://github.com/WICG/webcrypto-modern-algos/issues/23
// [undefined, 'SHA3-256', ['sign', 'verify']],
// [undefined, 'SHA3-384', ['sign', 'verify']],
// [undefined, 'SHA3-512', ['sign', 'verify']],
);
} else {
common.printSkipMessage('Skipping unsupported SHA-3 test cases');