bcrypt vs SHA-256: Password Hashing Compared
If you’re building authentication, choosing the right hashing algorithm is one of the most important security decisions you’ll make. This guide explains why SHA-256 is wrong for passwords and bcrypt is right.
The Core Problem
SHA-256 is designed to be fast. A modern GPU can compute billions of SHA-256 hashes per second. This is great for checksums and data integrity — but catastrophic for passwords.
| Algorithm | Speed (hashes/sec on GPU) | Time to crack 8-char password |
|---|---|---|
| SHA-256 | ~10 billion | Seconds to minutes |
| bcrypt (cost 12) | ~10 thousand | Centuries |
The speed difference is intentional. bcrypt is designed to be slow — and that slowness is its greatest security feature.
Why SHA-256 Fails for Passwords
Problem 1: Speed
SHA-256("password123") → ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f
An attacker with this hash can try billions of passwords per second. At that rate, most human-chosen passwords fall within minutes.
Problem 2: No Built-in Salt
Without a salt, identical passwords produce identical hashes:
SHA-256("password123") → ef92b778... (same for every user)
An attacker can precompute hashes for common passwords (rainbow table) and quickly find matches across all users.
Problem 3: No Key Stretching
SHA-256 runs one round of computation. There’s no way to increase the work factor as hardware gets faster.
Generate SHA-256 hashes for data integrity (not passwords!) with our Hash Generator.
Why bcrypt Works
bcrypt solves all three problems:
Built-in Salt
bcrypt("password123") → $2b$12$LJ3m4ys3Lg5Ey1j3EXAMPLE.HashedOutputHere...
Each call generates a unique, random salt. Two users with “password123” get different hashes.
Configurable Cost Factor
The cost factor (work factor) controls computation time:
Cost 10: ~100ms per hash
Cost 12: ~400ms per hash (recommended)
Cost 14: ~1.6sec per hash
As hardware gets faster, increase the cost factor. Your login flow adds 400ms of delay; an attacker’s brute-force becomes 400,000× slower.
Intentional Slowness
bcrypt uses the Blowfish cipher with multiple rounds of key expansion. This is computationally expensive by design and resistant to GPU parallelization.
Modern Alternatives
| Algorithm | Strength | Best For |
|---|---|---|
| bcrypt | Proven, widely supported | Most applications |
| Argon2id | Memory-hard, newest standard | New applications, high security |
| scrypt | Memory-hard | When Argon2 is unavailable |
Argon2id won the Password Hashing Competition in 2015 and is the recommended choice for new projects. bcrypt remains excellent and is more widely supported.
Implementation
Node.js (bcrypt)
import bcrypt from 'bcrypt';
// Hash a password
const hash = await bcrypt.hash('password123', 12);
// Verify a password
const isValid = await bcrypt.compare('password123', hash);
Python (bcrypt)
import bcrypt
# Hash
hashed = bcrypt.hashpw(b'password123', bcrypt.gensalt(rounds=12))
# Verify
is_valid = bcrypt.checkpw(b'password123', hashed)
Best Practices
- Never use MD5 or SHA for passwords — They are too fast and lack salting.
- Use bcrypt with cost 12+ — Balance security and login performance.
- Generate strong passwords — Use our Password Generator to create high-entropy passwords.
- Rehash on login — When you increase the cost factor, rehash passwords when users log in.
- Never store plaintext — This should go without saying, but database breaches still expose plaintext passwords.
This article is part of our Encoding and Hashing Guide series.