The SHA-2 Family: Secure but Still Inappropriate
The SHA-2 Family: Secure but Still Inappropriate
SHA-2, designed by the NSA and published in 2001, addressed SHA-1's weaknesses through significant algorithmic improvements. The family includes multiple variants: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256, with numbers indicating output bit length. SHA-256, producing 256-bit hashes, has become the most widely adopted variant, securing everything from TLS certificates to blockchain transactions.
SHA-2's improved design provides excellent collision resistance and preimage security. No practical attacks against full SHA-2 exist despite extensive cryptanalysis. The algorithm's structure, based on the Merkle-Damgård construction with a Davies-Meyer compression function, incorporates lessons learned from MD5 and SHA-1 vulnerabilities. For general cryptographic purposes, SHA-2 remains highly secure and recommended.
However, SHA-2's strength as a general-purpose hash function becomes its weakness for password hashing. Modern implementations achieve extraordinary speeds: software implementations process gigabytes per second, while hardware acceleration reaches even higher rates. This speed, combined with password predictability, makes brute force attacks devastatingly effective:
import hashlib
import secrets
import time
def sha256_password_vulnerability():
"""Demonstrate why SHA-256 is inappropriate for passwords despite being secure"""
# Generate a "secure" 8-character password
password = "Tr0ub4d0r&3"
sha256_hash = hashlib.sha256(password.encode()).hexdigest()
print(f"Password: {password}")
print(f"SHA-256 hash: {sha256_hash}")
# Benchmark SHA-256 speed
iterations = 5000000
start = time.time()
for i in range(iterations):
hashlib.sha256(f"test{i}".encode()).hexdigest()
elapsed = time.time() - start
rate = iterations / elapsed
print(f"\nSHA-256 Benchmark:")
print(f"Hashed {iterations:,} passwords in {elapsed:.2f} seconds")
print(f"Rate: {rate:,.0f} hashes/second on a single CPU core")
# Calculate brute force time for different password complexities
print("\nBrute Force Time Estimates (single CPU core):")
complexities = [
("8 char lowercase", 26**8),
("8 char alphanumeric", 62**8),
("8 char all printable", 94**8),
("10 char alphanumeric", 62**10),
("12 char alphanumeric", 62**12)
]
for desc, space in complexities:
time_seconds = space / rate
time_hours = time_seconds / 3600
time_days = time_hours / 24
time_years = time_days / 365
if time_years > 1:
print(f"{desc}: {time_years:,.1f} years")
elif time_days > 1:
print(f"{desc}: {time_days:,.1f} days")
elif time_hours > 1:
print(f"{desc}: {time_hours:,.1f} hours")
else:
print(f"{desc}: {time_seconds:,.1f} seconds")
print("\nNote: GPUs can be 100-1000x faster than CPUs for password cracking!")
sha256_password_vulnerability()