# crypto.pbkdf2-sha256
PBKDF2 (RFC 8018 section 5.2) with HMAC-SHA256 as its pseudorandom function:
it stretches a password and a salt into a key by running HMAC `iterations`
times, so that every guess an attacker makes costs the same. It is the
algorithm under `auth.password-hash`, which is what an application should
normally call; use this directly only to derive keys.
Bytes in and out are lists of integers 0 to 255, as everywhere in the registry
(see `encoding.hex`). Encode a text password with `encoding.utf8` first.
**How many iterations.** OWASP's Password Storage Cheat Sheet recommends
600,000 for PBKDF2-HMAC-SHA256 (2023). Measured on an Apple Silicon laptop,
one 32-byte key at a time:
| iterations | Python (hashlib) | Rust (release) | TypeScript (Node 24) |
|-----------:|-----------------:|---------------:|---------------------:|
| 100,000 | 8 ms | 48 ms | 39 ms |
| 310,000 | 24 ms | 95 ms | 113 ms |
| 600,000 | 47 ms | 178 ms | 222 ms |
so 600,000 is affordable in a login request in every language. Record the
count with the hash (`auth.password-hash` does) so it can be raised later.
**Implementation.** Python uses the standard library's
`hashlib.pbkdf2_hmac`, which runs the loop in C. TypeScript and Rust are
written out with no `node:crypto` or crates; they precompute the HMAC key's
inner and outer pad states once, and hash each 32-byte intermediate as a
single pre-padded block, which halves the work of calling HMAC naively and
allocates nothing inside the loop. That needs SHA-256's compression function
itself, which `crypto.sha256` does not expose, so it is repeated here rather
than required.
A password longer than 64 bytes is hashed first, as HMAC requires (RFC 2104),
and the key may be longer than 32 bytes: each further 32-byte block runs the
full iteration count again (RFC 8018's `T_i`), so ask for only what you use.
Empty passwords and empty salts are computed, as the RFC allows; refusing a
weak salt is `auth.password-hash`'s job (it wants 16 bytes or more).
Sources: RFC 8018, PKCS #5: Password-Based Cryptography Specification
Version 2.1, section 5.2 (https://www.rfc-editor.org/rfc/rfc8018); the
PBKDF2-HMAC-SHA256 test vectors of RFC 7914 section 11
(https://www.rfc-editor.org/rfc/rfc7914#section-11); RFC 6070's inputs
(https://www.rfc-editor.org/rfc/rfc6070) with their published SHA-256
results, each confirmed against Python's hashlib; OWASP Password Storage
Cheat Sheet (https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).