Key Derivation Functions (PBKDF2, HKDF)
Learn about key derivation functions: PBKDF2 for password-based key derivation and HKDF for deriving multiple keys from a master secret. Includes Web Crypto API examples and parameter guidance.
Detailed Explanation
Key Derivation Functions: PBKDF2 and HKDF
Key Derivation Functions (KDFs) transform input keying material into one or more cryptographically strong keys. Two KDFs are supported by the Web Crypto API and are widely used in modern applications: PBKDF2 and HKDF.
PBKDF2: Password-Based Key Derivation
PBKDF2 (Password-Based Key Derivation Function 2) converts a human-memorable password into a high-entropy encryption key. It uses three mechanisms to resist brute-force attacks:
- Salt — A random value that prevents precomputed dictionary attacks (rainbow tables)
- Iteration count — Repeats the hash function many times, making each guess expensive
- Hash function — Typically SHA-256 or SHA-512
// Web Crypto API — PBKDF2
const passwordBytes = new TextEncoder().encode("user-password");
const salt = crypto.getRandomValues(new Uint8Array(16));
const baseKey = await crypto.subtle.importKey(
"raw", passwordBytes, "PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 600000, // OWASP 2023 recommendation
hash: "SHA-256",
},
baseKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
Iteration Count Guidelines
The iteration count should be as high as tolerable for your use case:
| Year | OWASP Recommendation (SHA-256) |
|---|---|
| 2017 | 100,000 |
| 2021 | 310,000 |
| 2023 | 600,000 |
Higher iteration counts directly increase the time required for each password guess, but also increase legitimate key derivation time. Target 100-500ms on your target hardware.
HKDF: Extract-and-Expand Key Derivation
HKDF (HMAC-based Key Derivation Function) derives one or more keys from a high-entropy secret (not a password). It operates in two phases:
- Extract — Condenses the input key material into a fixed-length pseudorandom key
- Expand — Generates the required number of output key bytes using an info parameter
// Derive multiple keys from a shared secret
const sharedSecret = /* from ECDH key agreement */;
const baseKey = await crypto.subtle.importKey(
"raw", sharedSecret, "HKDF", false, ["deriveKey", "deriveBits"]
);
// Derive an encryption key
const encryptionKey = await crypto.subtle.deriveKey(
{ name: "HKDF", hash: "SHA-256",
salt: new Uint8Array(0),
info: new TextEncoder().encode("encryption") },
baseKey,
{ name: "AES-GCM", length: 256 },
false, ["encrypt", "decrypt"]
);
// Derive a separate authentication key
const authKey = await crypto.subtle.deriveBits(
{ name: "HKDF", hash: "SHA-256",
salt: new Uint8Array(0),
info: new TextEncoder().encode("authentication") },
baseKey,
256
);
PBKDF2 vs HKDF: When to Use Each
| PBKDF2 | HKDF | |
|---|---|---|
| Input | Low-entropy password | High-entropy secret |
| Purpose | Make brute-force expensive | Derive multiple keys |
| Slowness | Intentionally slow | Fast |
| Iterations | 600,000+ | N/A |
| Use case | Password → encryption key | Shared secret → multiple keys |
Important Distinctions
- Never use HKDF on passwords — HKDF is fast and offers no brute-force resistance
- Never use PBKDF2 to derive multiple keys — Use PBKDF2 to derive one master key, then HKDF to derive sub-keys
- Always use a unique salt with PBKDF2 — Two users with the same password should get different keys
- Use the info parameter in HKDF to separate keys for different purposes (encryption vs authentication)
Alternatives to PBKDF2
For password hashing (not browser-compatible via Web Crypto):
- Argon2 — Memory-hard, winner of the Password Hashing Competition
- scrypt — Memory-hard, used in some cryptocurrency protocols
- bcrypt — Time-tested, widely supported
These are preferred for server-side password hashing but are not available in the Web Crypto API.
Use Case
Key derivation functions are essential for any application that derives encryption keys from passwords. Browser-based encryption tools (encrypted note apps, file encryption, password managers) use PBKDF2 to convert user passwords into AES keys. The TLS and Signal protocols use HKDF to derive session keys from key agreement outputs. Understanding the distinction between PBKDF2 (slow, for passwords) and HKDF (fast, for secrets) prevents one of the most common cryptographic design errors.