import { scryptSync, randomBytes } from 'node:crypto' const SALT_LEN = 16 const KEY_LEN = 64 const SCRYPT_OPTS = { N: 16384, r: 8, p: 1 } /** * Hash a password for storage. Returns "salt:hash" hex string. * @param {string} password * @returns {string} Salt and hash as hex, colon-separated. */ export function hashPassword(password) { const salt = randomBytes(SALT_LEN) const hash = scryptSync(password, salt, KEY_LEN, SCRYPT_OPTS) return `${salt.toString('hex')}:${hash.toString('hex')}` } /** * Verify password against stored "salt:hash" value. * @param {string} password * @param {string} stored * @returns {boolean} True if password matches. */ export function verifyPassword(password, stored) { if (!stored || !stored.includes(':')) return false const [saltHex, hashHex] = stored.split(':') const salt = Buffer.from(saltHex, 'hex') const hash = scryptSync(password, salt, KEY_LEN, SCRYPT_OPTS) return hash.toString('hex') === hashHex }