Skip to content

Bcrypt Hashing

Introduction

Bcrypt is an adaptive password hashing function designed by Niels Provos and David Mazières in 1999. It's based on the Blowfish cipher and has become one of the most widely-used password hashing algorithms due to its security features and resistance to various attack methods.

Core Features

Key Characteristics

  • Adaptive work factor (cost factor)
  • Built-in salt generation
  • Constant-time comparison
  • Memory-hard operations
  • Based on Blowfish cipher's key setup phase

Algorithm Structure

The bcrypt hash format follows this structure:

$2[a|b|y]$[cost]$[22 characters of salt][31 characters of hash]

Example:

$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

Where:

  • $2a$ - Hash algorithm identifier
  • 10 - Work factor (cost)
  • N9qo8uLOickgx2ZMRZoMye - 22-character salt
  • Rest - The actual hash value

Technical Implementation

Work Factor

  • Controls the computational cost
  • Represented as 2^cost iterations
  • Recommended minimum of 10 (2^10 = 1,024 iterations)
  • Should be adjusted based on hardware capabilities
  • Typical range: 10-14 for general use

Salt Generation

  • Automatically generates a 16-byte (128-bit) cryptographic salt
  • Salt is base64 encoded into 22 characters
  • Unique per password
  • Prevents rainbow table attacks
  • Integrated into the algorithm (no separate salt storage needed)

Implementation Examples

Python Implementation

python
import bcrypt

def hash_password(password):
    # Convert the password to bytes
    password = password.encode('utf-8')
    
    # Generate salt and hash
    salt = bcrypt.gensalt(rounds=12)  # Work factor of 12
    hashed = bcrypt.hashpw(password, salt)
    
    return hashed

def verify_password(password, hashed):
    # Convert the password to bytes
    password = password.encode('utf-8')
    
    # Verify password
    return bcrypt.checkpw(password, hashed)

# Example usage
password = "mySecurePassword123"
hashed_password = hash_password(password)
is_valid = verify_password(password, hashed_password)

Node.js Implementation

javascript
const bcrypt = require('bcrypt');

async function hashPassword(password) {
    const saltRounds = 12;
    try {
        const hash = await bcrypt.hash(password, saltRounds);
        return hash;
    } catch (error) {
        throw new Error('Hashing failed');
    }
}

async function verifyPassword(password, hash) {
    try {
        const match = await bcrypt.compare(password, hash);
        return match;
    } catch (error) {
        throw new Error('Verification failed');
    }
}

Security Considerations

Advantages

  1. Adaptive Nature

    • Can be adjusted to remain secure as hardware improves
    • Allows for balance between security and performance
  2. Built-in Salt

    • Eliminates common implementation mistakes
    • Prevents rainbow table attacks
    • Unique per password
  3. Time-Memory Trade-off

    • Requires significant memory resources
    • Resistant to GPU-based attacks
    • Helps prevent large-scale cracking attempts

Best Practices

  1. Work Factor Selection

    • Choose based on server capabilities
    • Aim for ~250ms hash time
    • Regular assessment and adjustment
    • Consider user experience impact
  2. Implementation Guidelines

    • Use established libraries
    • Avoid custom implementations
    • Keep libraries updated
    • Implement secure password policies
  3. Error Handling

    • Use constant-time comparison
    • Handle errors gracefully
    • Avoid revealing specific error details
    • Log security-relevant events

Performance Considerations

Hardware Impact

  • CPU-intensive operation
  • Memory requirements increase with work factor
  • Consider server resources when selecting work factor
  • Monitor hash timing across different platforms

Benchmarking Guidelines

  1. Test hash generation times:

    • Different work factors
    • Various hardware configurations
    • Under different loads
    • With realistic data volumes
  2. Monitor system resources:

    • CPU usage
    • Memory consumption
    • Response times
    • Server load impact

Common Vulnerabilities and Mitigations

Known Issues

  1. Implementation Vulnerabilities

    • Incorrect salt handling
    • Weak work factors
    • Poor error handling
    • Timing attacks
  2. Environmental Risks

    • Insufficient entropy for salt
    • Memory constraints
    • CPU limitations
    • Power analysis attacks

Mitigation Strategies

  1. Secure Implementation

    • Use validated libraries
    • Regular security audits
    • Proper error handling
    • Secure key storage
  2. Operational Security

    • Monitor hash times
    • Regular work factor updates
    • Resource monitoring
    • Security logging

Migration Strategies

Upgrading Work Factors

  1. Gradual Migration

    • Hash verification time
    • Rehash upon login
    • Background migration
    • Progress tracking
  2. Implementation Steps

python
def verify_and_upgrade(password, stored_hash, new_work_factor):
    if bcrypt.checkpw(password, stored_hash):
        # Check if work factor needs upgrading
        current_work_factor = int(stored_hash.split('$')[2])
        if current_work_factor < new_work_factor:
            # Rehash with new work factor
            return bcrypt.hashpw(password, bcrypt.gensalt(new_work_factor))
    return stored_hash

Conclusion

Bcrypt remains a strong choice for password hashing due to its:

  • Adaptive nature
  • Built-in security features
  • Proven track record
  • Wide library support
  • Active maintenance

Regular assessment of work factors and adherence to implementation best practices ensures continued security in password storage systems.

Released under the MIT License.