Cryptographic Hash Functions: MD5, SHA-256, and Beyond
Hash functions are everywhere—from password storage to blockchain to Git commits. But which algorithm should you use? MD5? SHA-256? Bcrypt? The answer depends on what you're protecting. Here's your complete guide to choosing the right hash.
What Hash Functions Actually Do
A hash function takes input of any size and produces a fixed-size output called a "digest" or "hash." The same input always produces the same output, but even a tiny change in input produces a completely different hash. This makes them perfect for verification without exposing the original data.
Input: "Hello, World!"
MD5: fc3ff98e8c6a0d3087d515c0473f8677
SHA-256: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f
Input: "Hello, World." (just added a period)
MD5: 08f7ae5dd5df036d92e65b5c9e5c4c24
SHA-256: 9f8de6d1cc2b0e8e8c8c4e4e4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f
Key Properties of Cryptographic Hashes
- Deterministic: Same input → same output, always
- One-way: Can't reverse-engineer input from output
- Collision-resistant: Hard to find two inputs with the same hash
- Avalanche effect: Small input change → completely different output
The Hash Algorithm Comparison
| Algorithm | Output Size | Speed | Security | Use For |
|---|---|---|---|---|
| MD5 | 128 bits | ⚡ Very fast | ❌ Broken | Checksums only |
| SHA-1 | 160 bits | ⚡ Fast | ⚠️ Weak | Legacy systems |
| SHA-256 | 256 bits | ⚡ Fast | ✅ Strong | Signatures, integrity |
| SHA-512 | 512 bits | ⚡ Fast | ✅ Strong | Extra security margin |
| Bcrypt | 184 bits | 🐢 Slow (intentional) | ✅ Strong | Passwords |
| Argon2 | Variable | 🐢 Slow (intentional) | ✅ Best | Passwords (modern) |
Practical Code Examples
Generating Hashes in JavaScript
// SHA-256 in the browser using Web Crypto API
async function sha256(message) {
const encoder = new TextEncoder();
const data = encoder.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('');
}
// Usage
const hash = await sha256('Hello, World!');
console.log(hash);
// "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
// Verifying file integrity
async function verifyFileHash(file, expectedHash) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const actualHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return actualHash === expectedHash;
}Password Hashing with Bcrypt (Node.js)
import bcrypt from 'bcrypt';
// Hashing a password (during registration)
async function hashPassword(plainPassword) {
const saltRounds = 12; // Higher = slower = more secure
const hash = await bcrypt.hash(plainPassword, saltRounds);
return hash; // "$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4c.4/4c.4/4c.4/4"
}
// Verifying a password (during login)
async function verifyPassword(plainPassword, storedHash) {
const isMatch = await bcrypt.compare(plainPassword, storedHash);
return isMatch; // true or false
}
// ❌ WRONG: Don't do this!
const badHash = await sha256(password); // Fast hash = easily cracked
// ✅ CORRECT: Use slow password hashes
const goodHash = await bcrypt.hash(password, 12);When to Use Which Hash
File Integrity Verification → SHA-256
Verify downloaded files match the expected hash. Fast and secure for non-secret data.
Password Storage → Bcrypt or Argon2
Slow hashes resist brute-force attacks. Argon2 is newer and recommended; bcrypt is widely supported.
Digital Signatures → SHA-256 or SHA-512
Sign documents and verify authenticity. Combined with asymmetric encryption (RSA, ECDSA).
Cache Keys / Deduplication → SHA-256 (or even MD5)
When security isn't a concern, any fast hash works for content-based identifiers.
API Request Signing (HMAC) → SHA-256
HMAC combines a hash with a secret key to authenticate API requests.
Common Hash Security Mistakes
Using Fast Hashes for Passwords
SHA-256 can compute billions of hashes per second on GPUs. That means an attacker can try billions of password guesses per second. Always use bcrypt, Argon2, or scrypt for passwords—they're intentionally slow.
Not Salting Password Hashes
Without a unique salt per password, identical passwords produce identical hashes. Attackers use "rainbow tables" of precomputed hashes. Bcrypt and Argon2 handle salting automatically—don't roll your own.
Trusting MD5 or SHA-1 for Security
MD5 and SHA-1 have known collision attacks—attackers can create different files with the same hash. For any security-critical application, use SHA-256 or stronger.
Comparing Hashes Insecurely
String comparison like hash1 === hash2 can leak timing information. Use constant-time comparison functions when verifying hashes in security contexts.
Frequently Asked Questions
Is MD5 safe to use for anything?
MD5 is broken for security purposes—don't use it for passwords or digital signatures. However, it's still acceptable for non-security uses like generating cache keys, detecting accidental file corruption, or creating content-based identifiers where attacks aren't a concern.
What's the difference between hashing and encryption?
Hashing is one-way: you can't recover the original data from a hash. Encryption is two-way: with the right key, you can decrypt and recover the original data. Use hashing for passwords and data verification; use encryption when you need to retrieve the original data later.
Why do password hashes need to be slow?
Fast hashes let attackers try billions of password guesses per second. Slow hashes like bcrypt or Argon2 are intentionally designed to take ~100-500ms each, making brute-force attacks impractical. A hash that takes 0.1 seconds to compute makes attacking a password list take months instead of minutes.
Wrapping Up
Hash functions are fundamental to modern security, but using the wrong one can leave you vulnerable. For passwords, always use slow hashes like bcrypt or Argon2. For integrity verification and signatures, SHA-256 is your go-to. And remember: hashing is one-way—it's not encryption.
Next steps: Generate hashes of test data using our tools to understand how different algorithms behave, then review your application's password storage implementation.
Related Resources
Internal Links:
External References: