31 lines
969 B
JavaScript
31 lines
969 B
JavaScript
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
|
|
}
|