Skip to content

Commit c1512be

Browse files
committed
fix: limit default PBES2 alg's computational expense
Also adds an option to opt-in to higher computation expense.
1 parent 2269f4b commit c1512be

File tree

4 files changed

+22
-1
lines changed

4 files changed

+22
-1
lines changed

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,10 @@ operation.
14901490
- `keyManagementAlgorithms`: `string[]` Array of algorithms to accept as the `alg` (key management),
14911491
when the JWE does not use an Key Management algorithm from this list the decryption will fail.
14921492
**Default:** 'undefined' - accepts all algorithms available on the key or key store.
1493+
- `maxPBES2Count`: `number` (PBES2 Key Management Algorithms only) Maximum allowed "p2c" (PBES2
1494+
Count) Header Parameter value. The PBKDF2 iteration count defines the algorithm's computational
1495+
expense.
1496+
**Default:** '10000'
14931497
- `complete`: `<boolean>` When true returns an object with the parsed headers, verified
14941498
AAD, the content encryption key, the key that was used to unwrap or derive the content
14951499
encryption key, and cleartext instead of only the cleartext.

lib/jwe/decrypt.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const validateAlgorithms = (algorithms, option) => {
5252
/*
5353
* @public
5454
*/
55-
const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, keyManagementAlgorithms, contentEncryptionAlgorithms } = {}) => {
55+
const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, keyManagementAlgorithms, contentEncryptionAlgorithms, maxPBES2Count = 10000 } = {}) => {
5656
key = getKey(key, true)
5757

5858
keyManagementAlgorithms = validateAlgorithms(keyManagementAlgorithms, 'keyManagementAlgorithms')
@@ -142,6 +142,12 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c
142142

143143
check(key, ...(alg === 'dir' ? ['decrypt', enc] : ['keyManagementDecrypt', alg]))
144144

145+
if (alg.startsWith('PBES2')) {
146+
if (opts && opts.p2c > maxPBES2Count) {
147+
throw new errors.JWEInvalid('JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds')
148+
}
149+
}
150+
145151
try {
146152
if (alg === 'dir') {
147153
cek = JWK.asKey(key, { alg: enc, use: 'enc' })

test/jwe/sanity.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,13 @@ test('"enc" value must be supported error (when no alg was specified)', t => {
606606
JWE.encrypt('foo', k, { enc: 'foo' })
607607
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported encrypt alg: foo' })
608608
})
609+
610+
if (!('electron' in process.versions)) {
611+
test('decrypt PBES2 p2c limit', t => {
612+
const k = generateSync('oct', 256)
613+
const jwe = JWE.encrypt('foo', k, { alg: 'PBES2-HS256+A128KW' })
614+
t.throws(() => {
615+
JWE.decrypt(jwe, k, { maxPBES2Count: 1000 })
616+
}, { instanceOf: errors.JWEInvalid, message: 'JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds' })
617+
})
618+
}

types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ export namespace JWE {
401401
crit?: string[];
402402
contentEncryptionAlgorithms?: string[];
403403
keyManagementAlgorithms?: string[];
404+
maxPBES2Count?: number;
404405
}
405406

406407
interface completeDecrypt {

0 commit comments

Comments
 (0)