import { randomBytes, scrypt, timingSafeEqual } from 'crypto'; import { promisify } from 'util'; const scryptAsync = promisify(scrypt); const KEY_LENGTH = 64; export async function hashPassword(password: string): Promise { const salt = randomBytes(16).toString('hex'); const derived = (await scryptAsync(password, salt, KEY_LENGTH)) as Buffer; return `scrypt:${salt}:${derived.toString('hex')}`; } export async function verifyPassword( password: string, stored: string, ): Promise { const parts = stored.split(':'); if (parts.length !== 3 || parts[0] !== 'scrypt') { return false; } const [, salt, hashHex] = parts; if (!salt || !hashHex) { return false; } try { const derived = (await scryptAsync(password, salt, KEY_LENGTH)) as Buffer; const expected = Buffer.from(hashHex, 'hex'); if (derived.length !== expected.length) { return false; } return timingSafeEqual(derived, expected); } catch { return false; } }