InfoSec Notes
Comprehensive guide to hash functions including MD5, SHA family, properties, applications in password storage, integrity verification, and digital signatures with Python implementations.
What is a Hash Function?
A cryptographic hash function is a mathematical algorithm that maps data of arbitrary size to a fixed-size output (the hash or digest). It is a one-way function — you cannot recover the original input from the hash.
| Input (any size) | [Hash Function] → Fixed-size Output (digest) |
| "Hello" | SHA-256 → "185f8db32271fe25f561a6fc938b2e26..." (256 bits) |
| "Hello!" | SHA-256 → "334d016f755cd6dc58c53a86e183882f..." (256 bits) |
| [1GB file] | SHA-256 → "a1b2c3d4e5f6..." (still 256 bits) |
Required Properties
| Property | Description | Importance |
|---|---|---|
| Deterministic | Same input always gives same output | Verification works |
| Fixed output size | Any input → same size hash | Practical storage/comparison |
| Pre-image resistance | Cannot find input from hash | Passwords, commitments |
| Second pre-image resistance | Cannot find different input giving same hash | Document integrity |
| Collision resistance | Cannot find ANY two inputs with same hash | Digital signatures |
| Avalanche effect | Small input change → drastically different hash | Tamper detection |
Hash Algorithm Comparison
| Algorithm | Output Size | Status | Speed | Use Case |
|---|---|---|---|---|
| MD5 | 128 bits | BROKEN | Very Fast | Legacy checksums only |
| SHA-1 | 160 bits | BROKEN (2017) | Fast | Git (legacy), avoid |
| SHA-256 | 256 bits | SECURE | Medium | General purpose, Bitcoin |
| SHA-384 | 384 bits | SECURE | Medium | High-security applications |
| SHA-512 | 512 bits | SECURE | Fast (64-bit) | Large data, certificates |
| SHA-3-256 | 256 bits | SECURE | Medium | Alternative to SHA-2 |
| BLAKE2b | Variable | SECURE | Very Fast | High-performance apps |
| BLAKE3 | Variable | SECURE | Fastest | Parallel hashing |
Python Implementation
Applications of Hash Functions
1. Password Storage
2. Data Integrity Verification
# Verify downloaded file integrity
expected_hash = "e3b0c44298fc1c149afbf4c8996fb924..." # From publisher
computed_hash = hashlib.sha256(open("software.exe", "rb").read()).hexdigest()
if computed_hash == expected_hash:
print("File integrity verified - safe to install")
else:
print("WARNING: File has been tampered with!")3. Digital Signatures
Signing Process
Document → [SHA-256] → Hash → [Encrypt with Private Key] → Signature
Verification Process
Document → [SHA-256] → Computed Hash
Signature → [Decrypt with Public Key] → Original Hash
Compare: Computed Hash == Original Hash?
MD5 and SHA-1: Why They're Broken
MD5 Collision (2004)
# MD5 collision example (two different inputs, same MD5 hash)
# These were generated by Wang et al. (2004)
# In practice, attackers can create colliding PDFs, certificates, etc.
import hashlib
# Demonstration of why MD5 is broken
message1 = "Transfer $100 to Account A"
message2 = "Transfer $999 to Account B"
hash1 = hashlib.md5(message1.encode()).hexdigest()
hash2 = hashlib.md5(message2.encode()).hexdigest()
print(f"Different inputs, different hashes (as expected):")
print(f" MD5(\"{message1}\") = {hash1}")
print(f" MD5(\"{message2}\") = {hash2}")
print(f"\nBut researchers can CONSTRUCT two different files with SAME MD5!")
print(f"This means MD5 cannot guarantee document integrity.")
print(f"\nTimeline of MD5/SHA-1 breaks:")
print(f" 2004: MD5 collision found (Wang et al.)")
print(f" 2008: MD5 used to forge SSL certificates (Sotirov et al.)")
print(f" 2017: SHA-1 collision found (Google 'SHAttered' - $110K compute)")
print(f" 2020: SHA-1 chosen-prefix collision ($45K compute)")HMAC (Hash-based Message Authentication Code)
import hmac
import hashlib
def hmac_demonstration():
"""HMAC combines hash with secret key for authentication."""
secret_key = b"shared_secret_between_alice_and_bob"
message = b"Transfer $5000 from savings to checking"
# Create HMAC
mac = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
print(f"Message: {message.decode()}")
print(f"HMAC-SHA256: {mac}")
# Verify (receiver computes HMAC with same key)
received_message = b"Transfer $5000 from savings to checking"
computed_mac = hmac.new(secret_key, received_message, hashlib.sha256).hexdigest()
# Use constant-time comparison to prevent timing attacks
is_valid = hmac.compare_digest(mac, computed_mac)
print(f"Verification: {'VALID' if is_valid else 'INVALID'}")
# Tampered message fails verification
tampered = b"Transfer $50000 from savings to checking"
tampered_mac = hmac.new(secret_key, tampered, hashlib.sha256).hexdigest()
print(f"\nTampered verification: {hmac.compare_digest(mac, tampered_mac)}")
hmac_demonstration()Interview Questions
- Why can't you decrypt a hash to get the original data?
- Hash functions are mathematically one-way (pre-image resistant). Information is lost during hashing — infinite inputs map to finite outputs. You cannot determine which specific input produced a hash. Additionally, hash functions use non-invertible operations (modular arithmetic, bit shifting).
- What is a rainbow table attack and how do you prevent it?
- A rainbow table is a precomputed database mapping common passwords to their hashes. Prevention: use a unique random salt for each password. With salt, even identical passwords produce different hashes, making precomputed tables useless.
- Explain the birthday paradox and its relevance to hash collisions.
- The birthday paradox shows that in a group of just 23 people, there's a 50% chance two share a birthday. For hash functions, finding a collision requires approximately 2^(n/2) attempts (not 2^n). For MD5 (128-bit), collisions need ~2^64 operations — feasible with modern computing.
- Why is bcrypt/Argon2 preferred over SHA-256 for password hashing?
- SHA-256 is fast (designed for speed), which helps attackers try billions of guesses per second. bcrypt/Argon2 are intentionally slow (configurable work factor), memory-hard (resists GPU/ASIC attacks), and include built-in salt handling. They're designed specifically for password storage.
- What is the difference between a hash and an HMAC?
- A hash only takes data as input (anyone can compute it). An HMAC takes data + secret key, providing both integrity and authenticity. Only someone with the key can create a valid HMAC, preventing forgery. HMACs also resist length-extension attacks that affect plain hashes.
Summary
Hash functions are fundamental building blocks of information security, used for password storage, integrity verification, digital signatures, and authentication. Always use SHA-256 or better for security applications, use purpose-built KDFs (Argon2, bcrypt) for passwords, and never use MD5 or SHA-1 for any security purpose.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Cryptographic Hash Functions.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Information Security topic.
Search Terms
information-security, information security, information, security, cryptography, hash, functions, cryptographic hash functions
Related Information Security Topics