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

  1. Setup: Configure development environment
  2. Data: Prepare required data
  3. Implementation: Build core functionality
  4. Testing: Verify correctness
  5. 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.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!