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': case 'SHA-512':
return 1024; return 1024;
case 'SHA3-256': case 'SHA3-256':
return 1088; // Fall through
case 'SHA3-384': case 'SHA3-384':
return 832; // Fall through
case 'SHA3-512': 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, ReflectConstruct,
StringPrototypeRepeat, StringPrototypeRepeat,
StringPrototypeSlice, StringPrototypeSlice,
StringPrototypeStartsWith,
SymbolToStringTag, SymbolToStringTag,
} = primordials; } = primordials;
@ -1235,7 +1236,6 @@ function check(op, alg, length) {
case 'sign': case 'sign':
case 'verify': case 'verify':
case 'digest': case 'digest':
case 'generateKey':
case 'importKey': case 'importKey':
case 'exportKey': case 'exportKey':
case 'wrapKey': case 'wrapKey':
@ -1260,6 +1260,17 @@ function check(op, alg, length) {
return true; return true;
} }
case 'generateKey': {
if (
normalizedAlgorithm.name === 'HMAC' &&
normalizedAlgorithm.length === undefined &&
StringPrototypeStartsWith(normalizedAlgorithm.hash.name, 'SHA3-')
) {
return false;
}
return true;
}
default: { default: {
const assert = require('internal/assert'); const assert = require('internal/assert');
assert.fail('Unreachable code'); assert.fail('Unreachable code');

View File

@ -19,16 +19,18 @@ export const vectors = {
[!boringSSL, 'SHA3-512'], [!boringSSL, 'SHA3-512'],
], ],
'generateKey': [ 'generateKey': [
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256' }],
[!boringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }], [!boringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }], [false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
[!boringSSL, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }], [!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-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
[!boringSSL, { name: 'RSA-OAEP', 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 }], [!boringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }], [false, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
[false, { name: 'HMAC', hash: 'SHA3-256', length: 0 }], [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': [ 'deriveKey': [
[!boringSSL, [!boringSSL,
@ -36,7 +38,7 @@ export const vectors = {
{ name: 'AES-CBC', length: 128 }], { name: 'AES-CBC', length: 128 }],
[!boringSSL, [!boringSSL,
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, { 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, [false,
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
'HKDF'], 'HKDF'],
@ -45,14 +47,29 @@ export const vectors = {
{ name: 'AES-CBC', length: 128 }], { name: 'AES-CBC', length: 128 }],
[!boringSSL, [!boringSSL,
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
{ name: 'HMAC', hash: 'SHA3-256' }], { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[false, [false,
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
'HKDF'], 'HKDF'],
[!boringSSL, [!boringSSL,
{ name: 'X25519', public: X25519.publicKey }, { name: 'X25519', public: X25519.publicKey },
{ name: 'HMAC', hash: 'SHA3-256' }], { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
[!boringSSL, [!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: 'ECDH', public: ECDH.publicKey },
{ name: 'HMAC', hash: 'SHA3-256' }], { name: 'HMAC', hash: 'SHA3-256' }],
], ],

View File

@ -157,9 +157,14 @@ const { KeyObject } = require('crypto');
// Not long enough secret generated by ECDH // Not long enough secret generated by ECDH
[{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 1088], [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256],
[{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 832], [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384],
[{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 576], [{ 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 () => { (async () => {
@ -196,9 +201,14 @@ const { KeyObject } = require('crypto');
[{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512], [{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512],
[{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024],
[{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 1088], [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256],
[{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 832], [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384],
[{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 576], [{ 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 () => { (async () => {

View File

@ -614,9 +614,6 @@ if (hasOpenSSL(3, 5)) {
case 'SHA-256': length = 512; break; case 'SHA-256': length = 512; break;
case 'SHA-384': length = 1024; break; case 'SHA-384': length = 1024; break;
case 'SHA-512': 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 = [ const kTests = [
[ undefined, 'SHA-1', ['sign', 'verify']], [undefined, 'SHA-1', ['sign', 'verify']],
[ undefined, 'SHA-256', ['sign', 'verify']], [undefined, 'SHA-256', ['sign', 'verify']],
[ undefined, 'SHA-384', ['sign', 'verify']], [undefined, 'SHA-384', ['sign', 'verify']],
[ undefined, 'SHA-512', ['sign', 'verify']], [undefined, 'SHA-512', ['sign', 'verify']],
[ 128, 'SHA-256', ['sign', 'verify']], [128, 'SHA-256', ['sign', 'verify']],
[ 1024, 'SHA-512', ['sign', 'verify']], [1024, 'SHA-512', ['sign', 'verify']],
]; ];
if (!process.features.openssl_is_boringssl) { if (!process.features.openssl_is_boringssl) {
kTests.push( kTests.push(
[256, 'SHA3-256', ['sign', 'verify']],
[ undefined, 'SHA3-256', ['sign', 'verify']], [384, 'SHA3-384', ['sign', 'verify']],
[ undefined, 'SHA3-384', ['sign', 'verify']], [512, 'SHA3-512', ['sign', 'verify']],
[ undefined, '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 { } else {
common.printSkipMessage('Skipping unsupported SHA-3 test cases'); common.printSkipMessage('Skipping unsupported SHA-3 test cases');