36 lines
999 B
TypeScript
36 lines
999 B
TypeScript
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<string> {
|
|
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<boolean> {
|
|
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;
|
|
}
|
|
}
|