sec-password-hashing
1.000
Challenge · difficulty 3/5
# Task Implement **`solution.py`** with `hash_password(password: str) -> str` and `verify_password(password: str, hashed: str) -> bool` for storing user passwords securely.
Proposed solution
```python
import hashlib
import os
import hmac
def hash_password(password: str) -> str:
"""
Hash a password using PBKDF2-HMAC-SHA256 with a random salt.
Returns the hashed password in the format: algorithm:salt:hash
"""
# Generate a random salt (16 bytes = 128 bits)
salt = os.urandom(16)
# Use PBKDF2-HMAC-SHA256 with 100,000 iterations
iterations = 100_000
dk = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, iterations)
# Convert to hex strings for storage
salt_hex = salt.hex()
hash_hex = dk.hex()
# Return in format: algorithm:salt:hash
return f"pbkdf2_sha256:{iterations}:{salt_hex}:{hash_hex}"
def verify_password(password: str, hashed: str) -> bool:
"""
Verify a password against a stored hash.
Returns True if the password matches the hash, False otherwise.
"""
try:
# Parse the stored hash
parts = hashed.split(':')
if len(parts) != 4:
return False
algorithm, iterations_str, salt_hex, hash_hex = parts
# Verify algorithm
if algorithm != 'pbkdf2_sha256':
return False
# Parse iterations
try:
iterations = int(iterations_str)
except ValueError:
return False
# Convert hex strings back to bytes
salt = bytes.fromhex(salt_hex)
original_hash = bytes.fromhex(hash_hex)
# Compute hash with the provided password and extracted salt/iterations
computed_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, iterations)
# Use constant-time comparison to prevent timing attacks
return hmac.compare_digest(computed_hash, original_hash)
except Exception:
return False
```