crypto.ts20 lines · main
1import { timingSafeEqual } from 'node:crypto';
2
3/**
4 * Constant-time equality check for shared secrets and HMAC outputs.
5 *
6 * Why: comparing tokens with `===` runs in time proportional to the shared
7 * prefix length, which leaks byte-by-byte info to a remote attacker who
8 * can measure response latency. `timingSafeEqual` runs in time
9 * proportional to length only, regardless of content.
10 *
11 * Length-mismatch is checked up front and bails fast — for fixed-length
12 * secrets (the runtime shared secret is `>= 32` chars, HMAC outputs are
13 * fixed by digest size) the length itself is not the secret. For
14 * variable-length inputs you control, pad both sides to the same length
15 * before calling.
16 */
17export function constantTimeEqual(a: string, b: string): boolean {
18 if (a.length !== b.length) return false;
19 return timingSafeEqual(Buffer.from(a), Buffer.from(b));
20}