SBN

bcrypt vs Argon2 vs scrypt vs PBKDF2: A 2026 Decision Framework

The canonical Stack Overflow answers and the canonical security blog posts on “which password hashing function should I use” are nearly all from 2012 to 2014, recommending bcrypt. Argon2 won the Password Hashing Competition in 2015. A decade later, half the production systems I audit are still on bcrypt with cost factors picked in the Obama administration. Here is the actual 2026 decision framework.

This is not a “bcrypt is bad” post. bcrypt remains safe in 2026 if it’s tuned correctly. It is a “the conversation moved on and you may have missed it” post. The four algorithms have specific shapes, and one of them is the right pick for your situation. Let’s get to it.

The four algorithms in one paragraph each

PBKDF2 (2000). RFC 2898, designed by RSA Labs. Takes a base hash (typically SHA-256 or SHA-512), salts the password, and iterates the hash N times. The only one of the four that is FIPS 140-2 and FIPS 140-3 approved, which is why it survives in regulated environments long after newer algorithms appeared. Weakness: easily GPU-accelerated, because each iteration is a cheap SHA call. Modern attackers running ASIC or GPU rigs can test billions of PBKDF2 candidates per second. SHA-256 is the underlying primitive.

bcrypt (1999). Designed by Niels Provos and David Mazières, based on the Blowfish cipher. Adaptive cost factor (the famous “work factor”), 72-byte password ceiling (a real gotcha), 184-bit output. The brilliant property is that the Blowfish key schedule is intentionally cache-unfriendly, which historically made it expensive to parallelise on GPUs. That property degraded as GPUs got better at irregular memory access, but bcrypt remains slower to attack than PBKDF2. bcrypt reference on Hash Lab.

scrypt (2009). Designed by Colin Percival, the first “memory-hard” password hash to see real adoption. Tunes both CPU cost and memory cost, with the explicit goal of making custom hardware attacks expensive (because RAM is more expensive than gates). Used heavily in cryptocurrency mining-resistance for a while. scrypt reference.

Argon2 (2015). Winner of the Password Hashing Competition, designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. Three variants: Argon2d (data-dependent, fastest, vulnerable to side-channel attacks), Argon2i (data-independent, slower, side-channel resistant), Argon2id (hybrid, the recommended default). Tunes time cost, memory cost, and parallelism independently. Standardised as RFC 9106 in 2021. Argon2id reference.

The decision framework

Four buckets. Pick the one that matches your situation.

Bucket 1: greenfield code in 2026 – use Argon2id

You are writing new code, no library constraints, no FIPS requirement, no need to integrate with existing infrastructure. Use Argon2id.

Recommended parameters as of 2026 (server-side, interactive login, single password verification): time cost t=3, memory cost m=64 MiB, parallelism p=1. These match OWASP’s current Password Storage Cheat Sheet recommendations and produce a verification time of roughly 100ms on a modern x86 server core, which is the right tradeoff between user experience and attacker cost.

If you have more memory budget (servers with 32+ GB RAM and predictable login load), bump memory to m=256 MiB with t=2. Memory cost is what crushes ASIC and GPU attackers more than time cost does, so prefer memory if you have it.

Library: argon2-cffi for Python, argon2 crate for Rust, @node-rs/argon2 for Node (avoid the pure-JS implementations, they are 100x slower and you will pick weaker parameters to compensate). Hash Lab’s password hashing tool lets you tune parameters interactively and see the resulting verification time on your hardware.

Bucket 2: constrained environment or library-stuck – bcrypt is still safe

You are on a stack where the de-facto password hashing library is bcrypt (Rails, older Spring, anything that picked bcrypt in 2014 and never moved). Switching to Argon2id is correct in principle but expensive in practice if there is no business reason.

If you stay on bcrypt, recommended cost factor as of 2026: cost=12 minimum, cost=13 if your server can absorb it. Verify the resulting login time stays under 250ms on your production hardware. Anything below cost=10 is no longer safe in 2026 because consumer-grade GPUs can test it at hundreds of thousands of guesses per second.

Two bcrypt gotchas that bite people:

  • The 72-byte password ceiling. bcrypt truncates passwords at 72 bytes. If your application allows longer passwords, you must pre-hash with SHA-256 or SHA-512 before passing to bcrypt. The pre-hash should be deterministic and unsalted (you are not trying to add security, you are trying to compress).
  • Null byte truncation in some implementations. A handful of older bcrypt libraries truncate at the first null byte in the pre-hashed input, which means a base64-encoded SHA-256 pre-hash (which never has nulls) is safer than a raw binary pre-hash.

Bucket 3: FIPS-required environment – PBKDF2 with SHA-256

You are working in an environment that requires FIPS 140-2 or FIPS 140-3 approved primitives. Government, certain healthcare, certain financial. Argon2 is not FIPS-approved (as of mid-2026; the IETF process is ongoing). bcrypt is not FIPS-approved. scrypt is not FIPS-approved.

PBKDF2 with SHA-256 or SHA-512 is your only sanctioned option.

Recommended iteration counts as of 2026 (per OWASP and NIST SP 800-132 updated guidance): SHA-256: 600,000 iterations minimum. SHA-512: 210,000 iterations minimum. These are dramatically higher than the 10,000-iteration values that float around in legacy code. The OWASP recommendations have roughly 10x’d every 4 years as GPU compute has expanded.

You can layer a memory-hard wrapper around PBKDF2 (the “hash everything twice” trick using PBKDF2 followed by a non-FIPS memory-hard function) if you really need both FIPS compliance and memory-hardness, but this is an advanced pattern and you should consult your auditor before deploying it.

