Commit d0cbb419865 for nodejs
commit d0cbb41986550917851446aaf14a6e75672a7f5b
Author: Filip Skokan <panva.ip@gmail.com>
Date: Tue Sep 22 22:14:41 2026 +0200
crypto: allow short AES-GCM IVs
Allow nonempty GCM IVs shorter than the default length and let the
underlying cipher enforce its supported range.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66237
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
diff --git a/src/crypto/crypto_aes.cc b/src/crypto/crypto_aes.cc
index e46a84188f0..ea869a8eef1 100644
--- a/src/crypto/crypto_aes.cc
+++ b/src/crypto/crypto_aes.cc
@@ -573,8 +573,13 @@ Maybe<void> AESCipherTraits::AdditionalConfig(
UseDefaultIV(params);
}
- // For OCB mode, allow variable IV lengths (1-15 bytes)
- if (params->cipher.isOcbMode()) {
+ if (params->cipher.isGcmMode()) {
+ if (params->iv.size() == 0) {
+ THROW_ERR_CRYPTO_INVALID_IV(env);
+ return Nothing<void>();
+ }
+ } else if (params->cipher.isOcbMode()) {
+ // For OCB mode, allow variable IV lengths (1-15 bytes).
if (params->iv.size() == 0 || params->iv.size() > 15) {
THROW_ERR_CRYPTO_INVALID_IV(env);
return Nothing<void>();
diff --git a/test/parallel/test-webcrypto-aes-gcm-iv-length.js b/test/parallel/test-webcrypto-aes-gcm-iv-length.js
new file mode 100644
index 00000000000..a4243bd0930
--- /dev/null
+++ b/test/parallel/test-webcrypto-aes-gcm-iv-length.js
@@ -0,0 +1,42 @@
+'use strict';
+
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { createCipheriv } = require('crypto');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+ const plaintext = Buffer.from('AES-GCM with a variable-length IV');
+ const additionalData = Buffer.from('additional data');
+
+ for (const length of [128, 192, 256]) {
+ const keyBytes = Buffer.alloc(length / 8);
+ const key = await subtle.importKey(
+ 'raw', keyBytes, 'AES-GCM', false, ['encrypt', 'decrypt']);
+
+ for (const ivLength of [1, 8, 11, 12, 16, 128]) {
+ const iv = Buffer.alloc(ivLength, 1);
+ const algorithm = { name: 'AES-GCM', iv, additionalData };
+ const cipher = createCipheriv(`aes-${length}-gcm`, keyBytes, iv);
+ cipher.setAAD(additionalData);
+ const expected = Buffer.concat([
+ cipher.update(plaintext), cipher.final(), cipher.getAuthTag(),
+ ]);
+
+ assert.deepStrictEqual(
+ Buffer.from(await subtle.encrypt(algorithm, key, plaintext)), expected);
+ assert.deepStrictEqual(
+ Buffer.from(await subtle.decrypt(algorithm, key, expected)), plaintext);
+ }
+
+ const algorithm = { name: 'AES-GCM', iv: new Uint8Array(0) };
+ await assert.rejects(subtle.encrypt(algorithm, key, plaintext),
+ { name: 'OperationError' });
+ await assert.rejects(subtle.decrypt(algorithm, key, new Uint8Array(16)),
+ { name: 'OperationError' });
+ }
+})().then(common.mustCall());