Skip to content
/ node Public
  • Sponsor nodejs/node

  • Notifications You must be signed in to change notification settings
  • Fork 31.4k
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bf788d9

Browse files
panvatargos
authored andcommittedMar 11, 2025
src: refactor SubtleCrypto algorithm and length validations
PR-URL: #57319 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 37664e8 commit bf788d9

13 files changed

+103
-160
lines changed
 

‎lib/internal/crypto/aes.js

+2-50
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ const {
44
ArrayBufferIsView,
55
ArrayBufferPrototypeSlice,
66
ArrayFrom,
7-
ArrayPrototypeIncludes,
87
ArrayPrototypePush,
9-
MathFloor,
108
PromiseReject,
119
SafeSet,
1210
TypedArrayPrototypeSlice,
@@ -35,10 +33,7 @@ const {
3533
const {
3634
hasAnyNotIn,
3735
jobPromise,
38-
validateByteLength,
3936
validateKeyOps,
40-
validateMaxBufferLength,
41-
kAesKeyLengths,
4237
kHandle,
4338
kKeyObject,
4439
} = require('internal/crypto/util');
@@ -58,7 +53,6 @@ const {
5853
generateKey: _generateKey,
5954
} = require('internal/crypto/keygen');
6055

61-
const kTagLengths = [32, 64, 96, 104, 112, 120, 128];
6256
const generateKey = promisify(_generateKey);
6357

6458
function getAlgorithmName(name, length) {
@@ -108,20 +102,7 @@ function getVariant(name, length) {
108102
}
109103
}
110104

111-
function validateAesCtrAlgorithm(algorithm) {
112-
validateByteLength(algorithm.counter, 'algorithm.counter', 16);
113-
// The length must specify an integer between 1 and 128. While
114-
// there is no default, this should typically be 64.
115-
if (algorithm.length === 0 || algorithm.length > 128) {
116-
throw lazyDOMException(
117-
'AES-CTR algorithm.length must be between 1 and 128',
118-
'OperationError');
119-
}
120-
}
121-
122105
function asyncAesCtrCipher(mode, key, data, algorithm) {
123-
validateAesCtrAlgorithm(algorithm);
124-
125106
return jobPromise(() => new AESCipherJob(
126107
kCryptoJobAsync,
127108
mode,
@@ -132,12 +113,7 @@ function asyncAesCtrCipher(mode, key, data, algorithm) {
132113
algorithm.length));
133114
}
134115

135-
function validateAesCbcAlgorithm(algorithm) {
136-
validateByteLength(algorithm.iv, 'algorithm.iv', 16);
137-
}
138-
139116
function asyncAesCbcCipher(mode, key, data, algorithm) {
140-
validateAesCbcAlgorithm(algorithm);
141117
return jobPromise(() => new AESCipherJob(
142118
kCryptoJobAsync,
143119
mode,
@@ -156,25 +132,10 @@ function asyncAesKwCipher(mode, key, data) {
156132
getVariant('AES-KW', key.algorithm.length)));
157133
}
158134

159-
function validateAesGcmAlgorithm(algorithm) {
160-
if (!ArrayPrototypeIncludes(kTagLengths, algorithm.tagLength)) {
161-
throw lazyDOMException(
162-
`${algorithm.tagLength} is not a valid AES-GCM tag length`,
163-
'OperationError');
164-
}
165-
166-
validateMaxBufferLength(algorithm.iv, 'algorithm.iv');
167-
168-
if (algorithm.additionalData !== undefined) {
169-
validateMaxBufferLength(algorithm.additionalData, 'algorithm.additionalData');
170-
}
171-
}
172-
173135
function asyncAesGcmCipher(mode, key, data, algorithm) {
174-
algorithm.tagLength ??= 128;
175-
validateAesGcmAlgorithm(algorithm);
136+
const { tagLength = 128 } = algorithm;
176137

177-
const tagByteLength = MathFloor(algorithm.tagLength / 8);
138+
const tagByteLength = tagLength / 8;
178139
let tag;
179140
switch (mode) {
180141
case kWebCryptoCipherDecrypt: {
@@ -220,16 +181,7 @@ function aesCipher(mode, key, data, algorithm) {
220181
}
221182
}
222183

223-
function validateAesGenerateKeyAlgorithm(algorithm) {
224-
if (!ArrayPrototypeIncludes(kAesKeyLengths, algorithm.length)) {
225-
throw lazyDOMException(
226-
'AES key length must be 128, 192, or 256 bits',
227-
'OperationError');
228-
}
229-
}
230-
231184
async function aesGenerateKey(algorithm, extractable, keyUsages) {
232-
validateAesGenerateKeyAlgorithm(algorithm);
233185
const { name, length } = algorithm;
234186

235187
const checkUsages = ['wrapKey', 'unwrapKey'];

‎lib/internal/crypto/cfrg.js

-8
Original file line numberDiff line numberDiff line change
@@ -329,15 +329,7 @@ function cfrgImportKey(
329329
extractable);
330330
}
331331

332-
function validateEdDSASignVerifyAlgorithm(algorithm) {
333-
if (algorithm.name === 'Ed448' && algorithm.context?.byteLength) {
334-
throw lazyDOMException(
335-
'Non zero-length context is not yet supported.', 'NotSupportedError');
336-
}
337-
}
338-
339332
function eddsaSignVerify(key, data, algorithm, signature) {
340-
validateEdDSASignVerifyAlgorithm(algorithm);
341333
const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
342334
const type = mode === kSignJobModeSign ? 'private' : 'public';
343335

‎lib/internal/crypto/diffiehellman.js

-13
Original file line numberDiff line numberDiff line change
@@ -297,22 +297,9 @@ function diffieHellman(options) {
297297
}
298298

299299
let masks;
300-
301-
function validateEcdhDeriveBitsAlgorithmAndLength(algorithm, length) {
302-
if (algorithm.public.type !== 'public') {
303-
throw lazyDOMException(
304-
'algorithm.public must be a public key', 'InvalidAccessError');
305-
}
306-
307-
if (algorithm.name !== algorithm.public.algorithm.name) {
308-
throw lazyDOMException(`algorithm.public must be an ${algorithm.name} key`, 'InvalidAccessError');
309-
}
310-
}
311-
312300
// The ecdhDeriveBits function is part of the Web Crypto API and serves both
313301
// deriveKeys and deriveBits functions.
314302
async function ecdhDeriveBits(algorithm, baseKey, length) {
315-
validateEcdhDeriveBitsAlgorithmAndLength(algorithm, length);
316303
const { 'public': key } = algorithm;
317304

318305
if (baseKey.type !== 'private') {

‎lib/internal/crypto/ec.js

-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const {
4-
ObjectPrototypeHasOwnProperty,
54
SafeSet,
65
} = primordials;
76

@@ -76,16 +75,7 @@ function createECPublicKeyRaw(namedCurve, keyData) {
7675
return new PublicKeyObject(handle);
7776
}
7877

79-
function validateEcKeyAlgorithm(algorithm) {
80-
if (!ObjectPrototypeHasOwnProperty(kNamedCurveAliases, algorithm.namedCurve)) {
81-
throw lazyDOMException(
82-
'Unrecognized namedCurve',
83-
'NotSupportedError');
84-
}
85-
}
86-
8778
async function ecGenerateKey(algorithm, extractable, keyUsages) {
88-
validateEcKeyAlgorithm(algorithm);
8979
const { name, namedCurve } = algorithm;
9080

9181
const usageSet = new SafeSet(keyUsages);
@@ -158,7 +148,6 @@ function ecImportKey(
158148
extractable,
159149
keyUsages,
160150
) {
161-
validateEcKeyAlgorithm(algorithm);
162151
const { name, namedCurve } = algorithm;
163152

164153
let keyObject;

‎lib/internal/crypto/hkdf.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function hkdfSync(hash, key, salt, info, length) {
138138
}
139139

140140
const hkdfPromise = promisify(hkdf);
141-
function validateHkdfDeriveBitsAlgorithmAndLength(algorithm, length) {
141+
function validateHkdfDeriveBitsLength(length) {
142142
if (length === null)
143143
throw lazyDOMException('length cannot be null', 'OperationError');
144144
if (length % 8) {
@@ -149,7 +149,7 @@ function validateHkdfDeriveBitsAlgorithmAndLength(algorithm, length) {
149149
}
150150

151151
async function hkdfDeriveBits(algorithm, baseKey, length) {
152-
validateHkdfDeriveBitsAlgorithmAndLength(algorithm, length);
152+
validateHkdfDeriveBitsLength(length);
153153
const { hash, salt, info } = algorithm;
154154

155155
if (length === 0)

‎lib/internal/crypto/keygen.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ const {
3333
parsePrivateKeyEncoding,
3434
} = require('internal/crypto/keys');
3535

36-
const {
37-
kAesKeyLengths,
38-
} = require('internal/crypto/util');
39-
4036
const {
4137
customPromisifyArgs,
4238
kEmptyObject,
@@ -355,7 +351,7 @@ function generateKeyJob(mode, keyType, options) {
355351
validateInteger(length, 'options.length', 8, 2 ** 31 - 1);
356352
break;
357353
case 'aes':
358-
validateOneOf(length, 'options.length', kAesKeyLengths);
354+
validateOneOf(length, 'options.length', [128, 192, 256]);
359355
break;
360356
default:
361357
throw new ERR_INVALID_ARG_VALUE(

‎lib/internal/crypto/mac.js

-31
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,7 @@ const {
4040

4141
const generateKey = promisify(_generateKey);
4242

43-
function validateHmacGenerateKeyAlgorithm(algorithm) {
44-
if (algorithm.length !== undefined) {
45-
if (algorithm.length === 0)
46-
throw lazyDOMException(
47-
'Zero-length key is not supported',
48-
'OperationError');
49-
50-
// The Web Crypto spec allows for key lengths that are not multiples of 8. We don't.
51-
if (algorithm.length % 8) {
52-
throw lazyDOMException(
53-
'Unsupported algorithm.length',
54-
'NotSupportedError');
55-
}
56-
}
57-
}
58-
5943
async function hmacGenerateKey(algorithm, extractable, keyUsages) {
60-
validateHmacGenerateKeyAlgorithm(algorithm);
6144
const { hash, name } = algorithm;
6245
let { length } = algorithm;
6346

@@ -96,27 +79,13 @@ function getAlgorithmName(hash) {
9679
}
9780
}
9881

99-
function validateHmacImportKeyAlgorithm(algorithm) {
100-
if (algorithm.length !== undefined) {
101-
if (algorithm.length === 0) {
102-
throw lazyDOMException('Zero-length key is not supported', 'DataError');
103-
}
104-
105-
// The Web Crypto spec allows for key lengths that are not multiples of 8. We don't.
106-
if (algorithm.length % 8) {
107-
throw lazyDOMException('Unsupported algorithm.length', 'NotSupportedError');
108-
}
109-
}
110-
}
111-
11282
function hmacImportKey(
11383
format,
11484
keyData,
11585
algorithm,
11686
extractable,
11787
keyUsages,
11888
) {
119-
validateHmacImportKeyAlgorithm(algorithm);
12089
const usagesSet = new SafeSet(keyUsages);
12190
if (hasAnyNotIn(usagesSet, ['sign', 'verify'])) {
12291
throw lazyDOMException(

‎lib/internal/crypto/pbkdf2.js

+2-7
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,7 @@ function check(password, salt, iterations, keylen, digest) {
9292
}
9393

9494
const pbkdf2Promise = promisify(pbkdf2);
95-
function validatePbkdf2DeriveBitsAlgorithmAndLength(algorithm, length) {
96-
if (algorithm.iterations === 0)
97-
throw lazyDOMException(
98-
'iterations cannot be zero',
99-
'OperationError');
100-
95+
function validatePbkdf2DeriveBitsLength(length) {
10196
if (length === null)
10297
throw lazyDOMException('length cannot be null', 'OperationError');
10398

@@ -109,7 +104,7 @@ function validatePbkdf2DeriveBitsAlgorithmAndLength(algorithm, length) {
109104
}
110105

111106
async function pbkdf2DeriveBits(algorithm, baseKey, length) {
112-
validatePbkdf2DeriveBitsAlgorithmAndLength(algorithm, length);
107+
validatePbkdf2DeriveBitsLength(length);
113108
const { iterations, hash, salt } = algorithm;
114109

115110
if (length === 0)

‎lib/internal/crypto/rsa.js

+5-11
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,17 @@ function rsaOaepCipher(mode, key, data, algorithm) {
111111
algorithm.label));
112112
}
113113

114-
function validateRsaKeyGenerateAlgorithm(algorithm) {
114+
async function rsaKeyGenerate(
115+
algorithm,
116+
extractable,
117+
keyUsages,
118+
) {
115119
const publicExponentConverted = bigIntArrayToUnsignedInt(algorithm.publicExponent);
116120
if (publicExponentConverted === undefined) {
117121
throw lazyDOMException(
118122
'The publicExponent must be equivalent to an unsigned 32-bit value',
119123
'OperationError');
120124
}
121-
122-
return publicExponentConverted;
123-
}
124-
125-
async function rsaKeyGenerate(
126-
algorithm,
127-
extractable,
128-
keyUsages,
129-
) {
130-
const publicExponentConverted = validateRsaKeyGenerateAlgorithm(algorithm);
131125
const {
132126
name,
133127
modulusLength,

‎lib/internal/crypto/util.js

-12
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ const kNamedCurveAliases = {
168168
'P-521': 'secp521r1',
169169
};
170170

171-
const kAesKeyLengths = [128, 192, 256];
172-
173171
const kSupportedAlgorithms = {
174172
'digest': {
175173
'SHA-1': null,
@@ -416,14 +414,6 @@ function hasAnyNotIn(set, checks) {
416414
return false;
417415
}
418416

419-
function validateByteLength(buf, name, target) {
420-
if (buf.byteLength !== target) {
421-
throw lazyDOMException(
422-
`${name} must contain exactly ${target} bytes`,
423-
'OperationError');
424-
}
425-
}
426-
427417
const validateByteSource = hideStackFrames((val, name) => {
428418
val = toBuf(val);
429419

@@ -597,11 +587,9 @@ module.exports = {
597587
toBuf,
598588

599589
kNamedCurveAliases,
600-
kAesKeyLengths,
601590
normalizeAlgorithm,
602591
normalizeHashName,
603592
hasAnyNotIn,
604-
validateByteLength,
605593
validateByteSource,
606594
validateKeyOps,
607595
jobPromise,
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.