Skip to content

Commit c959f30

Browse files
authored
fix: add JS-side validation for pbkdf2 iterations/keylen (#939)
1 parent 955b935 commit c959f30

2 files changed

Lines changed: 46 additions & 4 deletions

File tree

example/src/tests/pbkdf2/pbkdf2_tests.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,21 @@ algos.forEach(function (algorithm) {
195195
});
196196
});
197197

198-
// TODO(#931): enable invalid fixture tests once JS-side validation is added
199-
// for iterations/keylen. Currently invalid values (negative, NaN, Infinity)
200-
// reach the native C layer and trigger assert()/abort() instead of throwing.
201-
// See: fixtures.invalid
198+
fixtures.invalid.forEach(function (f) {
199+
test(
200+
SUITE,
201+
`invalid: ${algorithm} throws "${f.exception}" for iterations=${f.iterations} keylen=${f.dkLen}`,
202+
() => {
203+
expect(() => {
204+
crypto.pbkdf2Sync(
205+
f.key as string,
206+
f.salt as string,
207+
f.iterations as number,
208+
f.dkLen as number,
209+
algorithm,
210+
);
211+
}).to.throw(f.exception);
212+
},
213+
);
214+
});
202215
});

packages/react-native-quick-crypto/src/pbkdf2.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,33 @@ function getNative(): Pbkdf2 {
3131
return native;
3232
}
3333

34+
const MAX_INT32 = 2147483647;
35+
36+
function validateParameters(iterations: number, keylen: number): void {
37+
if (typeof iterations !== 'number') {
38+
throw new TypeError('Iterations not a number');
39+
}
40+
if (typeof keylen !== 'number') {
41+
throw new TypeError('Key length not a number');
42+
}
43+
if (
44+
iterations < 1 ||
45+
!Number.isFinite(iterations) ||
46+
!Number.isInteger(iterations) ||
47+
iterations > MAX_INT32
48+
) {
49+
throw new TypeError('Bad iterations');
50+
}
51+
if (
52+
keylen < 0 ||
53+
!Number.isFinite(keylen) ||
54+
!Number.isInteger(keylen) ||
55+
keylen > MAX_INT32
56+
) {
57+
throw new TypeError('Bad key length');
58+
}
59+
}
60+
3461
function sanitizeInput(input: BinaryLike, errorMsg: string): ArrayBuffer {
3562
try {
3663
return binaryLikeToArrayBuffer(input);
@@ -51,6 +78,7 @@ export function pbkdf2(
5178
if (callback === undefined || typeof callback !== 'function') {
5279
throw new Error('No callback provided to pbkdf2');
5380
}
81+
validateParameters(iterations, keylen);
5482
const sanitizedPassword = sanitizeInput(password, WRONG_PASS);
5583
const sanitizedSalt = sanitizeInput(salt, WRONG_SALT);
5684
const normalizedDigest = normalizeHashName(digest, HashContext.Node);
@@ -81,6 +109,7 @@ export function pbkdf2Sync(
81109
keylen: number,
82110
digest: string,
83111
): Buffer {
112+
validateParameters(iterations, keylen);
84113
const sanitizedPassword = sanitizeInput(password, WRONG_PASS);
85114
const sanitizedSalt = sanitizeInput(salt, WRONG_SALT);
86115

0 commit comments

Comments
 (0)