Skip to main content
Key Derivation Functions Beginner

PBKDF2: Password-Based Key Derivation

For nearly two decades, PBKDF2's answer to password cracking was simple: make every guess expensive by repeating a hash thousands of times. Here's how it works, and why memory-hard successors like Argon2 eventually surpassed it.

PL
Pashalis Laoutaris
August 4, 2026
5 min read

Interactive PBKDF2 Visualizer

🔐 PBKDF2 Key Derivation

Real PBKDF2-HMAC-SHA256 — verified against a standard library implementation. High iteration counts will take a moment.
Enter text and click a button to start!
Iteration:
Click Derive Key to run PBKDF2.

PBKDF2: Password-Based Key Derivation

Introduction

Passwords make terrible encryption keys directly: they’re short, guessable, and drawn from a much smaller space than a proper cryptographic key. PBKDF2 (Password-Based Key Derivation Function 2), standardized in RFC 2898 back in 2000, addresses this with a simple but effective idea: apply a pseudorandom function — almost always HMACmany thousands of times in a row, deliberately making each password guess computationally expensive, rather than the near-instant single hash an attacker would otherwise get to try.

Table of Contents

The Core Idea: Deliberate Slowness

A single SHA-256 hash of a password takes a fraction of a microsecond — meaning an attacker with a stolen password database and a GPU can try billions of guesses per second against unsalted, un-stretched hashes. PBKDF2’s fix: instead of hashing the password once, run HMAC repeatedly — often tens of thousands or hundreds of thousands of times — chaining each output into the next round’s input. A legitimate login only pays this cost once, adding a barely noticeable delay; an attacker trying billions of candidate passwords pays it billions of times over.

How PBKDF2 Works

For each 32-byte (or hash-output-sized) block of the derived key:

U1 = HMAC(password, salt || block_index)
U2 = HMAC(password, U1)
U3 = HMAC(password, U2)
...
Uc = HMAC(password, U(c-1))

Block = U1 XOR U2 XOR U3 XOR ... XOR Uc

where c is the configured iteration count. If more output bytes are needed than one hash produces, additional blocks are derived the same way with an incrementing block index, and the results concatenated. The XOR-of-all-iterations construction (rather than just using the final HMAC output) is a deliberate design choice: it ensures that even if an attacker could somehow predict or shortcut a later iteration, they’d still need the full chain to reconstruct the correct final value.

Interactive Visualizer

The visualizer above runs genuine PBKDF2-HMAC-SHA256 — real iterated HMAC, real XOR chaining — and was verified against a standard cryptographic library’s PBKDF2 implementation before being published here. Try increasing the iteration count and watch how much longer the derivation takes, even for a tiny demo.

Choosing an Iteration Count

PBKDF2’s security is directly proportional to its iteration count: higher counts mean slower brute-forcing, but also slower legitimate logins. Modern guidance (OWASP, NIST) recommends iteration counts in the hundreds of thousands for PBKDF2-HMAC-SHA256, adjusted upward over time as hardware gets faster — a moving target that requires periodically re-hashing stored credentials with higher counts as recommendations increase, which is itself an operational burden PBKDF2 places on system maintainers.

A Verified Example

Using standard demonstration parameters:

  • Password: “password”
  • Salt: “salt123”
  • Iterations: 1,000
  • Output length: 32 bytes

produces a specific, deterministic 32-byte derived key — exactly what the visualizer above reproduces, matching a standard cryptographic library’s PBKDF2-HMAC-SHA256 output byte for byte.

PBKDF2’s Limitation, and What Replaced It

PBKDF2’s iteration-based slowdown has one significant weakness: it requires almost no memory to compute, which means GPUs and custom ASICs — extremely good at massively parallel arithmetic with minimal memory per unit — can still brute-force PBKDF2-protected passwords dramatically faster than a general-purpose CPU, even at high iteration counts. This exact weakness is what motivated the 2013-2015 Password Hashing Competition and its winner, Argon2, which adds deliberate memory-hardness on top of iteration count, closing the GPU/ASIC advantage far more effectively. PBKDF2 remains acceptable — and is still mandated in some compliance standards and legacy systems — but Argon2id is the modern recommendation for new password-hashing systems where it’s available.

FAQ

Is PBKDF2 still safe to use?

With a sufficiently high iteration count (hundreds of thousands, per current OWASP guidance) it remains an acceptable choice, particularly where compliance requirements mandate it or where Argon2 isn’t available. For new systems without such constraints, Argon2id is the stronger modern recommendation.

Why does PBKDF2 XOR all the intermediate HMAC outputs together instead of just using the last one?

It’s a defense-in-depth design choice from the original specification — combining every intermediate value means an attacker gains nothing from guessing or shortcutting any single iteration in the middle of the chain; the full sequential chain is always required.

What’s the difference between PBKDF2 and bcrypt?

Both are iterated, deliberately slow password-hashing functions from a similar era, but bcrypt is built around a modified Blowfish key schedule rather than HMAC, and has somewhat better (though still limited compared to Argon2) resistance to GPU-based cracking due to its internal memory access patterns.

How is PBKDF2 different from HKDF?

HKDF is designed to expand an already-strong secret (like a Diffie-Hellman shared value) into multiple derived keys quickly. PBKDF2 is designed for the opposite scenario — deliberately slowing down derivation from a weak, guessable secret like a human password. Using HKDF for password hashing (skipping the deliberate slowness) would be insecure.

Why is a higher iteration count more secure?

Each additional iteration adds a fixed, unavoidable amount of computation to both legitimate derivation and any brute-force attempt. Since the legitimate cost (one login) is negligible even at high counts, while the attacker’s cost multiplies across every single password guess they try, increasing the iteration count directly increases the total computational cost of any brute-force attack.

References

  1. RFC 2898. “PKCS #5: Password-Based Cryptography Specification Version 2.0.” IETF, 2000. Available at: https://datatracker.ietf.org/doc/html/rfc2898

  2. RFC 8018. “PKCS #5: Password-Based Cryptography Specification Version 2.1.” IETF, 2017 (updated specification).

  3. OWASP. “Password Storage Cheat Sheet.” Available at: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html

  4. Wikipedia. “PBKDF2.” Available at: https://en.wikipedia.org/wiki/PBKDF2