← run

sec-password-hashing

1.000
2/2 tests· security
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
```