Lion Cipher Lab
Implement PBKDF2 from scratch, and measure what each iteration buys you
- Foundations
- Intermediate
- ~75 min
- Free · no account required
Why it matters
Almost every security checklist says 'hash passwords with a slow, salted function', and PBKDF2 is the one that ships everywhere: in Python's standard library, in FIPS-validated crypto modules, in Wi-Fi WPA2 and in Kerberos. But 'slow' is a number, and most people who set that number copied it. In this lab you build PBKDF2 yourself from its RFC, on top of an HMAC you also build, and prove both against published test vectors you did not produce. Then you measure what the iteration count actually buys. Each iteration adds the same cost to the defender's single login and to every one of the…
What you'll learn
- building HMAC-SHA256 from RFC 2104 on top of hashlib.sha256 (ipad 0x36, opad 0x5C, 64-byte block, long keys hashed first) and proving it on RFC 4231 test cases 1, 2, 3, 6 and 7 (5/5) and against Python's hmac module
- building PBKDF2 from RFC 8018 section 5.2: the F function, the U1 xor U2 xor ... xor Uc chain, INT(i) as a 4-byte big-endian block index, and multi-block output truncated to dkLen
- proving it on the six RFC 6070 PBKDF2-HMAC-SHA1 vectors (the 16,777,216-iteration one took 209.70 s in pure Python) and a seeded 400-case differential test against hashlib.pbkdf2_hmac, 271 of them multi-block
- seeing why test coverage matters: a planted 'same block index' bug still passed 4 of 5 RFC 6070 vectors and failed exactly the 271 multi-block random cases
- measuring the iteration count's price on real hardware: 600,000 iterations of PBKDF2-HMAC-SHA256 cost 0.94 CPU-seconds per login on a Ryzen 3 3250U, so a 10,000-word guess list costs about 2.6 CPU-hours per salted user
- checking a number against its source: OWASP's 600,000 for PBKDF2-HMAC-SHA256 (raised from 310,000 in January 2023), NIST SP 800-132's 2010 minimum of 1,000 and its 128-bit salt rule
- demonstrating three honest limits with your own code: no memory hardness (scrypt refuses 128 MiB by default, PBKDF2 needs a few hundred bytes), the HMAC long-password quirk (a 65-byte password and its SHA-256 derive the same key), and the login endpoint as a CPU lever (24 bogus logins pushed an honest login from 3.08 s to 5.67 s)
Steps in this lab
- What you are building, and the words you need
- Set up: a terminal, Python, and a lab folder
- Write HMAC, then PBKDF2, straight from the RFCs
- Prove it against numbers you did not produce
- Plant a bug: what single-block tests miss
- Measure what each iteration costs, for the defender and the attacker
- Check your number against OWASP and NIST, and see how it aged
- Show that the salt matters, with two users and one password
- Honest negative 1: PBKDF2 is not memory-hard
- Honest negative 2: the long-password quirk, and the long-password cost trap
- Honest negative 3: your iteration count is a lever on your own login endpoint
- Do it better: what to ship, and when PBKDF2 is the wrong choice