Skip to content

Commit f3ba4c7

Browse files
committed
refactor: use Double HMAC pattern for AES-CBC tag comparison
fixes #752
1 parent 8a0da69 commit f3ba4c7

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

src/lib/decrypt.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,26 @@ import { checkEncCryptoKey } from './crypto_key.js'
88
import invalidKeyInput from './invalid_key_input.js'
99
import { isCryptoKey } from './is_key_like.js'
1010

11-
let timingSafeEqual: (a: Uint8Array, b: Uint8Array) => boolean =
12-
// @ts-expect-error
13-
globalThis.process?.getBuiltinModule?.('node:crypto')?.timingSafeEqual
14-
15-
timingSafeEqual ||= (a: Uint8Array, b: Uint8Array): boolean => {
11+
async function timingSafeEqual(a: Uint8Array, b: Uint8Array): Promise<boolean> {
1612
if (!(a instanceof Uint8Array)) {
1713
throw new TypeError('First argument must be a buffer')
1814
}
1915
if (!(b instanceof Uint8Array)) {
2016
throw new TypeError('Second argument must be a buffer')
2117
}
22-
if (a.length !== b.length) {
23-
throw new TypeError('Input buffers must have the same length')
24-
}
2518

26-
const len = a.length
19+
const algorithm = { name: 'HMAC', hash: 'SHA-256' }
20+
const key = (await crypto.subtle.generateKey(algorithm, false, ['sign'])) as CryptoKey
21+
22+
const aHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, a))
23+
const bHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, b))
24+
2725
let out = 0
2826
let i = -1
29-
while (++i < len) {
30-
out |= a[i] ^ b[i]
27+
while (++i < 32) {
28+
out |= aHmac[i] ^ bHmac[i]
3129
}
30+
3231
return out === 0
3332
}
3433

@@ -69,7 +68,7 @@ async function cbcDecrypt(
6968

7069
let macCheckPassed!: boolean
7170
try {
72-
macCheckPassed = timingSafeEqual(tag, expectedTag)
71+
macCheckPassed = await timingSafeEqual(tag, expectedTag)
7372
} catch {
7473
//
7574
}

0 commit comments

Comments
 (0)