MD5 vs SHA-256 — When to Use Each and When Not to Use MD5
MD5 is broken for security use cases but still useful for checksums and non-security hashing. SHA-256 is the modern standard for cryptographic integrity. Learn the differences,...
MD5 is broken for cryptographic use but remains useful for non-security checksum applications. SHA-256 is the modern standard for integrity verification, digital signatures, and security applications.
Generate hashes instantly with the Hash Generator.
The key differences
| Property | MD5 | SHA-256 |
|---|---|---|
| Output size | 128 bits (32 hex chars) | 256 bits (64 hex chars) |
| Speed | Very fast (~1 GB/s) | Fast (~500 MB/s) |
| Collision resistance | ❌ Broken (2004) | ✅ No known collisions |
| Pre-image resistance | ✅ Computationally secure | ✅ Strong |
| Cryptographic use | ❌ Never | ✅ Recommended |
| Password hashing | ❌ Never | ❌ Too fast (use bcrypt) |
| File checksums | ✅ OK (for corruption only) | ✅ Preferred |
| Digital signatures | ❌ Never | ✅ Standard |
| SSL certificates | ❌ Deprecated | ✅ Required |
Why MD5 is broken for security
In 2004, researchers demonstrated MD5 collision attacks — finding two different inputs that produce the same MD5 hash:
# These two different strings have the same MD5 hash:
# (simplified example — real collision requires crafted binary data)
# d131dd02c5e6eec4693d9a0698aff95c (different inputs, same hash)
# Practical attacks:
# - 2008: Researchers forged a CA certificate using MD5 collisions
# - 2012: Flame malware used MD5 collision to fake Windows updates
# - 2019: "HashClash" tool creates file collisions in seconds
Consequence: An attacker can create a malicious file that has the same MD5 hash as a legitimate file. You cannot verify integrity with MD5 alone.
MD5 is still fine for non-security use cases
import crypto from 'crypto';
// MD5 is fast and useful for non-security checksums:
// ✅ Cache key generation (fast hash of content):
function cacheKey(content) {
return crypto.createHash('md5').update(content).digest('hex');
}
// ✅ ETag generation for HTTP caching:
function generateETag(body) {
return `"${crypto.createHash('md5').update(body).digest('hex')}"`;
}
// ✅ Detecting file duplicates (performance, not security):
function fileFingerprint(buffer) {
return crypto.createHash('md5').update(buffer).digest('hex');
}
// ✅ Gravatar URL (email MD5 hash — their legacy API):
function gravatarUrl(email) {
const hash = crypto.createHash('md5')
.update(email.trim().toLowerCase())
.digest('hex');
return `https://www.gravatar.com/avatar/${hash}`;
}
SHA-256 for security-critical applications
import crypto from 'crypto';
// ✅ File integrity verification:
function sha256File(buffer) {
return crypto.createHash('sha256').update(buffer).digest('hex');
}
// ✅ API request signing:
function signRequest(secret, payload) {
return crypto.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
}
// ✅ Token generation:
function generateToken(userId, secret) {
const data = `${userId}:${Date.now()}`;
return crypto.createHmac('sha256', secret).update(data).digest('hex');
}
// ✅ Password reset tokens (short-lived):
import { randomBytes } from 'crypto';
function generateResetToken() {
return randomBytes(32).toString('hex'); // 64-char hex string
}
Python comparison
import hashlib
import time
data = b'Hello, World!' * 1000000 # 13MB test data
# MD5 speed:
start = time.perf_counter()
md5 = hashlib.md5(data).hexdigest()
print(f"MD5: {len(md5)} chars, {time.perf_counter()-start:.3f}s")
# SHA-256 speed:
start = time.perf_counter()
sha256 = hashlib.sha256(data).hexdigest()
print(f"SHA-256: {len(sha256)} chars, {time.perf_counter()-start:.3f}s")
# SHA-512 speed:
start = time.perf_counter()
sha512 = hashlib.sha512(data).hexdigest()
print(f"SHA-512: {len(sha512)} chars, {time.perf_counter()-start:.3f}s")
# Typical output:
# MD5: 32 chars, 0.021s
# SHA-256: 64 chars, 0.038s
# SHA-512: 128 chars, 0.024s (faster than SHA-256 on 64-bit systems!)
Migration from MD5 to SHA-256
// Migrate MD5 ETags to SHA-256:
// Old: MD5 of content
// New: SHA-256 of content
// Handle both during transition:
function generateETag(content) {
return `"sha256-${crypto.createHash('sha256').update(content).digest('base64')}"`;
}
// HTTP response:
// ETag: "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
Which to choose: decision guide
Need cryptographic security?
Yes → SHA-256 (or SHA-3 for future-proofing)
Hashing passwords?
→ bcrypt, Argon2id, or scrypt (NEVER MD5 or plain SHA)
Simple deduplication or cache keys?
Performance critical → MD5
Not performance critical → SHA-256 (safer habit)
File integrity for downloads?
Need tamper detection → SHA-256
Corruption detection only → MD5 is OK (but SHA-256 is standard)
HMAC signing?
→ HMAC-SHA256 always
Related tools
- Hash Generator — generate MD5, SHA-256, SHA-512
- Password Generator — generate secure random values
- HMAC Authentication — sign requests with SHA-256
Related posts
- MD5 Is Dead. Use These Instead. — MD5 was broken in 2004 and is trivially cracked for passwords. Here's what to us…
- bcrypt Password Hashing — Why You Should Use bcrypt and How to Implement It — bcrypt is the standard password hashing algorithm for web applications. Learn wh…
- File Integrity Verification with Checksums — SHA-256 and MD5 — Verify file integrity using SHA-256 and MD5 checksums. Learn how to generate and…
- Hash Functions Comparison — MD5, SHA-1, SHA-256, bcrypt, Argon2 — Hash functions have different speed, output size, and security properties. MD5 a…
- SHA-256 Hash — How It Works and How to Use It in Code — SHA-256 produces a 256-bit (64 hex character) hash. It's used for data integrity…
Related tool
Generate MD5, SHA-1, SHA-256, and SHA-512 hashes client-side.
Written by Mian Ali Khalid. Part of the Encoding & Crypto pillar.