When a company gets breached, the difference between "we reset passwords as a precaution" and "36 million credentials are circulating" usually comes down to one engineering decision made years earlier: which algorithm hashed the passwords, and with what settings. General-purpose hashes like SHA-256 compute in nanoseconds - Wonderful for checksums, catastrophic for passwords, because attackers with GPUs try billions of guesses per second. Password hashing algorithms exist to destroy that economy. Three names dominate the conversation - Argon2, bcrypt, and scrypt - And while all three are defensible, they resist modern cracking hardware in importantly different ways.
The problem: cracking hardware scales, humans don't
An offline attacker holding stolen hashes plays a pure economics game: guesses per second times seconds, against the guess-depth of each password. Consumer GPUs run SHA-256 in the tens of billions of hashes per second; a rack of them tests every eight-character password in hours. The mechanics of offline cracking haven't changed in a decade - What's changed is the hardware's appetite.
Password hashes fight back with deliberate cost, and cost comes in two currencies:
- Time-hardness: make each guess take many iterations. Effective, but GPUs and custom ASICs parallelize pure computation ruthlessly - The defender pays on one CPU core what the attacker amortizes across thousands.
- Memory-hardness: make each guess also require a chunk of RAM, touched in unpredictable patterns. Memory is the great equalizer - A GPU with 24 GB can run only ~380 parallel guesses if each demands 64 MiB, versus tens of thousands of compute-only threads. ASICs fare even worse; silicon area spent on RAM is expensive and gives no shortcut.
That distinction - Time-only versus time-plus-memory - Is the axis on which these three algorithms differ.
bcrypt: the 25-year veteran
Published in 1999 by Niels Provos and David Mazières, bcrypt derives from the Blowfish cipher and introduced the crucial idea of a built-in, adjustable cost factor: each increment doubles the work (cost 12 = 2¹² rounds of key setup). Salts are generated automatically and embedded in the output string - One reason bcrypt survived while ad-hoc salted-SHA schemes kept being implemented wrong. Our overview of why bcrypt beats MD5 and SHA-256 for passwords covers that history.
bcrypt's quirks matter in practice. It uses a small fixed ~4 KB of memory - Enough to annoy 1999-era hardware and still awkward for GPUs (its pattern of RAM access resists them better than raw SHA-256 by orders of magnitude), but far from modern memory-hardness. More sharply: it truncates input at 72 bytes, silently in many libraries - A real correctness trap for long passphrases, historically worked around (dangerously, if done naively) by pre-hashing. And its cost is time-only, so dedicated cracking rigs steadily erode any fixed setting. OWASP's floor today is a work factor of 10; many deployments run 12.
scrypt: memory-hardness arrives
Colin Percival introduced scrypt in 2009 (later RFC 7914) with exactly the insight above: force each guess to fill and repeatedly revisit a large block of RAM, and parallel hardware chokes. Its parameters - N (CPU/memory cost), r (block size), p (parallelism) - Set the footprint; OWASP's baseline of N=2¹⁷, r=8, p=1 costs about 128 MiB per guess. scrypt is well-studied and genuinely effective; it protects everything from encrypted backups to (ironically) Litecoin's proof-of-work. Its main criticisms are ergonomic: the parameters interact non-obviously, and its memory access pattern being password-dependent opens theoretical cache-timing concerns in shared environments - One of the itches Argon2 was designed to scratch.
Argon2: the competition winner and current default
By the early 2010s the field wanted a purpose-built successor, vetted in the open. The Password Hashing Competition (2013–2015) ran cryptographers' candidates through public analysis, and Argon2, by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich, won. It's now specified in RFC 9106 with three variants:
- Argon2d - Password-dependent memory access; maximally GPU-hostile, but timing-sensitive.
- Argon2i - Password-independent access; timing-safe, weaker against cracking rigs.
- Argon2id - The hybrid (first pass independent, subsequent passes dependent) that gets both benefits and is the recommended default everywhere: RFC 9106, OWASP, and NIST SP 800-63B's latest revision, which explicitly cites memory-hard functions as preferred.
Argon2's three independent dials - Memory (m), iterations (t), parallelism (p) - Let defenders tune cost precisely to their hardware budget. Widely used baselines:
| Algorithm | Year | Memory per guess | Recommended baseline (OWASP) | Watch out for |
|---|---|---|---|---|
| Argon2id | 2015 | Tunable (MiB–GiB) | m=19 MiB, t=2, p=1 minimum; RFC 9106 suggests up to 2 GiB, t=1, p=4 | Low-memory configs squander its advantage |
| scrypt | 2009 | Tunable (~128 MiB typical) | N=2¹⁷, r=8, p=1 | Interacting parameters; timing side channels |
| bcrypt | 1999 | ~4 KB fixed | Work factor ≥ 10 | 72-byte input truncation; time-only cost |
| PBKDF2 (legacy comparison) | 2000 | Negligible | 600,000 iterations (HMAC-SHA-256) | No memory-hardness - GPUs feast on it |
PBKDF2 earns its row as the cautionary contrast: pure iteration with zero memory cost, kept alive mainly by FIPS-compliance requirements, and the reason some older password-manager vaults cracked embarrassingly fast after the 2022 LastPass theft - Accounts left on early-2010s iteration counts effectively donated their margin. Same lesson at a smaller scale: parameters set once and never revisited are parameters rotting.
The algorithm is half the decision; the parameters are the other half. A well-tuned bcrypt beats a starved Argon2id - But a properly fed Argon2id beats everything.
Choosing, in practice
New system? Argon2id, full stop - It's the consensus recommendation of RFC 9106, OWASP, and modern framework defaults. Start at OWASP's floor (19 MiB, t=2, p=1) and raise memory until login verification costs a tolerable ~100–500 ms on your production hardware. Higher memory per guess buys more attacker pain than higher iteration count.
Existing bcrypt or scrypt deployment? No emergency - Both remain respectable when parameterized to current guidance. Prioritize raising cost factors over migrating algorithms, and migrate opportunistically: re-hash each user's password at their next successful login, when you briefly hold the plaintext legitimately.
Any system: add the seasoning layers. Per-user salts come free with all three algorithms; a server-side pepper adds a second factor the database thief doesn't get - Our salting and peppering guide covers that construction. And never invent your own scheme; use maintained libraries (libsodium, argon2 bindings, framework defaults) that get the details right.
$argon2id$v=19$m=65536,t=3,p=4$… or $2b$12$… (bcrypt). The parameters travel inside the string - Which is how a system can verify old hashes while writing new ones at stronger settings.What this means if you're a user
You'll almost never learn which algorithm guards a given site - So play the odds you control. Every algorithm in the table shares one property: cost per guess times number of guesses needed. The site controls the first factor; you control the second, and yours has more leverage. A password in the top million falls under any algorithm - It's simply guessed early. A random 16-character string from a password generator needs so many guesses that even PBKDF2 holds; check where any candidate falls with the password strength meter. Strong input turns every row of that table into "effectively uncrackable" - Weak input turns every row into "already cracked."
FAQ
Which is best: Argon2, bcrypt, or scrypt?
Argon2id is the modern default - It won the Password Hashing Competition, is standardized in RFC 9106, and its tunable memory-hardness ages best against GPU and ASIC cracking. bcrypt and scrypt remain perfectly defensible when configured to current OWASP baselines. The wrong answers are fast hashes (SHA-256, MD5) and any scheme you invented yourself.
Is bcrypt obsolete?
No - 25 years of scrutiny with no cryptographic break is a remarkable record, and at work factor 10–12 it still slows attackers by orders of magnitude versus fast hashes. Its real limitations are the 72-byte input truncation and time-only cost that dedicated hardware erodes steadily. For new builds choose Argon2id; for existing bcrypt systems, raising the cost factor matters more than switching.
What Argon2id parameters should I use?
Treat OWASP's minimum - 19 MiB memory, 2 iterations, parallelism 1 - As the floor, and RFC 9106's suggestions (up to 2 GiB memory with t=1, p=4, or 64 MiB with t=3, p=4) as the comfortable range. Then tune empirically: raise memory until a login verification takes roughly 100–500 ms on your servers. Revisit the numbers every couple of years; fixed parameters quietly lose ground to hardware.
Why not just use SHA-256 with a salt?
Salting defeats precomputed tables, but does nothing about speed - A single modern GPU still evaluates billions of salted SHA-256 guesses per second, versus mere thousands for a memory-hard hash. That five-to-six-order-of-magnitude gap is the entire reason purpose-built password hashes exist. Salts make attacks per-user; slow hashes make each guess expensive; you need both.
Do these algorithms protect a weak password?
Only briefly. Every cracking run tries common passwords first, so "Password123!" falls in the first seconds under Argon2id just as under MD5 - It merely costs the attacker slightly more electricity. Slow hashing multiplies the strength your password already has; multiplying near-zero yields near-zero. The protection compounds spectacularly only when the input is long and random.