Every application that stores passwords faces the same security requirement: passwords must never be stored in plaintext, and they must be stored in a way that makes bulk cracking computationally impractical even if the database is stolen.
MD5 and SHA-256 are fast cryptographic hash functions — which makes them terrible for passwords. bcrypt was specifically designed to be slow, and that slowness is the entire point.
Generate a bcrypt Hash
bcrypt Hash Generator
Hash passwords using bcrypt.
Why Fast Hashes Are Dangerous for Passwords
MD5, SHA-1, SHA-256, and SHA-512 are designed for speed. A modern GPU can compute:
- MD5: ~40 billion hashes per second
- SHA-256: ~10 billion hashes per second
- bcrypt (cost 12): ~250 hashes per second
This speed difference is catastrophic for password security. If an attacker obtains your database, they can run dictionary attacks and rainbow table attacks against fast hashes at billions of attempts per second. An 8-character password can be cracked via brute force in seconds to minutes against MD5.
Against bcrypt at cost 12, the same attack takes years to centuries on the same hardware.
How bcrypt Works
bcrypt was designed in 1999 by Niels Provos and David Mazières specifically for password hashing. It has three key properties:
1. Adaptive Cost Factor
bcrypt includes a work factor (cost factor) — an integer that controls how many iterations of hashing occur. Every increment doubles the computation time.
| Cost | Approx. Time (modern server) | Hashes/sec (GPU attack) |
|---|---|---|
| 10 | ~100ms | ~1,000 |
| 12 | ~400ms | ~250 |
| 14 | ~1.5s | ~63 |
| 16 | ~6s | ~16 |
As hardware gets faster, you increase the cost factor — keeping the protection proportional to computing power growth.
2. Built-in Salt
bcrypt generates a unique random 128-bit salt for every hash automatically. This means two identical passwords produce completely different hash strings:
Password: "hunter2"
Hash 1: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewqxaX9ov
Hash 2: $2b$12$eImiTXuWVxfM37uY4JANjQ.X9YKfGGmFIDSMa2L4T7q6k
Both verify correctly against "hunter2" even though they look entirely different. No rainbow table can be precomputed because the salt is embedded in the hash itself.
3. Fixed Output Length
bcrypt always produces a 60-character string regardless of input length, making storage simple and consistent.
Reading a bcrypt Hash
A bcrypt hash looks like this:
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewqxaX9ovXZTx26
Breaking it down:
$2b$ → bcrypt algorithm version (2b is current)
12$ → Cost factor
LQv3c1yqBWVHxkd0LHAkCO → 22-char salt (Base64 encoded)
Yz6TtxMQJqhN8/LewqxaX9ovXZTx26 → 31-char hash
Everything needed to verify a password is embedded in the single hash string — no separate salt storage required.
bcrypt vs the Alternatives
| Algorithm | Designed For | Password Use | Notes |
|---|---|---|---|
| MD5 | Checksums | ❌ Never | 40B hashes/sec on GPU; completely insecure |
| SHA-256 | Data integrity | ❌ Never | Fast by design; no salt, no cost factor |
| SHA-512 | Data integrity | ❌ Never | Same problem as SHA-256, just longer |
| bcrypt | Password hashing | ✅ Yes | Adaptive cost, built-in salt |
| scrypt | Password hashing | ✅ Yes | Also memory-hard; good alternative |
| Argon2 | Password hashing | ✅ Yes (recommended) | Winner of PHC; memory-hard; newest standard |
| PBKDF2 | Key derivation | ✅ Acceptable | NIST-approved; used in many standards |
Recommendation hierarchy: Argon2id > bcrypt > scrypt > PBKDF2. Avoid MD5 and SHA for passwords entirely — there is no acceptable use case.
Implementation Examples
Node.js (bcryptjs)
const bcrypt = require('bcryptjs');
// Hash a password
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
// Verify a password
const isValid = await bcrypt.compare(inputPassword, storedHash);
Python (bcrypt)
import bcrypt
# Hash
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
# Verify
is_valid = bcrypt.checkpw(input_password.encode('utf-8'), hashed)
PHP
// Hash
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// Verify
$isValid = password_verify($inputPassword, $hash);
Choosing the Right Cost Factor
The rule: choose the highest cost factor that keeps login time under 100–400ms on your production server. Too slow and it becomes a denial-of-service vector (an attacker floods login requests, consuming server resources).
Testing approach:
const start = Date.now();
await bcrypt.hash('test', 12);
console.log(`Cost 12: ${Date.now() - start}ms`);
Aim for 200–400ms. If your server is powerful enough to do cost 14 in 400ms, use 14. Revisit the cost factor as hardware improves.
Common Mistakes
Hashing the hash: Never run bcrypt output through another hash function. The output of bcrypt is already the secure stored form.
Pre-hashing with SHA-256: Some implementations hash the password with SHA-256 before bcrypt to handle bcrypt's 72-character input limit. This is generally unnecessary for typical passwords but can help for very long passphrases.
Using cost 10 in 2026: Cost 10 was a reasonable default in 2011. With 2026 hardware, use at least 12, ideally 13–14.
Storing salts separately: bcrypt embeds the salt in the hash string. No separate salt column is needed.
Privacy Note
FluxToolkit's bcrypt generator runs entirely in your browser. The passwords you test are never transmitted to our servers. bcrypt hashing is performed client-side using JavaScript — your input stays on your device.
Frequently Asked Questions
Can I crack a bcrypt hash?
Bcrypt hashes cannot be reversed (cracked) directly — hashing is one-way. Attackers can only attack by guessing the original password and comparing. With cost 12, a GPU manages ~250 guesses per second, making brute force impractical for strong passwords.
Is bcrypt still the best choice in 2026?
Argon2id is now the recommended algorithm for new implementations (it won the Password Hashing Competition in 2015). However, bcrypt is still highly secure and widely supported. Using bcrypt correctly is far better than using Argon2id incorrectly.
What is bcrypt's 72-character limit?
bcrypt only processes the first 72 bytes of the input. Passwords or passphrases longer than 72 bytes are silently truncated. This is rarely a problem for typical passwords but should be noted for passphrase-based authentication.
Should I salt before bcrypt?
No. bcrypt generates its own random salt automatically. Adding your own salt before bcrypt provides no additional security and adds complexity without benefit.
Does FluxToolkit store passwords I hash?
No. Everything runs client-side in your browser. No input is transmitted to or stored on our servers.
Related Articles
- SHA-256 vs MD5 vs bcrypt Guide — Full comparison of hashing algorithms.
- Strong Passwords & Cryptographic Hashes — Password generation and storage best practices.
- SHA-512 vs SHA-256 Guide — When to use SHA-512 for data integrity use cases.
- HMAC Generator Guide — Message authentication using cryptographic hashes.
- JWT Decoder Guide — How password hashing fits into authentication flows.