Cryptographic Hash Functions Explained: MD5, SHA-256 & Security

Cryptographic hash functions are fundamental building blocks of modern security. They power password storage, digital signatures, blockchain, file integrity verification, and much more. This guide explains how hash functions work, compares the most common algorithms, and covers security best practices you need to know.

What Is a Hash Function?

A cryptographic hash function takes an input of any size and produces a fixed-length output (the "hash" or "digest"). A good hash function has these properties:

  • Deterministic: The same input always produces the same hash
  • Fast to compute: Generating a hash is efficient
  • Pre-image resistant: Given a hash, it's infeasible to find the original input
  • Collision resistant: It's infeasible to find two different inputs with the same hash
  • Avalanche effect: A tiny change in input produces a completely different hash
# SHA-256 avalanche effect demonstration
echo -n "hello"  | sha256sum
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

echo -n "hello!" | sha256sum
# ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b
# Completely different output from just adding "!"

Common Hash Algorithms

MD5 (128-bit)

Designed by Ronald Rivest in 1991, MD5 produces a 128-bit (32 hex character) digest. It's fast but cryptographically broken — collision attacks have been practical since 2004.

# Command line
echo -n "Hello" | md5sum
# 8b1a9953c4611296a827abf8c47804d7

# Python
import hashlib
hashlib.md5(b"Hello").hexdigest()
# '8b1a9953c4611296a827abf8c47804d7'
⚠️ Do NOT use MD5 for security purposes. It is vulnerable to collision attacks and should only be used for non-security checksums (e.g., file deduplication).

SHA-1 (160-bit)

SHA-1 produces a 160-bit hash. Google demonstrated a practical collision (SHAttered) in 2017. Major browsers and certificate authorities have deprecated SHA-1. Avoid it for new projects.

SHA-256 (256-bit)

Part of the SHA-2 family designed by the NSA, SHA-256 is currently the industry standard for general-purpose hashing. It produces a 256-bit (64 hex character) digest and has no known practical attacks.

// JavaScript (Web Crypto API)
async function sha256(message) {
  const data = new TextEncoder().encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

await sha256("Hello");
// "185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969"
# Python
import hashlib
hashlib.sha256(b"Hello").hexdigest()
# '185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969'

SHA-3 (Variable length)

SHA-3 (Keccak) was standardized in 2015 as an alternative to SHA-2. It uses a completely different internal structure (sponge construction) and provides an independent security fallback if SHA-2 is ever compromised.

Hash Algorithm Comparison

  • MD5: 128-bit output, broken — use only for checksums
  • SHA-1: 160-bit output, deprecated — avoid for new work
  • SHA-256: 256-bit output, secure — the current standard
  • SHA-512: 512-bit output, secure — faster on 64-bit CPUs
  • SHA-3-256: 256-bit output, secure — independent alternative to SHA-2

Password Hashing: Why SHA-256 Isn't Enough

General-purpose hash functions like SHA-256 are too fast for password hashing. An attacker with a GPU can compute billions of SHA-256 hashes per second. Instead, use purpose-built password hashing functions:

  • bcrypt: Time-tested, configurable work factor, built-in salt
  • scrypt: Memory-hard, resists GPU attacks
  • Argon2: Winner of the Password Hashing Competition (2015), best choice for new projects
# Python: password hashing with bcrypt
import bcrypt

password = b"my_secure_password"
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password, salt)
# b'$2b$12$LJ3m4ys3Lz0YqB4K5Vh...'

# Verify
bcrypt.checkpw(b"my_secure_password", hashed)  # True
bcrypt.checkpw(b"wrong_password", hashed)       # False
💡 Rule of thumb: Use SHA-256 for data integrity (checksums, digital signatures). Use bcrypt/Argon2 for password storage. Never store passwords as plain SHA-256 hashes.

Real-World Applications

  • File integrity: Verify downloads haven't been tampered with by comparing SHA-256 checksums
  • Digital signatures: Hash the message first, then sign the hash with a private key
  • Blockchain: Bitcoin uses double SHA-256 for proof-of-work mining
  • HMAC: Hash-based Message Authentication Code combines a secret key with a hash for message authentication
  • Content addressing: Git uses SHA-1 (migrating to SHA-256) to identify commits and objects
# Verify a file download
sha256sum downloaded_file.tar.gz
# Compare output with the published checksum

# HMAC in Python
import hmac, hashlib
key = b"secret_key"
message = b"important data"
mac = hmac.new(key, message, hashlib.sha256).hexdigest()
print(mac)  # "a]..."

🛠️ Generate Hashes Online

Open Hash Tool →

Further Reading