Password Hashing Explained: bcrypt, scrypt, Argon2, and PBKDF2
Password hashing is the practice of storing user passwords as irreversible, deliberately slow cryptographic values so that a database breach does not immediately expose everyone's credentials. Unlike general-purpose hashes designed for speed, password hashing functions are engineered to be expensive to compute, frustrating attackers who try to guess billions of passwords. This article explains the four algorithms every security engineer should know: bcrypt, scrypt, Argon2, and PBKDF2.
Why General-Purpose Hashes Fail for Passwords
A natural but dangerous instinct is to store a password as its SHA-256 hash. This is unsafe for two reasons:
- Speed is the enemy. SHA-256 is designed to be fast, so an attacker with modern GPUs or ASICs can compute billions of guesses per second against a stolen hash.
- No per-user variation. Identical passwords produce identical hashes, so attackers can use precomputed rainbow tables and crack many accounts at once.
Password hashing functions fix both problems with two core ideas: salting and deliberate slowness (work factors). They are specialized key derivation functions (KDFs) tuned for password storage.
Salting: Defeating Precomputation
A salt is a unique, random value generated per password and stored alongside the hash. It is mixed into the hashing process so that:
- Two users with the same password get different stored hashes.
- Precomputed rainbow tables become useless, because an attacker would need a separate table per salt.
Salts do not need to be secret, only unique and unpredictable, typically 16 bytes from a secure random source. A related optional secret is a pepper, a site-wide secret kept outside the database that adds a further layer if the database alone is leaked.
PBKDF2: Iterated Hashing
PBKDF2 (Password-Based Key Derivation Function 2) is the oldest of these standards. It repeatedly applies a pseudorandom function, almost always HMAC over a hash like SHA-256, for a configurable number of iterations. Each iteration feeds into the next, so the total cost scales with the iteration count.
- Strengths: simple, standardized, widely available, and FIPS-approved, which matters in regulated environments.
- Weakness: it is only computationally hard, not memory-hard. Attackers can parallelize it cheaply on GPUs and ASICs because each guess uses very little memory.
To use PBKDF2 well, set the iteration count as high as your performance budget tolerates, using a high-entropy random salt per password.
bcrypt: Adaptive and Battle-Tested
bcrypt is based on a modified version of the Blowfish cipher's expensive key setup. Its defining feature is a tunable cost factor (work factor): each increment doubles the work, so the algorithm can be made slower as hardware improves.
- Strengths: mature, widely deployed, resistant to naive GPU acceleration because its algorithm accesses a moderate amount of memory in a cache-unfriendly pattern.
- Limitations: it uses a fixed, small memory footprint (around 4 KB), so it is not strongly memory-hard, and it truncates passwords beyond 72 bytes, which callers must handle.
bcrypt remains a solid, conservative choice, and its long track record makes it a safe default where Argon2 is unavailable.
scrypt: Introducing Memory-Hardness
scrypt was designed to defeat custom hardware attacks by being memory-hard: it requires a large, tunable amount of memory as well as CPU time. Because memory is expensive to replicate across thousands of parallel cracking units, memory-hardness dramatically raises the cost of large-scale attacks.
scrypt exposes parameters for CPU/memory cost (N), block size (r), and parallelism (p). Tuning these lets defenders balance security against server resources. Its main drawback is that misconfiguration is easy, and choosing safe parameters requires care.
Argon2: The Modern Recommendation
Argon2 won the Password Hashing Competition and is the recommended default for new systems. It is strongly memory-hard and highly configurable, with three variants:
- Argon2d maximizes resistance to GPU cracking but uses data-dependent memory access, which can be vulnerable to side channels.
- Argon2i uses data-independent memory access, resisting side-channel attacks but offering slightly less brute-force resistance.
- Argon2id is a hybrid combining both, and is the generally recommended variant for password storage.
Argon2 takes three key parameters:
- Memory cost: how much RAM each hash consumes (for example, tens to hundreds of megabytes).
- Time cost: the number of iterations over that memory.
- Parallelism: the number of lanes/threads used.
# Conceptual parameters for Argon2id (tune to your hardware)
hash = argon2id(
password = user_password,
salt = random_16_bytes,
memory = 64 * 1024, # 64 MiB
time = 3, # iterations
parallelism = 4 # lanes
)
Tuning aims for a hash that takes a noticeable fraction of a second on your server, making mass guessing prohibitively expensive while keeping legitimate logins responsive.
Choosing and Operating a Password Hash
Practical guidance for deploying password hashing:
- Prefer Argon2id for new systems; bcrypt and scrypt are strong alternatives, and PBKDF2 is acceptable where standards compliance requires it.
- Always use a unique random salt per password, stored with the hash.
- Calibrate work factors to your hardware so each hash takes a meaningful fraction of a second, and raise them over time.
- Store the parameters (algorithm, salt, cost) with each hash so you can verify and later upgrade.
- Use constant-time comparison when verifying, and rehash with stronger parameters when users next log in.
Password hashing is a defensive control: its goal is to buy time and raise attacker cost after a breach, complementing rate limiting, multi-factor authentication, and breach monitoring.
Key Takeaways
- Password hashing uses deliberately slow, salted algorithms so a database breach does not instantly reveal passwords.
- Never use fast general-purpose hashes like plain SHA-256 for passwords; they are trivially parallelized by attackers.
- Salting defeats rainbow tables, and work factors make each guess expensive; memory-hardness further defeats GPU and ASIC attacks.
- Argon2id is the modern recommendation, with bcrypt and scrypt as strong choices and PBKDF2 for compliance-driven contexts.
- Tune parameters to your hardware, store them with each hash, and increase them as computing power grows.