crypto.ts20 lines · main
| 1 | import { 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 | */ |
| 17 | export 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 | } |