What bcrypt Actually Is
A Blowfish-based password hashing scheme designed by Niels Provos & David Mazières (1999). Deliberately slow and adaptive — bcrypt's cost factor lets security scale with hardware improvements.
Where bcrypt Is Used
- Linux PAM (
/etc/shadow) - PHP
password_hash() - Node.js
bcrypt/bcryptjs - Django (optional backend)
- Ruby on Rails (default via
has_secure_password)
Three-Part Output Anatomy
Why bcrypt Is Slow: The Eksblowfish Key Schedule
The cost factor is not an arbitrary dial — it is literally an exponent. bcrypt runs Blowfish's key setup, then repeats it 2cost times, each round re-mixing your password and salt into an 18-word subkey array (the P-arrayThe 18 32-bit subkeys Blowfish derives from its key. In bcrypt these are re-derived every round, so the whole key schedule — not just one hash — is what gets repeated 2^cost times.) and four 256-entry substitution boxes (the S-boxesFour lookup tables of 256 32-bit words each = 4 KB of state that must be held and rewritten. This size is what makes bcrypt awkward to parallelize on a GPU's small per-core memory., 4 KB of state). That 4 KB of constantly-rewritten state is what makes bcrypt awkward to run massively-parallel on a GPU.
cost 6 → 26 = 64 key-expansion rounds
The 72-Byte Limit — bcrypt's #1 Footgun
bcrypt only feeds the first 72 bytes of a password into the key schedule. Everything after byte 72 is silently ignored. Two different passwords that share the same 72-byte prefix therefore produce a hash that verifies against either one. Type two long passwords below that agree for the first 72 bytes but differ afterward, and watch them cross-verify.
Hash Generator
Enter a password and choose a cost factor. The output is a real bcrypt hash computed in your browser — not simulated.
Input
Output
Cost Factor Timing Benchmark
Hashes the same password at cost factors 8 through 14, sequentially. Each +1 in cost doubles the computation time. This is by design — the slowness IS the security.
Results
Verify & Timing-Safe Comparison
bcrypt's headline defense is slowness + per-user salt (Exhibits 1 & 3) — that is what
survives a database breach. Constant-time comparison, shown here, is a secondary hardening:
it stops a subtler leak in how you compare the final hash. bcrypt.compare() checks a
password against a stored hash in constant time, closing a
timing oracleAn attacker who can measure how long a comparison takes and learn a secret from it. A naive byte-by-byte === returns faster on the first mismatch, so response time leaks how many leading bytes were guessed correctly..
Basic Verify
Timing Leak: This Is Why You Never Compare Hashes With ===
A naive === comparison returns as soon as it hits the first mismatched byte, so it runs
longer the more leading bytes an attacker guesses correctly. That duration is a leak.
bcrypt.compare() checks every byte regardless, so its time reveals nothing.
Honesty note: a real === leak on a modern CPU is a few nanoseconds — far too small to see on a bar. Choose how to expose it:
Naive === (variable timing)
Constant-time compare
bcrypt.compare(), HMAC tags, tokens.
But keep it in proportion: bcrypt's defining value is being deliberately slow and salted,
not the constant-time compare. That compare is the last mile of an already-strong scheme.
bcrypt vs Alternatives
Not all hashing algorithms are equal. This comparison shows why bcrypt remains a strong choice and when to prefer alternatives.
Algorithm Comparison
| Algorithm | Year | Adaptive | Memory-hard | GPU-resistant | Status |
|---|
Live Timing: bcrypt vs PBKDF2
Hash the same password with bcrypt (cost 12) and PBKDF2 (100,000 rounds via WebCrypto).
Real-World Attack Demo
Three breach scenarios showing what happens when passwords are stored as plaintext, unsalted MD5, or bcrypt hashes.