PBKDF2 is the oldest algorithm in this site's password-hashing coverage by a wide margin — standardized as part of PKCS #5 v2.0 by RSA Laboratories in 2000, two decades before Argon2 existed — and it's still everywhere: WPA2 Wi-Fi passphrases, iOS and Android keychains, FileVault, countless NIST-compliance-driven systems. Understanding exactly what it does mechanically explains both why it's still considered acceptable and why it's not most people's first choice anymore.
The construction: a chain of PRF calls, XORed together
PBKDF2 doesn't hash the password directly, over and over, the way a naive hash(hash(hash(password))) scheme might. Its core function, defined precisely in RFC 8018, builds each output block like this:
U1 = PRF(password, salt || blockIndex)
U2 = PRF(password, U1)
U3 = PRF(password, U2)
...
Uc = PRF(password, U(c-1))
F = U1 XOR U2 XOR U3 XOR ... XOR UcPRF is almost always HMAC with some hash function — HMAC-SHA256 is the current default. Each U value feeds into the next call as input, which means the chain is genuinely sequential: computing U500 requires having already computed U499, all the way back to U1. There's no way to jump ahead. The final XOR of every intermediate value together is, per the RFC's own description, a "belt-and-suspenders" move — even if one particular U value happened to have some exploitable structure, XORing it with every other one washes that out.
The iteration count c is the whole game: RFC 8018 states plainly that an iteration count of c "will increase the security strength of a password by log2(c) bits against trial-based attacks" — going from 1,000 iterations to 1,024,000 is a straightforward 10-bit increase in effective security, no more complicated than that.
Why this doesn't resist GPUs the way Argon2 or scrypt do
The chain above is sequential per password guess — but nothing stops an attacker from running millions of independent chains, for millions of different guesses, fully in parallel. Each individual PBKDF2 computation needs almost no memory — HMAC-SHA256 state fits in a few hundred bytes — so a GPU with thousands of cores can run thousands of separate guesses simultaneously, each one only constrained by the iteration count, not by any shared memory bottleneck. That's the exact gap Why SHA-256 Should Not Be Used for Passwords works through in concrete numbers: an RTX 4090 computing raw SHA-256 at roughly 21 billion hashes per second drops to roughly 35,000 guesses per second once wrapped in PBKDF2-HMAC-SHA256 at 600,000 iterations — a real, six-order-of-magnitude slowdown, and also the entire security margin PBKDF2 has to offer. Argon2 and scrypt add a second, independent lever — memory that has to be held per guess — that PBKDF2's design never included.
The iteration count problem, concretely
PBKDF2's standards history is exactly why so many older systems have wildly insufficient settings baked in. NIST's original guidance called 1,000 iterations an acceptable minimum — reasonable in 2000, on hardware with nothing like a modern GPU behind it. Code written against that guidance, and never revisited, is still running in production systems today, twenty-five years and several orders of magnitude of attacker compute later. OWASP's current recommendation is 600,000 iterations for PBKDF2-HMAC-SHA256 — 600 times the old NIST floor — and that number is expected to keep climbing the same way bcrypt's cost factor and Argon2's memory target do. If you're auditing a system that's used PBKDF2 for a long time without anyone deliberately raising the iteration count, it's very likely running at a small fraction of what's actually recommended today — the iteration count is normally stored directly alongside the hash and salt, so it's always worth checking the actual stored value rather than assuming whatever the original implementation defaulted to years ago.
Why it's still a legitimate choice
PBKDF2 remains genuinely acceptable, not just legacy cruft, in one specific circumstance: environments that require FIPS 140 validation. NIST Special Publication 800-132 formally specifies PBKDF2 for password-based key derivation, which makes it one of the few password-hashing options with that particular compliance stamp — Argon2 and scrypt don't have FIPS-approved status the way PBKDF2 does. If a system genuinely needs FIPS-140 validated cryptography, PBKDF2-HMAC-SHA256 at a high iteration count is a legitimate, deliberate choice, not a compromise — outside that specific requirement, Argon2id is the better default for the reasons covered in Bcrypt vs Argon2.
Try it yourself
Password Hash Generator computes real PBKDF2-HMAC-SHA1/SHA256/SHA512 hashes with a configurable iteration count, so you can see exactly how raising it changes the computation time. It runs entirely in your browser.