Bucket 4: scrypt

scrypt is rarely the right pick in 2026. Argon2id does everything scrypt does, better (because Argon2 had 6 more years of cryptanalysis baked into the design) and is now well-supported across mainstream stacks. The one place scrypt still wins is when you are integrating with an existing system that already uses scrypt (Litecoin-derivative codebases, certain hardware wallets), and you don’t want to introduce a new primitive.

If you must use scrypt, recommended parameters: N=2^17, r=8, p=1. This consumes 128 MiB of memory per verification. Drop N to 2^16 if memory budget is tight.

Cost-parameter tuning, generally

The right cost parameter is the highest one your servers can absorb without degrading the login user experience. The standard tradeoff: target 100 to 250ms of verification time on a production server core. Below 100ms, you are leaving attacker-cost on the table. Above 250ms, real users will feel the lag and complain.

The trap people fall into: they pick a parameter, ship it, and never revisit. Hardware gets 10x faster every 5 to 7 years. Your cost parameter should be revisited on the same cadence as your dependency upgrade cycle. Set a reminder.

One technique that helps: store the cost parameter inside the hash record (which is the default for bcrypt, Argon2, and scrypt; PBKDF2 requires you to track it yourself). On verify, if the stored cost is below your current target, transparently rehash the password at the new cost during the user’s successful login. After 6 to 12 months you will have rotated most active users without a forced password reset.

Migration patterns: how to rehash gracefully

You inherited a legacy system on PBKDF2 with 10,000 iterations, or on bcrypt cost=8, or on something embarrassing like unsalted MD5. The good news is you don’t need a forced password reset.

The pattern is to wrap the old hash in the new one at rest, and unwrap on verify. Concretely: take every existing legacy_hash and compute new_hash = argon2id(legacy_hash). Store new_hash. Mark the user record as “legacy wrapped.” On login, compute legacy_hash from the user’s submitted password, then verify new_hash matches argon2id(legacy_hash). The user’s password never touches the old algorithm during verification because the legacy_hash is already in your database.

This pattern protects every password in the database immediately (because the at-rest values are now Argon2id-wrapped) and lets you migrate users individually at next login. After you’ve rotated everyone who logs in within 12 months, you can force a password reset on the long tail. Best practices for user authentication covers the broader security framework around this.

The traps that catch people

Using SHA-256 alone (no key stretching). If your codebase computes sha256(password) or even sha256(salt + password) and stores that, you have a vulnerable system. SHA-256 is a fast hash; it is designed to be fast. A modern GPU rig tests hundreds of billions of SHA-256 candidates per second. Use one of the four password-specific algorithms above. The Hash Lab identifier can tell you what algorithm produced a given hash string if you’re inheriting a system and aren’t sure.

Storing the salt separately from the hash. Modern bcrypt, scrypt, and Argon2 hash strings include the salt and parameters in the encoded output. There is no reason to store them in a separate column, and doing so introduces a class of bugs where you accidentally lose the salt during a migration. Trust the algorithm’s serialisation format.

Inadequate cost parameters. Half the bcrypt deployments I audit run at cost=10, which was a reasonable default in 2014 and is not in 2026. The same applies to PBKDF2 systems still running 100,000 iterations.

Per-user pepper without a key management plan. A pepper (a secret added to every password before hashing, not stored in the database) is a real defense-in-depth measure, but only if you actually have a key management story for it. Without rotation, hardware backing, and recovery procedures, the pepper just becomes another secret that leaks with the database.

Mixing client-side and server-side hashing without understanding what you’re protecting against. Client-side hashing protects the password in transit (mostly handled by TLS anyway) but does not protect against database compromise (because the client-hashed value becomes the new effective password). Server-side hashing protects against database compromise. You almost always want server-side. If you want both, do client-side as a transport encoding and server-side as the durable storage hash; do not skip the server-side.

The broader context

Two adjacent points worth making explicitly.

First, passwords are not dead, despite a decade of optimism. The right long-term move is to layer passwords with passkeys, WebAuthn, and other phishing-resistant factors. But the password column is not going away in 2026, which means picking a current password hashing algorithm and tuning it correctly still matters.

Second, AI-generated passwords are not a substitute for proper hashing, but they are part of the bridge. AI password generators covers the user-side bridge.

If you want to experiment with the four algorithms hands-on (input a password, see the output, tune parameters, observe the verification time on your hardware), Hash Lab’s password hashing tool runs everything in-browser via WebCrypto and WASM. The full algorithm catalog (including hashing primitives like SHA-256, BLAKE3, and the message authentication codes) is at Hash Lab.

The summary, in one sentence: greenfield is Argon2id, legacy bcrypt is still fine if you raise the cost, FIPS environments use PBKDF2, scrypt is rarely the right pick anymore. Pick the bucket, set the parameters, and ship something that’s not from 2014.

The post bcrypt vs Argon2 vs scrypt vs PBKDF2: A 2026 Decision Framework appeared first on Deepak Gupta's notebook.

*** This is a Security Bloggers Network syndicated blog from Deepak Gupta's notebook authored by Deepak Gupta. Read the original post at: https://guptadeepak.com/bcrypt-vs-argon2-vs-scrypt-vs-pbkdf2-password-hashing-decision-framework-2026/

Avatar photo

Deepak Gupta

Deepak is the CTO and co-founder of LoginRadius, a rapidly-expanding Customer Identity Management provider. He's dedicated to innovating LoginRadius' platform, and loves fooseball and winning poker games.

deepak-gupta has 126 posts and counting.See all posts by deepak-gupta