Key derivation function (KDF) reference
A KDF turns a secret into one or more cryptographic keys. There are two very different jobs: password hashing (deliberately slow, memory-hard, designed to be expensive for an attacker) and key extraction/expansion (fast, for deriving multiple keys from an already-strong master secret). Mixing these up is a serious security mistake. This reference covers Argon2, scrypt, bcrypt, PBKDF2 and HKDF with their cost parameters and current OWASP-aligned tuning so you can store passwords safely and derive session keys correctly.
The two categories of KDF
Password hashing KDFs
These exist to make offline brute-force guessing expensive. Their defining properties are controllable slowness and, in the best cases, memory hardness.
| Function | Memory-hard? | Status | Notes |
|---|---|---|---|
| Argon2id | Yes | Recommended | PHC winner; tune m, t, p |
| scrypt | Yes | Acceptable | N, r, p parameters |
| bcrypt | Mildly | Acceptable | 72-byte input limit |
| PBKDF2-HMAC-SHA256 | No | FIPS fallback | High iteration count needed |
Key extraction and expansion KDFs
These derive keys from secrets that are already strong (for example, a Diffie-Hellman output or a master key). They are fast by design — making them unsuitable for passwords.
| Function | Typical use |
|---|---|
| HKDF | TLS, Signal, WireGuard key schedules |
| PBKDF2 (high iterations) | FIPS environments needing slow password hashing |
How password hashing works
Password KDFs add three defences against offline attack:
- Salt — a unique random value per password defeats rainbow tables and ensures two users with the same password get different hashes.
- CPU cost — iteration count (PBKDF2) or work factor (bcrypt) makes each guess take longer, multiplying the attacker’s time.
- Memory cost — a large mandatory RAM footprint (Argon2, scrypt) defeats GPU/ASIC parallelism because those chips have little memory per core.
Argon2id specifically combines data-independent memory access (resisting side-channel attacks like cache timing) with memory hardness, which is why it is the modern first choice.
Tuning guidance
- Use Argon2id for new systems. Recommended starting point:
m=19456(19 MB),t=2iterations,p=1lane. Tune upward to the maximum your server latency budget allows (typically 200–500 ms for interactive login). - For PBKDF2 in FIPS environments: use
HMAC-SHA-256and at least600,000iterations (OWASP 2023+). Iterations provide only CPU hardness, not memory hardness. - bcrypt input is silently truncated at 72 bytes. If users have long passphrases, pre-hash with SHA-256 (and base64-encode to avoid null bytes) before passing to bcrypt.
- HKDF is fast on purpose — never use it for password storage. It is the right choice for deriving separate encryption and MAC keys from a single master key.
Practical tips and notes
- Store the algorithm and parameters alongside every hash in the output string. Modern formats like
$argon2id$v=19$m=19456,t=2,p=1$...embed this automatically so you can migrate to higher costs over time without invalidating existing hashes. - Upgrade cost factors on next login, not in a batch, to avoid blocking users with a slow re-hash job.
- A password-hashed with bcrypt and a 10-work-factor from 2010 is weaker today; use the reference to identify which of your stored hashes need a cost bump.