root/learning-hub/security-cryptography/password-hashing-bcrypt-argon2
← Back to Learning Hub
SECURITY & CRYPTOGRAPHY•7 min read•Intermediate••100% Client-Side Verified

Password Hashing Guide: Bcrypt, Argon2 & PBKDF2 Explained

A complete developer's guide to modern password hashing. Learn the differences between Bcrypt, Argon2id, and PBKDF2, and how to choose the right cost factors.

#Bcrypt#Argon2#Security#Cryptography#Hashing

Interactive Password Hash & Verifier

Live Interactive Sandbox
100% Client-Side

Computes Bcrypt, Argon2, or PBKDF2 hashes locally using the Web Crypto API. Test the preset input below or customize it before launching into the full workspace.

Candidate Password:
Ready for advanced parsing, syntax error highlighting & bulk export?
Open in Full Workspace (Password Hash & Verifier)

Password hashing is the foundational layer of application security. Unlike encryption (which is reversible), hashing is a one-way function — you can verify a password against a hash, but you cannot reverse the hash back to the original password.

Choosing the right algorithm and tuning its cost parameters is critical. Get it wrong and an attacker with a stolen database can crack millions of passwords per second on commodity GPUs.


Why Not SHA-256 or MD5?

General-purpose hash functions like SHA-256 and MD5 are designed to be fast. That's the exact opposite of what you want for password storage.

Algorithm Hashes/sec (RTX 4090) Purpose
MD5 ~164 billion Checksums, NOT passwords
SHA-256 ~22 billion Data integrity, NOT passwords
Bcrypt (cost 12) ~32,000 ✅ Password storage
Argon2id (64MB) ~1,000 ✅ Password storage

The entire point of a password hash function is to be deliberately slow so that brute-force attacks become economically unfeasible.


1. Bcrypt — The Industry Standard

Bcrypt has been the default recommendation since 1999. It uses the Blowfish cipher internally and has a built-in salt.

How Bcrypt Output Looks

$2b$12$LJ3m4ys3YOlTBSVVoJBNMezgqLcJEE3I7mFtHxMUb4uVlvDFqmqy6
 │  │  │                                                          
 │  │  └── 22-char salt + 31-char hash (Base64 encoded)
 │  └───── Cost factor (2^12 = 4096 iterations)
 └──────── Algorithm identifier ($2b$ = modern Bcrypt)

Bcrypt in Code

# Python (bcrypt library)
import bcrypt

password = b"CorrectHorseBatteryStaple"
salt = bcrypt.gensalt(rounds=12)  # Cost factor = 12
hashed = bcrypt.hashpw(password, salt)

# Verify
if bcrypt.checkpw(password, hashed):
    print("Password matches")
// Node.js (bcryptjs)
const bcrypt = require('bcryptjs');

const hash = await bcrypt.hash('CorrectHorseBatteryStaple', 12);
const isValid = await bcrypt.compare('CorrectHorseBatteryStaple', hash);

Choosing the Cost Factor

Cost Iterations ~Time (modern CPU) Use Case
10 1,024 ~65ms Minimum acceptable
12 4,096 ~250ms OWASP recommended
14 16,384 ~1s High-security systems
16 65,536 ~4s Local key derivation

Rule of thumb: Choose the highest cost that keeps login latency under 250ms on your production hardware.


2. Argon2id — The Modern Gold Standard

Argon2 won the 2015 Password Hashing Competition and comes in three variants:

Variant Protection Against When to Use
Argon2d GPU attacks (data-dependent) NOT for passwords (side-channel vulnerable)
Argon2i Side-channel attacks (data-independent) Okay, but less GPU-resistant
Argon2id Both GPU + side-channel attacks ✅ Always use this for passwords

Why Argon2id Is Superior

Unlike Bcrypt (which is CPU-bound), Argon2id is memory-hard. It forces the attacker to allocate large amounts of RAM per hash attempt, making GPU/ASIC-based cracking economically impractical.

OWASP-Recommended Parameters

Memory:      64 MB  (65536 KiB)
Iterations:  3
Parallelism: 1 thread
Salt:        16 bytes (random)
Hash length: 32 bytes

Argon2id in Code

# Python (argon2-cffi)
from argon2 import PasswordHasher

ph = PasswordHasher(
    memory_cost=65536,  # 64 MB
    time_cost=3,        # 3 iterations
    parallelism=1       # 1 thread
)

hash = ph.hash("CorrectHorseBatteryStaple")
# Returns: $argon2id$v=19$m=65536,t=3,p=1$<salt>$<hash>

try:
    ph.verify(hash, "CorrectHorseBatteryStaple")
    print("Valid")
except Exception:
    print("Invalid")

3. PBKDF2 — The Legacy Option

PBKDF2 (Password-Based Key Derivation Function 2) is the oldest of the three and is built into most platforms natively (including the Web Crypto API and .NET).

// Browser Web Crypto API
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
  "raw", enc.encode(password), "PBKDF2", false, ["deriveBits"]
);
const hash = await crypto.subtle.deriveBits(
  { name: "PBKDF2", salt: salt, iterations: 600000, hash: "SHA-256" },
  keyMaterial, 256
);

OWASP recommends 600,000 iterations with SHA-256 for PBKDF2. However, PBKDF2 is not memory-hard, so it remains vulnerable to GPU acceleration.


Algorithm Decision Matrix

Feature Bcrypt Argon2id PBKDF2
Memory-hard ❌ ✅ ❌
GPU-resistant Moderate ✅ Strong ❌ Weak
Built-in salt ✅ ✅ ❌ (manual)
Native browser support ❌ ❌ ✅ (Web Crypto)
OWASP top pick (2024) ✅ ✅ (preferred) ✅ (if others unavailable)
Max password length 72 bytes Unlimited Unlimited

Recommendation: Use Argon2id if your platform supports it. Fall back to Bcrypt (cost 12+) otherwise. Use PBKDF2 only when neither is available (e.g., browser-only environments).


Security Best Practices

  1. Always salt: Every hash must use a unique, cryptographically random salt (at least 16 bytes). Bcrypt and Argon2 handle this automatically.
  2. Never truncate passwords silently: Bcrypt has a 72-byte limit. If your app accepts longer passwords, hash with SHA-256 first (prehashing), then pass the result to Bcrypt.
  3. Rehash on login: If a user logs in and their stored hash uses outdated parameters (e.g., Bcrypt cost 8), verify the password and then re-hash with stronger parameters before storing.
  4. Use a pepper for defense-in-depth: A pepper is a server-side secret key applied before hashing. Store it in an HSM or environment variable — never in the database.
  5. Rate-limit login attempts: Even the strongest hash is useless if your login endpoint allows unlimited attempts.

Test your password hashing configuration with the Password Hash & Verifier tool. For related security topics, see the SSH Key Generation Guide and JWT Token Decoding.

Live Tool: Bcrypt / Argon2 / PBKDF2 Password Hash Verifier & Generator

Client-Side Engine

Generate Bcrypt, Argon2id, PBKDF2, and SCrypt hashes (with Bcrypt cost and PBKDF2 iteration controls) and verify passwords against Bcrypt hashes.

Launch Tool Workspace

Frequently Asked Questions (FAQ)

Argon2id is memory-hard. While Bcrypt only taxes CPU cycles, Argon2id allocates large blocks of RAM, making GPU/ASIC parallel cracking economically unfeasible.

Related Guides & References

view learning hub →