Password Hash Speed Test
Watch SHA-256, PBKDF2 and bcrypt race on the same input.
Picking a password hash is two decisions, and most advice only covers the first. <strong>Which algorithm</strong> is settled: OWASP puts Argon2id first, then scrypt, then PBKDF2 for FIPS environments, and classifies <strong>bcrypt as legacy-only</strong> — a demotion that contradicts a great deal of older internet advice. <strong>Which parameters</strong> is the harder question, because the right answer depends on your hardware and your latency budget. This tool benchmarks OWASP's recommended parameter sets on the device you are using right now and tells you which one fits. Everything runs locally; no password is involved and nothing is uploaded.
How long a single password verification may take. Interactive logins commonly tolerate 250–1000 ms. Higher is more resistant to offline cracking, but also more expensive to serve and easier to abuse for denial of service.
| Algorithm | Parameters | Measured | Verdict | Fidelity |
|---|
How to read these numbers. PBKDF2 runs on the browser's native Web Crypto implementation and is broadly representative. Argon2id runs as WebAssembly, which is close to native speed. bcrypt runs as pure JavaScript (bcryptjs), which is materially slower than a native server implementation — treat its timings as an upper bound on cost, not a prediction of your server. Above all, this measures your current device; a production server is usually faster than a laptop and much faster than a phone. Re-run this on hardware that resembles production before committing to a setting.
scrypt has no Web Crypto primitive, so it is not benchmarked here rather than shipping a misleading pure-JavaScript timing. These are the OWASP-recommended sets, each considered equivalent in strength — pick based on how much memory you can afford per hash:
A password hash is deliberately slow. That is the entire point: it is the only defence that still works after an attacker has your database, because it makes each guess expensive. The algorithm determines what kind of expensive — bcrypt and PBKDF2 are primarily CPU-bound, while Argon2id and scrypt are also memory-hard, which is what makes them resistant to the GPU and ASIC farms that make CPU-only hashing cheap to parallelise. That memory-hardness is the reason OWASP now ranks Argon2id first and bcrypt last.
But an algorithm with weak parameters is worse than a lesser algorithm with strong ones. Argon2id at trivial memory is not meaningfully better than bcrypt at cost 12, and PBKDF2 at the 1,000 iterations someone hard-coded in 2013 is close to useless against modern hardware. The recommended iteration counts climb every few years precisely because attacker hardware does — which is why the parameters belong stored alongside each hash, in the encoded hash string, rather than as a global constant you have to migrate all at once. Every modern format does this, and it is what lets you raise the cost for a user transparently on their next successful login.
The remaining question is how far you can push before your own users feel it. That is not answerable from a table, because it depends on your hardware and your peak login rate: the same Argon2id setting that takes 60 ms on a server might take 400 ms on a low-end phone, and every concurrent login holds that memory for the duration. The honest method is to measure on hardware resembling production, pick the slowest configuration inside your latency budget, and revisit it when you upgrade. That is what this tool automates for the recommended sets.
m=46 MiB, t=1, p=1; m=19 MiB, t=2, p=1; m=12 MiB, t=3, p=1; m=9 MiB, t=4, p=1; and m=7 MiB, t=5, p=1. They trade memory against time — pick based on how much memory you can afford to spend per concurrent hash. Note that the first two are specified for Argon2id and should not be used with Argon2i.bcrypt(base64(hmac-sha384(data:$password, key:$pepper)), $salt, $cost), because a naive pre-hash reintroduces password-shucking risk.