31 lines
982 B
JavaScript
31 lines
982 B
JavaScript
#!/usr/bin/env node
|
|
import { webcrypto } from 'node:crypto';
|
|
|
|
const password = process.argv[2];
|
|
if (!password) {
|
|
console.error('Usage: node tools/hash.mjs <password>');
|
|
process.exit(1);
|
|
}
|
|
|
|
const PBKDF2_ITERATIONS = 100_000;
|
|
const SALT_BYTES = 16;
|
|
|
|
async function hashPassword(pw) {
|
|
const enc = new TextEncoder();
|
|
const salt = webcrypto.getRandomValues(new Uint8Array(SALT_BYTES));
|
|
const baseKey = await webcrypto.subtle.importKey('raw', enc.encode(pw), 'PBKDF2', false, ['deriveBits']);
|
|
const bits = await webcrypto.subtle.deriveBits(
|
|
{ name: 'PBKDF2', salt, iterations: PBKDF2_ITERATIONS, hash: 'SHA-256' },
|
|
baseKey,
|
|
256
|
|
);
|
|
const hashArr = new Uint8Array(bits);
|
|
const saltHex = [...salt].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
const hashHex = [...hashArr].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
return `pbkdf2:${PBKDF2_ITERATIONS}:${saltHex}:${hashHex}`;
|
|
}
|
|
|
|
hashPassword(password).then((h) => {
|
|
console.log(h);
|
|
});
|