Hash Functions & HMAC
๐ฅ Vibe Prompt
"Compare SHA-256, SHA-3, SHA-512 hash speeds. Implement HMAC for API authentication."
import hashlib, hmac, time
def bench_hash(name, data, func):
start = time.time()
for _ in range(100000):
func(data).hexdigest()
elapsed = time.time() - start
print(f"{name}: {elapsed:.2f}s ({100000/elapsed:.0f} hps)")
data = b"Hello, Security!" * 1000
bench_hash("SHA-256", data, hashlib.sha256)
bench_hash("SHA-512", data, hashlib.sha512)
bench_hash("SHA-3-256", data, hashlib.sha3_256)
bench_hash("BLAKE2b", data, hashlib.blake2b)
# HMAC for API auth
secret_key = b"api-secret-key-12345"
message = b"GET /api/orders 1700000000"
hmac_sig = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print(f"\nHMAC-SHA256: {hmac_sig}")
# Verify
expected = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print(f"Verified: {hmac.compare_digest(hmac_sig, expected)}")
Applications
- Password storage
- File integrity (checksums)
- API authentication (HMAC)
- Blockchain (Merkle tree)
- Digital signatures
Chapter Summary
- Understand core concepts and principles
- Master implementation methods and techniques
- Familiar with common issues and solutions
- Able to apply in real projects
Further Reading
- Official documentation and API references
- Open source examples on GitHub
- Technical books and online courses
- Community discussions and tech blogs
Implementation Example
Basic Example
# This section provides a complete implementation example
Steps
- Setup: Configure development environment
- Data: Prepare required data
- Implementation: Build core functionality
- Testing: Verify correctness
- Optimization: Improve performance
Common Errors
| Error Type | Cause | Solution | |------------|-------|----------| | Compilation | Syntax | Check code syntax | | Runtime | Environment | Verify dependencies installed | | Logic | Algorithm | Step-by-step debugging | | Performance | Efficiency | Use profilers |
Code Example
import sys
def main():
print("Hello, World!")
if __name__ == "__main__":
main()
References
- Official documentation
- API reference
- Open source examples
- Community discussions
Hash Functions
A hash function maps data of arbitrary size to a fixed-size output (digest).
Properties of Secure Hash Functions
| Property | Description | Importance | |----------|-------------|------------| | Deterministic | Same input always produces same output | Essential | | Fast computation | Quick to calculate for any input | Practical | | Preimage resistant | Cannot reverse hash to find input | Security critical | | Second preimage resistant | Cannot find different input with same hash | Security critical | | Collision resistant | Cannot find any two inputs with same hash | Security critical | | Avalanche effect | Small input change causes ~50% bit change | Randomness |
Common Hash Algorithms
| Algorithm | Output Size | Security Status | Use Case | |-----------|-------------|-----------------|----------| | MD5 | 128 bits | โ Broken | Legacy checksums only | | SHA-1 | 160 bits | โ Broken (SHAttered) | Deprecated, avoid | | SHA-256 | 256 bits | โ Secure | General purpose | | SHA-3-256 | 256 bits | โ Secure | Future-proof | | BLAKE2b | 256-512 bits | โ Secure | High performance |
Python Examples
import hashlib
def hash_examples():
message = b"Hello, Security World!"
# SHA-256
sha256 = hashlib.sha256(message).hexdigest()
print(f"SHA-256: {sha256}")
print(f"Length: {len(sha256)} hex chars = {len(sha256) * 4} bits\n")
# SHA-512
sha512 = hashlib.sha512(message).hexdigest()
print(f"SHA-512: {sha512}")
print(f"Length: {len(sha512)} hex chars = {len(sha512) * 4} bits\n")
# BLAKE2b
blake2 = hashlib.blake2b(message, digest_size=32).hexdigest()
print(f"BLAKE2b: {blake2}")
# Demonstrate avalanche effect
message2 = b"Hello, Security World?" # One char difference
hash2 = hashlib.sha256(message2).hexdigest()
diff_bits = sum(
bin(int(a, 16) ^ int(b, 16)).count('1')
for a, b in zip(sha256, hash2)
)
print(f"\nBit difference with 1-char change: {diff_bits} / 256")
hash_examples()
HMAC (Hash-Based Message Authentication Code)
HMAC uses a hash function combined with a secret key to verify both authenticity and integrity.
Why HMAC Over Plain Hash?
| Attack | Plain Hash | HMAC | |--------|------------|------| | Tampering | โ Attacker can recalculate hash | โ Key unknown | | Length extension | โ Vulnerable (SHA-256) | โ Resistant | | Replay | โ No protection | โ Keyed per session | | Forgery | โ Anyone can create | โ Requires secret key |
HMAC Implementation
import hmac
import hashlib
def create_hmac(message: str, secret: str) -> str:
"""Create HMAC-SHA256 signature."""
return hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
def verify_hmac(message: str, secret: str, signature: str) -> bool:
"""Verify HMAC signature (constant-time comparison)."""
expected = create_hmac(message, secret)
return hmac.compare_digest(expected, signature)
# API request signing
SECRET = "my-api-secret-key-123"
request_body = '{"user": "alice", "action": "transfer", "amount": 100}'
signature = create_hmac(request_body, SECRET)
print(f"Signature: {signature}")
# Server verifies
is_valid = verify_hmac(request_body, SECRET, signature)
print(f"Valid: {is_valid}")
# Tampered message fails
tampered = '{"user": "alice", "action": "transfer", "amount": 9999}'
print(f"Tampered valid: {verify_hmac(tampered, SECRET, signature)}")
Password Hashing
Use dedicated password hashing functions, not general-purpose hashes.
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
"""Hash password with bcrypt (includes salt)."""
return pwd_context.hash(password)
def verify_password(password: str, hashed: str) -> bool:
"""Verify password against hash."""
return pwd_context.verify(password, hashed)
# Registration
hashed = hash_password("MySecureP@ss123")
print(f"Bcrypt hash: {hashed}")
# Login attempt
print(f"Correct password: {verify_password('MySecureP@ss123', hashed)}")
print(f"Wrong password: {verify_password('wrong', hashed)}")
Summary
Hash functions provide integrity verification, HMAC adds authenticity with a secret key, and password hashing protects user credentials from breaches.
Key takeaways:
- Hash functions: fixed-size output, one-way, collision-resistant |
- SHA-256 is the current standard for general hashing |
- HMAC = hash + secret key for authenticated integrity |
- Use
hmac.compare_digest()for constant-time comparison | - Never use MD5 or SHA-1 for security-critical applications |
- Password hashing: use bcrypt, argon2, or scrypt (not plain SHA) |
- HMAC is used in API request signing and JWT token verification |
What's Next: PKI and Certificates
The next chapter covers Public Key Infrastructure and digital certificates.