EncryptCodecencryptcodec
Blog/Security
SecurityMarch 12, 2026 · 7 min read

Bcrypt vs Argon2 vs scrypt — Which Password Hashing Algorithm to Use in 2025

Storing passwords is one of those things that developers get wrong more often than they should. Not because the concepts are hard, but because the ecosystem has evolved and old habits die hard. If you're still reaching for MD5, SHA-256, or even unsalted bcrypt without thinking, this article is for you.

Here's a practical breakdown of the three serious contenders in 2025: bcrypt, Argon2, and scrypt.

Why Password Hashing Is Different from Regular Hashing

General-purpose hash functions (SHA-256, MD5) are designed to be fast. That's great for checksums and integrity verification — terrible for passwords. An attacker with a GPU can compute billions of SHA-256 hashes per second.

Password hashing algorithms are intentionally slow and resource-intensive. They're designed to make brute-force and dictionary attacks economically infeasible. The three we're comparing all do this, but in meaningfully different ways.

Compare hashing algorithms for passwords

p@ssw0rd123
Argon2id
hashing
Hash time (~600ms)0%
Memory used (64 MB)GPU-resistant ✓
GPU resistant
Memory hard
Recommended

✓ Best choice — memory-hard, PHC winner

Bcrypt

Released: 1999. Yes, it's older than most of the developers using it.

How it works

Bcrypt uses a cost factor (work factor) — a number that determines how many iterations the algorithm runs. Each increment doubles the computation time.

cost factor 10 → ~100ms
cost factor 12 → ~400ms
cost factor 14 → ~1600ms

Strengths

  • Mature, battle-tested, widely supported across virtually every language and framework
  • Simple API — hard to misconfigure
  • Output includes the salt, version, and cost factor (self-describing hash)

Weaknesses

  • Password length limit: bcrypt truncates input at 72 bytes. Passwords longer than 72 characters get silently truncated — a real security edge case.
  • Not memory-hard: Attackers can parallelize cracking using ASICs and GPUs more effectively than against memory-hard algorithms.
  • Cost factor is a single dimension — you can't independently tune memory vs CPU.

When to use it

You're on a legacy stack, you need maximum library compatibility, or you're maintaining existing systems. For new projects, prefer Argon2id.

Argon2

Released: 2015. Won the Password Hashing Competition in 2015. OWASP's top recommendation as of 2024.

Variants

  • Argon2d: Maximizes resistance to GPU attacks. Vulnerable to side-channel attacks. Don't use for passwords.
  • Argon2i: Resistant to side-channel attacks. Slightly weaker against GPU attacks.
  • Argon2id: Hybrid of both. Use this one.

Tuning parameters

Argon2 gives you three levers:

  • Memory cost (m): RAM in KiB to use
  • Time cost (t): Number of iterations
  • Parallelism (p): Number of threads

OWASP recommended minimums (2024):

  • m=19456 (19 MiB), t=2, p=1
  • Or m=65536 (64 MiB), t=1, p=4

Strengths

  • Memory-hard by design — makes GPU/ASIC attacks significantly more expensive
  • Flexible tuning
  • No arbitrary password length limits
  • Modern, actively maintained

Weaknesses

  • Slightly less universal library support than bcrypt (though coverage is now very good)
  • More parameters means more ways to misconfigure if you're not careful

scrypt

Released: 2009. Designed by Colin Percival for Tarsnap.

How it works

scrypt is also memory-hard, parameterized by:

  • N: CPU/memory cost (power of 2)
  • r: Block size
  • p: Parallelization factor

Strengths

  • Memory-hard — better than bcrypt against GPU attacks
  • Available in most standard libraries (OpenSSL, Node crypto, etc.)

Weaknesses

  • Tuning is less intuitive than Argon2 — N, r, p interact in non-obvious ways
  • OWASP now recommends Argon2id over scrypt for new systems
  • Less actively maintained/updated compared to Argon2

When to use it

When Argon2 isn't available in your environment and you need memory-hardness. It's a solid second choice.

Code Examples

const argon2 = require('argon2');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const { promisify } = require('util');
const scrypt = promisify(crypto.scrypt);

// Argon2id (recommended)
const hash = await argon2.hash('user_password', {
type: argon2.argon2id,
memoryCost: 19456, // 19 MiB
timeCost: 2,
parallelism: 1,
});
const valid = await argon2.verify(hash, 'user_password');

// bcrypt
const saltRounds = 12;
const bcryptHash = await bcrypt.hash('user_password', saltRounds);
const bcryptValid = await bcrypt.compare('user_password', bcryptHash);

// scrypt (Node built-in)
const salt = crypto.randomBytes(16);
const derivedKey = await scrypt('user_password', salt, 64);
// Store salt + derivedKey together

Side-by-Side Comparison

FeaturebcryptArgon2idscrypt
Memory-hard
GPU resistanceMediumHighHigh
Tuning flexibilityLow (1 param)High (3 params)Medium
Password length limit72 bytesNoneNone
OWASP recommendedAcceptable✅ First choiceAcceptable
Library supportExcellentVery goodGood
ComplexityLowMediumMedium

Migration Strategy: Moving to Argon2id

You can't re-hash passwords without the plaintext — so migrate on next login:

  1. Add an algorithm field to your users table
  2. On successful login, check if the stored hash uses the old algorithm
  3. If so, re-hash with Argon2id and update the stored hash
  4. Over time, old algorithm hashes disappear naturally

PHP's password_needs_rehash() does this automatically. For other languages, check the hash prefix — Argon2id hashes start with $argon2id$.

Use Argon2id for any new system in 2025. The library support is solid across all major languages, OWASP backs it, and the memory-hardness gives you a meaningful security advantage over bcrypt against modern hardware attacks.

If you're on a legacy bcrypt system with a high cost factor (≥12), you're not in immediate danger — but plan a migration. If you're building something new and reaching for bcrypt out of habit, stop and use Argon2id instead.

The one thing that matters more than which algorithm you pick: don't roll your own. Use a maintained library, follow OWASP's parameter recommendations, and let the algorithm do the work.

Share this post

Test password hashing in your browser

Free, browser-based — no signup required.

Frequently Asked Questions

Related posts