import { KEY_ID_PATTERN, isSealedWithCurrentKey, loadKeyRing, openLegacyCiphertext, openWithRing, sealWithRing, } from '../../common/crypto/key-ring'; /** * TOTP secrets must be reversible (unlike passwords/refresh tokens, which * are one-way hashed) so the server can compute the expected code on every * login. They are sealed with the MFA key ring (MFA_ENCRYPTION_KEY, see * common/crypto/key-ring.ts). Secrets stored before the key ring have no key * id and were encrypted with sha256(JWT_ACCESS_SECRET); they stay readable * until the rekey job reseals them. */ export function encryptMfaSecret(plaintext: string): string { return sealWithRing(loadKeyRing('mfa'), plaintext); } export function decryptMfaSecret(stored: string): string { return KEY_ID_PATTERN.test(stored) ? openWithRing(loadKeyRing('mfa'), stored).plaintext : openLegacyCiphertext('mfa', stored); } /** True for secrets the rekey job should reseal with the current key. */ export function mfaSecretNeedsRekey(stored: string): boolean { return !isSealedWithCurrentKey(loadKeyRing('mfa'), stored); }