What is Bcrypt?
Bcrypt is a password hashing function designed by Niels Provos and David Mazières, based on the Blowfish cipher. It incorporates a salt to protect against rainbow table attacks and is adaptive, allowing the iteration count to be increased to make it slower and more resistant to brute-force attacks.
How Bcrypt Works
Bcrypt uses the Eksblowfish algorithm, an enhanced version of Blowfish that requires an expensive key setup phase. The algorithm:
- Key Setup: Derives an encryption key from the password using the costly Eksblowfish key schedule
- Salt Generation: Creates a 128-bit random salt for each password
- Cost Factor: Performs 2^cost iterations, making brute-force attacks computationally expensive
- Output Format: Produces a 60-character string containing version, cost, salt, and hash
Security Considerations
Why Bcrypt is Secure:
- Adaptive Cost: Can increase computational cost as hardware improves
- Built-in Salt: Each password gets a unique salt, preventing rainbow table attacks
- Slow by Design: Deliberately slow to resist brute-force attacks
- Memory Hard: Requires memory access patterns that resist GPU acceleration
- Proven Track Record: Used successfully since 1999 with no practical vulnerabilities
Bcrypt vs Other Algorithms:
| Algorithm |
Speed |
Memory Usage |
GPU Resistant |
Recommendation |
| Bcrypt |
Slow |
4KB |
Good |
Recommended |
| Argon2 |
Configurable |
Configurable |
Excellent |
Best for new apps |
| PBKDF2 |
Configurable |
Minimal |
Poor |
Legacy support |
| Scrypt |
Slow |
Configurable |
Good |
Alternative option |
Hash Format
$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
- $2y$ - Algorithm identifier (2y = current version)
- 10 - Cost factor (2^10 = 1,024 rounds)
- N9qo8uLO... - Salt (22 characters)
- IjZAgcfl... - Hash (31 characters)
Cost Factor Guidelines
| Cost |
Iterations |
Time (approx) |
Use Case |
| 8 |
256 |
~15ms |
Testing only |
| 10 |
1,024 |
~60ms |
Minimum production |
| 12 |
4,096 |
~250ms |
Recommended |
| 14 |
16,384 |
~1s |
High security |
PHP
// Generate hash
$password = 'MySecurePassword123!';
$hash = password_hash($password, PASSWORD_BCRYPT, [
'cost' => 12
]);
// Verify password
if (password_verify($password, $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
// Get hash info
$info = password_get_info($hash);
print_r($info);
Node.js
const bcrypt = require('bcrypt');
// Generate hash
const password = 'MySecurePassword123!';
const saltRounds = 12;
// Async
bcrypt.hash(password, saltRounds, (err, hash) => {
console.log(hash);
});
// Sync
const hash = bcrypt.hashSync(password, saltRounds);
// Verify
bcrypt.compare(password, hash, (err, result) => {
console.log(result); // true
});
Python
import bcrypt
# Generate hash
password = b'MySecurePassword123!'
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password, salt)
# Verify password
if bcrypt.checkpw(password, hashed):
print("Password matches")
else:
print("Password does not match")
Java
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
// Generate hash
String password = "MySecurePassword123!";
String hashedPassword = encoder.encode(password);
// Verify password
boolean matches = encoder.matches(password, hashedPassword);
Security Best Practices
DO
- Use a cost factor of at least 10 (12 recommended)
- Increase cost factor as hardware improves
- Use bcrypt for password storage only
- Implement rate limiting on login attempts
- Use HTTPS for all authentication
- Consider using Argon2 for new projects
DON'T
- Store passwords in plain text
- Use MD5, SHA-1, or SHA-256 for passwords
- Implement your own crypto
- Use the same salt for all passwords
- Store passwords reversibly encrypted
- Use cost factors below 10 in production
Migration Strategy
If you're migrating from a weaker hash function:
- When user logs in, verify with old hash
- If valid, hash with bcrypt and update database
- Mark account as migrated
- After grace period, require password reset for non-migrated accounts
Performance Considerations
- Bcrypt is CPU-intensive by design
- Consider async hashing to avoid blocking
- Cache cost factor benchmarks per server
- Monitor hash generation time in production
- Balance security with user experience
Common Use Cases
User Authentication
Store user passwords securely in databases for web applications, mobile apps, and APIs
Admin Panels
Protect administrative access with strong password hashing for content management systems
API Keys
Hash API keys and tokens for secure storage while maintaining quick verification
Password Managers
Secure master passwords for password management applications
Implementation Examples
Password Hashing Workflow:
- Registration: User provides password → Generate bcrypt hash → Store hash in database
- Login: User provides password → Retrieve stored hash → Verify password against hash
- Password Change: Verify old password → Generate new hash → Update database
- Cost Factor Update: Re-hash passwords during login with new cost factor
Frequently Asked Questions
Q: What cost factor should I use?
A: Start with cost factor 12 for production. This provides good security while keeping login times reasonable. Benchmark on your actual hardware and adjust based on performance requirements.
Q: Can I decrypt a bcrypt hash?
A: No, bcrypt is a one-way function. You can only verify if a password matches a hash, not decrypt it back to the original password.
Q: Is bcrypt still secure in 2024?
A: Yes, bcrypt remains secure for password hashing. While newer algorithms like Argon2 offer additional features, bcrypt is still widely recommended and has no known vulnerabilities.
Q: How long should bcrypt hashing take?
A: Aim for 50-250ms for interactive logins. This balances security with user experience. Adjust the cost factor to achieve this timing on your servers.
Q: Should I add an additional salt to bcrypt?
A: No, bcrypt automatically generates and includes a cryptographically secure salt. Adding your own salt is unnecessary and doesn't improve security.
Technical Specifications
| Algorithm: |
Eksblowfish (Enhanced Blowfish) |
| Key Size: |
Up to 72 bytes (576 bits) |
| Salt Size: |
128 bits (16 bytes) |
| Output Size: |
184 bits (23 bytes) + metadata |
| Cost Range: |
4-31 (2^4 to 2^31 iterations) |
| Version Identifiers: |
$2a$, $2b$, $2x$, $2y$ |