Table of Contents
In an era where data breaches expose billions of credentials every year, choosing the right password hashing algorithm is one of the most critical security decisions you’ll make. The wrong choice can leave your users vulnerable to brute-force attacks, GPU cracking farms, and ASIC-powered password recovery.
This guide provides an exhaustive, developer-focused comparison of PBKDF2-SHA-256 and Argon2id — the two most widely recommended password hashing algorithms today. We’ll cover security architecture, real-world benchmarks, OWASP and NIST recommendations, code examples in multiple languages, and a step-by-step migration path.
TL;DR — Quick Verdict
| Criteria | Winner |
|---|---|
| Overall Security (2026) | Argon2id |
| GPU / ASIC Resistance | Argon2id |
| FIPS-140 & NIST Compliance | PBKDF2-SHA-256 |
| Customizability | Argon2id |
| Library & Framework Support | Tie (both widely supported) |
| Best for New Projects | Argon2id |
| Best for Regulated Industries | PBKDF2-SHA-256 |
Bottom line: For most new applications, Argon2id is the superior choice. Use PBKDF2-SHA-256 only when FIPS-140 compliance is a hard requirement.
What Is Password Hashing and Why Does It Matter?
A password hashing algorithm is a one-way cryptographic function that transforms a plaintext password into a fixed-length string (the hash). Instead of storing raw passwords, applications store these hashes. When a user logs in, the system hashes the input and compares it to the stored hash.
The key properties of a good password hash:
- One-way: Computationally infeasible to reverse
- Deterministic: Same input always produces the same output
- Slow by design: Intentionally resource-intensive to deter brute-force attacks
- Salted: A unique random value is appended to each password before hashing
- Resistant to parallelism: Hard to crack using GPUs, FPGAs, or ASICs
General-purpose hash functions like SHA-256, MD5, or SHA-1 are not suitable for password hashing because they are designed to be fast — the exact opposite of what you want for password security.
What Is PBKDF2-SHA-256?
PBKDF2 (Password-Based Key Derivation Function 2) was published in 2000 as part of RFC 2898 (later updated in RFC 8018). It is one of the oldest and most widely deployed password hashing standards.
How PBKDF2 Works
PBKDF2 applies a pseudorandom function — typically HMAC-SHA-256 — iteratively to the password combined with a salt:
DK = PBKDF2(PRF, Password, Salt, Iterations, dkLen)
Where:
- PRF = Pseudorandom function (e.g., HMAC-SHA-256)
- Password = The user’s plaintext password
- Salt = A cryptographically random value (at least 16 bytes recommended)
- Iterations = Number of times the PRF is applied (the “cost factor”)
- dkLen = Desired length of the derived key
Each iteration feeds the output of the previous round back as input, creating a chain of HMAC operations. The computational cost scales linearly with the iteration count.
PBKDF2 Strengths
- ✅ NIST SP 800-132 recommended — Required in many government and regulated environments
- ✅ FIPS-140 validated — Available in FIPS-compliant cryptographic modules
- ✅ Universal support — Built into virtually every language, framework, and operating system
- ✅ Simple, well-understood design — Decades of cryptanalysis with no critical weaknesses found
- ✅ RFC standardized — RFC 8018 provides a clear specification
PBKDF2 Weaknesses
- ❌ CPU-only hardness — Cost scales only with CPU time, not memory
- ❌ Vulnerable to GPU/ASIC attacks — SHA-256 is highly parallelizable on GPUs and can be implemented efficiently on custom ASICs
- ❌ Single tuning parameter — Only iteration count can be adjusted; no memory or parallelism controls
- ❌ Linear cost scaling — Doubling security doubles cost equally for both defender and attacker
PBKDF2 Iterations: How Many Do You Need?
The recommended iteration count has increased significantly over the years as hardware has gotten faster:
| Year | OWASP Minimum Iterations | NIST Recommendation |
|---|---|---|
| 2017 | 100,000 | 10,000+ |
| 2021 | 310,000 | 10,000+ |
| 2023 | 600,000 | 10,000+ |
| 2025–2026 | 600,000+ | 10,000+ (under review) |
OWASP 2025 recommendation: Use a minimum of 600,000 iterations with HMAC-SHA-256. Aim for a hash computation time of roughly 250ms on your production hardware.
What Is Argon2id?
Argon2 was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. It won the Password Hashing Competition (PHC) in July 2015, beating 23 other submissions after rigorous peer review. It is specified in RFC 9106 (2021).
Argon2 Variants Explained
Argon2 comes in three variants:
| Variant | Memory Access Pattern | Best For |
|---|---|---|
| Argon2d | Data-dependent (faster) | Backend/server-side where side-channel attacks are not a concern |
| Argon2i | Data-independent (safer) | Environments exposed to side-channel attacks |
| Argon2id | Hybrid (first half Argon2i, second half Argon2d) | Recommended default for password hashing |
Argon2id is the recommended variant because it combines the side-channel resistance of Argon2i in the first pass with the GPU/ASIC resistance of Argon2d in subsequent passes.
How Argon2id Works
Argon2id has three primary tuning parameters:
Hash = Argon2id(Password, Salt, Memory, Iterations, Parallelism, HashLength)
- Memory (m) — Amount of RAM used during hashing (in KiB). This is the key differentiator from PBKDF2.
- Iterations (t) — Number of passes over the memory. More passes = more time.
- Parallelism (p) — Number of threads that can be used. Increases memory bandwidth requirements.
- Salt — At least 16 bytes of cryptographically random data.
- Hash Length — Typically 32 bytes (256 bits).
The algorithm fills a large block of memory with pseudo-random data derived from the password and salt, then repeatedly accesses this memory in a pattern that is intentionally hard to optimize on GPUs or ASICs.
Argon2id Strengths
- ✅ Memory-hard — Requires significant RAM, making GPU/ASIC attacks orders of magnitude more expensive
- ✅ PHC winner — Vetted through the most rigorous password hashing competition ever held
- ✅ Three tuning parameters — Independent control over memory, time, and parallelism
- ✅ Side-channel resistant — The Argon2id hybrid mode defends against timing attacks
- ✅ RFC 9106 standardized — Published as an IETF standard in 2021
- ✅ OWASP primary recommendation — The #1 recommended algorithm for new applications
Argon2id Weaknesses
- ❌ Not yet FIPS-140 validated — Cannot be used in strict FIPS-compliant environments (as of 2026)
- ❌ Higher memory consumption — Each hash operation uses 19–64+ MiB of RAM on the server
- ❌ Newer, less battle-tested — Only ~11 years of deployment vs. 26 years for PBKDF2
- ❌ Potential for misconfiguration — Three parameters mean more ways to set insecure defaults
PBKDF2-SHA-256 vs Argon2id: Head-to-Head Comparison
Security: Attack Resistance
| Attack Type | PBKDF2-SHA-256 | Argon2id |
|---|---|---|
| Brute Force (CPU) | ✅ Strong (with high iterations) | ✅ Strong |
| GPU Cracking | ❌ Vulnerable (SHA-256 is GPU-friendly) | ✅ Resistant (memory-hard) |
| ASIC Attacks | ❌ Vulnerable (Bitcoin miners can be repurposed) | ✅ Resistant (memory bandwidth bound) |
| FPGA Attacks | ❌ Vulnerable | ✅ Resistant |
| Side-Channel Attacks | ⚠️ Depends on implementation | ✅ Resistant (Argon2id hybrid mode) |
| Time-Memory Tradeoff | N/A | ✅ Resistant (Argon2d component) |
| Rainbow Table Attacks | ✅ Resistant (with salt) | ✅ Resistant (with salt) |
Why memory-hardness matters: A modern GPU like the NVIDIA RTX 4090 can compute billions of SHA-256 hashes per second, but has only 24 GB of VRAM. If each Argon2id hash requires 64 MiB of memory, the GPU can only run ~375 parallel instances — compared to millions of parallel PBKDF2 computations. This makes Argon2id thousands of times more expensive to crack on GPUs.
Performance Benchmarks
Here are approximate single-thread hashing times on a modern server (AMD EPYC 7763, 2.45 GHz):
| Algorithm | Configuration | Time per Hash | Memory Used |
|---|---|---|---|
| PBKDF2-SHA-256 | 600,000 iterations | ~250ms | ~0 KiB |
| PBKDF2-SHA-256 | 210,000 iterations | ~90ms | ~0 KiB |
| Argon2id | m=19456 (19 MiB), t=2, p=1 | ~250ms | 19 MiB |
| Argon2id | m=47104 (46 MiB), t=1, p=1 | ~250ms | 46 MiB |
| Argon2id | m=65536 (64 MiB), t=3, p=4 | ~300ms | 64 MiB |
Key insight: At equal wall-clock time (~250ms), Argon2id provides vastly superior security because attackers must also invest the same memory for each cracking attempt, which is far more expensive to parallelize.
OWASP Recommended Parameters (2025–2026)
The OWASP Password Storage Cheat Sheet ranks password hashing algorithms in this order of preference:
- Argon2id (primary recommendation)
- scrypt
- bcrypt
- PBKDF2-SHA-256 (when FIPS compliance is required)
Argon2id Recommended Parameters
| Parameter | OWASP Minimum | Higher Security |
|---|---|---|
| Memory (m) | 19 MiB (19456 KiB) | 46–64 MiB |
| Iterations (t) | 2 | 3–5 |
| Parallelism (p) | 1 | 4 |
| Salt length | 16 bytes | 16 bytes |
| Hash length | 32 bytes | 32 bytes |
PBKDF2-SHA-256 Recommended Parameters
| Parameter | OWASP Minimum |
|---|---|
| Iterations | 600,000 |
| Salt length | 16 bytes (minimum) |
| Hash length | 32 bytes (256 bits) |
| PRF | HMAC-SHA-256 |
NIST and FIPS Compliance
This is where PBKDF2 still has a decisive advantage for certain organizations:
| Standard | PBKDF2-SHA-256 | Argon2id |
|---|---|---|
| NIST SP 800-132 | ✅ Recommended | ❌ Not mentioned |
| NIST SP 800-63B (Digital Identity) | ✅ Referenced | ❌ Not mentioned |
| FIPS 140-2/3 | ✅ Validated implementations available | ❌ No validated implementations |
| PCI DSS | ✅ Accepted | ⚠️ Accepted (not explicit) |
| HIPAA | ✅ Accepted | ⚠️ Accepted (not explicit) |
| SOC 2 | ✅ Accepted | ✅ Accepted |
Important note: As of 2026, NIST is reviewing Argon2 for potential inclusion in future guidelines. The cryptographic community widely expects Argon2id to receive NIST endorsement, but no timeline has been confirmed. If your organization requires FIPS-140 compliance, PBKDF2-SHA-256 remains the only fully validated option.
Customizability
| Feature | PBKDF2-SHA-256 | Argon2id |
|---|---|---|
| CPU cost tuning | ✅ Iterations | ✅ Iterations (t) |
| Memory cost tuning | ❌ Not available | ✅ Memory (m) |
| Parallelism tuning | ❌ Not available | ✅ Parallelism (p) |
| Output length | ✅ Configurable | ✅ Configurable |
| Salt length | ✅ Configurable | ✅ Configurable |
| Hash function choice | ✅ Multiple PRFs available | ❌ Fixed (Blake2b internally) |
Code Examples: Implementing PBKDF2 and Argon2id
Node.js
PBKDF2-SHA-256 in Node.js
const crypto = require('crypto');
function hashWithPBKDF2(password) {
const salt = crypto.randomBytes(16);
const iterations = 600000;
const keyLength = 32;
const digest = 'sha256';
const hash = crypto.pbkdf2Sync(
password, salt, iterations, keyLength, digest
);
// Store salt + iterations + hash together
return `pbkdf2:sha256:${iterations}:${salt.toString('base64')}:${hash.toString('base64')}`;
}
function verifyPBKDF2(password, stored) {
const [, , iterations, saltB64, hashB64] = stored.split(':');
const salt = Buffer.from(saltB64, 'base64');
const originalHash = Buffer.from(hashB64, 'base64');
const hash = crypto.pbkdf2Sync(
password, salt, parseInt(iterations), originalHash.length, 'sha256'
);
return crypto.timingSafeEqual(hash, originalHash);
}Argon2id in Node.js
const argon2 = require('argon2');
async function hashWithArgon2id(password) {
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 19456, // 19 MiB (OWASP minimum)
timeCost: 2, // 2 iterations
parallelism: 1, // 1 thread
saltLength: 16,
hashLength: 32,
});
return hash; // Returns encoded string with all parameters
}
async function verifyArgon2id(password, hash) {
return await argon2.verify(hash, password);
}Python
PBKDF2-SHA-256 in Python
import hashlib
import os
import base64
def hash_with_pbkdf2(password: str) -> str:
salt = os.urandom(16)
iterations = 600000
dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations, dklen=32)
salt_b64 = base64.b64encode(salt).decode()
hash_b64 = base64.b64encode(dk).decode()
return f"pbkdf2:sha256:{iterations}:{salt_b64}:{hash_b64}"
def verify_pbkdf2(password: str, stored: str) -> bool:
_, _, iterations, salt_b64, hash_b64 = stored.split(':')
salt = base64.b64decode(salt_b64)
original_hash = base64.b64decode(hash_b64)
dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, int(iterations), dklen=len(original_hash))
return dk == original_hashArgon2id in Python
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=2, # 2 iterations
memory_cost=19456, # 19 MiB
parallelism=1, # 1 thread
hash_len=32,
salt_len=16,
type=argon2.Type.ID # Argon2id
)
def hash_with_argon2id(password: str) -> str:
return ph.hash(password)
def verify_argon2id(password: str, hash: str) -> bool:
try:
return ph.verify(hash, password)
except Exception:
return FalseGo
Argon2id in Go
package main
import (
"crypto/rand"
"golang.org/x/crypto/argon2"
"encoding/base64"
"fmt"
)
func hashWithArgon2id(password string) (string, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
if err != nil {
return "", err
}
// OWASP recommended: memory=19MiB, iterations=2, parallelism=1
hash := argon2.IDKey([]byte(password), salt, 2, 19*1024, 1, 32)
return fmt.Sprintf("$argon2id$v=19$m=19456,t=2,p=1$%s$%s",
base64.RawStdEncoding.EncodeToString(salt),
base64.RawStdEncoding.EncodeToString(hash),
), nil
}Real-World Adoption: Who Uses What?
Understanding which major platforms use each algorithm provides valuable context:
Organizations Using Argon2id
- Bitwarden — Switched from PBKDF2 to Argon2id as the default in 2023
- 1Password — Uses Argon2id for vault key derivation
- Signal — Uses Argon2id for PIN-based key recovery
- ProtonMail — Uses Argon2id for account password hashing
- Django 4.0+ — Added Argon2id as a supported password hasher
- PHP 7.2+ — Native
password_hash()supports Argon2id - libsodium — Recommends Argon2id as the default password hashing function
Organizations Using PBKDF2-SHA-256
- Apple iCloud Keychain — Uses PBKDF2 for key derivation
- Wi-Fi WPA2/WPA3 — Uses PBKDF2-SHA-256 for passphrase-to-key derivation
- Microsoft .NET —
Rfc2898DeriveBytesimplements PBKDF2 - LUKS disk encryption — Supports PBKDF2 (and Argon2id in LUKS2)
- US Government systems — Required for FIPS-140 compliance
- Banking & financial systems — Common due to regulatory requirements
- Django (default) — Still uses PBKDF2 as the default hasher (Argon2id optional)
When to Choose PBKDF2-SHA-256
Choose PBKDF2-SHA-256 when:
- FIPS-140 compliance is mandatory — Government contracts, military, healthcare (HIPAA), financial (PCI DSS) environments may require FIPS-validated cryptographic modules
- Your platform lacks Argon2 support — Some embedded systems, legacy platforms, or constrained environments only support PBKDF2
- Memory is extremely constrained — IoT devices or environments where allocating 19+ MiB per hash operation is not feasible
- You need maximum interoperability — PBKDF2 is available in virtually every programming language and cryptographic library without additional dependencies
- Regulatory audit requirements — When auditors specifically require NIST-approved algorithms
If you choose PBKDF2: Use a minimum of 600,000 iterations with HMAC-SHA-256, a 16-byte random salt, and measure that your hash computation takes approximately 250ms on your production server.
When to Choose Argon2id
Choose Argon2id when:
- Starting a new project — Argon2id is the OWASP #1 recommendation for all new applications
- Maximum security is the priority — The memory-hardness of Argon2id makes it significantly more resistant to offline cracking than PBKDF2
- You need GPU/ASIC resistance — If your threat model includes well-funded attackers with GPU farms or custom hardware
- Your server has adequate memory — Each concurrent login will require 19–64 MiB of RAM during hash computation
- You’re building a password manager, crypto wallet, or high-security application — Where the cost of a breach is extremely high
- FIPS compliance is not required — Most commercial web applications, SaaS products, and consumer-facing services
If you choose Argon2id: Start with the OWASP minimum of m=19456 (19 MiB), t=2, p=1, then increase memory as your server allows. Aim for ~250ms per hash on your production hardware.
How to Migrate from PBKDF2 to Argon2id
If you’re currently using PBKDF2 and want to switch to Argon2id, here’s a safe migration strategy that requires zero downtime and no forced password resets:
Step 1: Update Your Hash Storage
Ensure your password hash column can store both PBKDF2 and Argon2id formatted strings. Argon2id hashes are typically longer (~97 characters) than PBKDF2 hashes.
-- Increase column size if needed
ALTER TABLE users ALTER COLUMN password_hash TYPE VARCHAR(255);Step 2: Implement Dual Verification
async function verifyPassword(password, storedHash) {
if (storedHash.startsWith('$argon2id$')) {
return await argon2.verify(storedHash, password);
}
// Legacy PBKDF2 verification
return verifyPBKDF2(password, storedHash);
}Step 3: Re-hash on Login
When a user successfully logs in with a PBKDF2 hash, re-hash their password with Argon2id:
async function loginUser(username, password) {
const user = await getUser(username);
const isValid = await verifyPassword(password, user.passwordHash);
if (!isValid) return { success: false };
// Migrate to Argon2id if still using PBKDF2
if (!user.passwordHash.startsWith('$argon2id$')) {
const newHash = await hashWithArgon2id(password);
await updateUserHash(user.id, newHash);
}
return { success: true };
}Step 4: Monitor Migration Progress
Track the percentage of users who have been migrated:
SELECT
COUNT(CASE WHEN password_hash LIKE '$argon2id$%' THEN 1 END) as argon2id_users,
COUNT(CASE WHEN password_hash NOT LIKE '$argon2id$%' THEN 1 END) as legacy_users,
COUNT(*) as total_users
FROM users;Step 5: Handle Inactive Users
For users who haven’t logged in after several months, consider:
- Forcing a password reset on next login
- Sending a “secure your account” email prompting them to log in
- Setting a deadline after which legacy hashes are invalidated
How Does bcrypt Fit In?
Many developers also consider bcrypt when choosing a password hashing algorithm. Here’s how it compares:
| Feature | PBKDF2-SHA-256 | bcrypt | Argon2id |
|---|---|---|---|
| Year Introduced | 2000 | 1999 | 2015 |
| Memory-Hardness | ❌ No | ⚠️ Minimal (4 KiB) | ✅ Yes (configurable) |
| GPU Resistance | ❌ Poor | ⚠️ Moderate | ✅ Strong |
| Max Password Length | Unlimited | 72 bytes | Unlimited |
| OWASP Ranking | #4 | #3 | #1 |
| NIST/FIPS Approved | ✅ Yes | ❌ No | ❌ No |
bcrypt’s 72-byte limit is a notable practical limitation. Passwords longer than 72 bytes are silently truncated, which can cause unexpected security issues with passphrase-based authentication. Neither PBKDF2 nor Argon2id has this limitation.
Threat Modeling: Understanding the Attacker’s Cost
To truly understand why Argon2id is superior for most use cases, let’s model the attacker’s cost:
Scenario: Cracking a Single Password Hash
Assumptions: Attacker uses 8× NVIDIA RTX 4090 GPUs (24 GB VRAM each, ~$1,600 each)
PBKDF2-SHA-256 (600,000 iterations)
- Hashcat benchmark: ~25,000 hashes/second per GPU
- 8 GPUs: ~200,000 hashes/second
- Time to crack 8-char alphanumeric password: ~4.3 days
- Cost: ~$100 in electricity
Argon2id (m=64MiB, t=3, p=4)
- Each hash attempt requires 64 MiB RAM
- Per GPU (24 GB VRAM): ~375 parallel attempts max
- Estimated: ~150 hashes/second per GPU
- 8 GPUs: ~1,200 hashes/second
- Time to crack 8-char alphanumeric password: ~720 days
- Cost: ~$17,000 in electricity
Argon2id makes the same attack ~167× more expensive. This is why memory-hardness matters — it turns a $100 attack into a $17,000 attack.
Common Mistakes to Avoid
1. Using Too Few PBKDF2 Iterations
Many tutorials still recommend 10,000–100,000 iterations. In 2026, the OWASP minimum is 600,000. Always benchmark on your production hardware and aim for ~250ms per hash.
2. Using Argon2id with Insufficient Memory
Setting m=1024 (1 MiB) defeats the purpose of memory-hardness. The OWASP minimum is 19,456 KiB (19 MiB). More is better.
3. Not Using a Unique Salt
Every password hash must use a cryptographically random salt of at least 16 bytes. Never reuse salts across users.
4. Using MD5 or SHA-256 Directly
General-purpose hash functions are not password hashing algorithms. Never use MD5(password) or SHA256(password + salt).
5. Rolling Your Own Hashing Scheme
Use battle-tested libraries. Don’t combine algorithms in novel ways unless you’re a cryptographer.
6. Not Planning for Parameter Upgrades
Hardware gets faster every year. Build your system to support re-hashing with stronger parameters when users log in (as shown in the migration guide above).
Future Outlook: What’s Coming Next?
The password hashing landscape continues to evolve:
- NIST Review of Argon2: NIST is expected to evaluate Argon2 for formal recommendation. If approved, it would remove the last major barrier to Argon2id adoption in regulated industries.
- Post-Quantum Considerations: Current password hashing algorithms are not significantly threatened by quantum computers (Grover’s algorithm provides only a quadratic speedup against symmetric primitives), but research continues.
- Hardware Evolution: As GPUs and ASICs become more powerful, the advantage of memory-hard algorithms like Argon2id will become even more pronounced.
- Balloon Hashing: Another memory-hard function that has received some academic interest, though Argon2id remains the clear leader.
- OPAQUE and Asymmetric PAKE: Protocol-level improvements that prevent the server from ever seeing the plaintext password, complementing hash-based storage.
Conclusion
The choice between PBKDF2-SHA-256 and Argon2id comes down to your specific requirements:
-
For new applications without FIPS constraints: Use Argon2id. It provides superior GPU/ASIC resistance, more tuning parameters, and is the #1 OWASP recommendation. Start with
m=19456, t=2, p=1and scale up. -
For FIPS-regulated environments: Use PBKDF2-SHA-256 with a minimum of 600,000 iterations. Monitor for NIST guidance on Argon2, and plan your migration path.
-
For existing PBKDF2 systems: Plan a gradual migration to Argon2id using the transparent re-hashing strategy outlined above. There’s no need for a flag day or forced password resets.
The security of your users’ passwords is too important to leave to outdated defaults. Whichever algorithm you choose, benchmark on your production hardware, use strong parameters, and build in the ability to upgrade over time.
Frequently Asked Questions
What is the difference between PBKDF2-SHA-256 and Argon2id?
PBKDF2-SHA-256 is a CPU-intensive key derivation function that iterates HMAC-SHA-256 to slow down brute-force attacks. Argon2id is a newer, memory-hard function that requires both CPU time and significant RAM, making it far more resistant to GPU and ASIC-based attacks. Argon2id is the OWASP #1 recommendation for password hashing in 2026.
Is Argon2id always superior to PBKDF2-SHA-256?
For raw security against modern hardware attacks, yes — Argon2id’s memory-hardness provides a significant advantage. However, PBKDF2-SHA-256 is still the better choice when FIPS-140 compliance is required, or in extremely memory-constrained environments where allocating 19+ MiB per hash is not feasible.
What are the OWASP recommended Argon2id parameters?
The OWASP minimum recommended parameters for Argon2id are: memory (m) = 19,456 KiB (19 MiB), iterations (t) = 2, parallelism (p) = 1, with a 16-byte salt and 32-byte hash output. For higher security, increase memory to 46–64 MiB.
How many PBKDF2 iterations should I use in 2026?
OWASP recommends a minimum of 600,000 iterations with HMAC-SHA-256. You should benchmark on your production hardware and aim for a hash computation time of approximately 250 milliseconds. Adjust upward as hardware improves.
Is PBKDF2 NIST approved?
Yes. PBKDF2 is recommended in NIST SP 800-132 for password-based key derivation and is available in FIPS-140 validated cryptographic modules. This makes it the required choice for many government and regulated industry applications.
Is Argon2id FIPS compliant?
No, not as of 2026. Argon2id does not yet have FIPS-140 validated implementations. However, NIST is reviewing Argon2 for potential inclusion in future guidelines. For organizations that require FIPS compliance, PBKDF2-SHA-256 remains the necessary choice.
Can I migrate from PBKDF2 to Argon2id without resetting all passwords?
Yes. You can implement a transparent migration strategy: verify existing passwords against their PBKDF2 hash, and on successful login, re-hash the password using Argon2id and store the new hash. This gradually migrates users without requiring password resets.
How does bcrypt compare to PBKDF2 and Argon2id?
bcrypt falls between PBKDF2 and Argon2id in security. It offers some GPU resistance due to its 4 KiB memory requirement, but far less than Argon2id. It also has a 72-byte password length limit that can be problematic. OWASP ranks it #3 (after Argon2id and scrypt, before PBKDF2).
What password hashing algorithm does Bitwarden use?
Bitwarden switched from PBKDF2 to Argon2id as the default in 2023. Users can still choose PBKDF2 with 600,000+ iterations if needed for compatibility. This move reflects the industry trend toward memory-hard algorithms.
Why not just use SHA-256 for password hashing?
SHA-256 is a general-purpose hash function designed to be fast. A modern GPU can compute billions of SHA-256 hashes per second, making brute-force attacks trivial. Password hashing algorithms like PBKDF2 and Argon2id are intentionally slow and resource-intensive to make such attacks impractical.



