Comparing Modern Password Hashers

Comparing Modern Password Hashers

Each algorithm has specific strengths making it suitable for different scenarios. Bcrypt remains excellent for systems with limited memory or when compatibility with older systems is required. Its maturity means extensive library support across all platforms. However, bcrypt's limited memory usage (4KB) makes it more vulnerable to ASIC attacks than memory-hard alternatives.

Scrypt provides superior ASIC resistance through tunable memory requirements but suffers from complex parameter selection and less widespread support. The algorithm's memory-hardness makes it ideal for cryptocurrency applications where ASIC resistance is paramount. For password hashing, scrypt's complexity often leads to suboptimal parameter choices that compromise security.

def compare_algorithms():
    """Compare performance and security characteristics"""
    
    password = "TestPassword123!"
    
    print("Algorithm Comparison (matching time cost ~100ms):\n")
    
    # Bcrypt
    start = time.time()
    bcrypt_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=11))
    bcrypt_time = time.time() - start
    
    # Scrypt  
    start = time.time()
    scrypt_salt = os.urandom(16)
    scrypt_hash = scrypt.hash(password.encode(), scrypt_salt, N=16384, r=8, p=1)
    scrypt_time = time.time() - start
    
    # Argon2id
    ph = PasswordHasher(time_cost=2, memory_cost=65536, parallelism=4)
    start = time.time()
    argon2_hash = ph.hash(password)
    argon2_time = time.time() - start
    
    print(f"Bcrypt:   {bcrypt_time:.3f}s (4KB memory)")
    print(f"Scrypt:   {scrypt_time:.3f}s (16MB memory)")
    print(f"Argon2id: {argon2_time:.3f}s (64MB memory)")
    
    print("\nSecurity Characteristics:")
    print("Bcrypt:   Good GPU resistance, limited ASIC resistance")
    print("Scrypt:   Excellent GPU/ASIC resistance, complex tuning")
    print("Argon2id: Best overall resistance, modern design")
    
    print("\nRecommended Minimum Parameters (2024):")
    print("Bcrypt:   cost=13")
    print("Scrypt:   N=32768, r=8, p=1")
    print("Argon2id: time=3, memory=64MB, threads=4")

compare_algorithms()