Start · Sprachen · JavaScript · Snippets · Passwort hashen mit SubtleCrypto

Passwort hashen mit SubtleCrypto

Krypto & Passwörter

Hasht Passwörter mit PBKDF2-SHA256 (600k Iterationen, zufälliger Salt) über die Web Crypto API und prüft sie mit zeitkonstantem Vergleich. Funktioniert im Browser und in Node.js ab Version 20.

Code

const b64 = (b) => btoa(String.fromCharCode(...new Uint8Array(b)));
const unb64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));

const derive = async (pw, salt, iterations) => {
  const key = await crypto.subtle.importKey('raw', new TextEncoder().encode(pw), 'PBKDF2', false, ['deriveBits']);
  return crypto.subtle.deriveBits({ name: 'PBKDF2', hash: 'SHA-256', salt, iterations }, key, 256);
};

// Format: iter$salt$hash
const hashPassword = async (pw, iter = 600_000) => {
  const salt = crypto.getRandomValues(new Uint8Array(16));
  return `${iter}$${b64(salt)}$${b64(await derive(pw, salt, iter))}`;
};

const verifyPassword = async (pw, stored) => {
  const [iter, salt, hash] = stored.split('$');
  const a = new Uint8Array(await derive(pw, unb64(salt), +iter));
  const b = unb64(hash);
  // zeitkonstanter Vergleich
  return a.length === b.length && a.reduce((d, x, i) => d | (x ^ b[i]), 0) === 0;
};
await hashPassword('geheim') // "600000$kJ3v...==$Qx8f...=" await verifyPassword('geheim', h) // true await verifyPassword('falsch', h) // false