SHA-256 vs MD5: Differences, Use Cases, and When Not to Use MD5
Every developer encounters hash functions — verifying file downloads, storing passwords, generating checksums, building caches, creating ETags. The two names that appear most often are MD5 and SHA-256. They look similar on the surface: both take input and produce a fixed-length hex string. But they are fundamentally different in security, speed, and appropriate use cases. Choosing the wrong one has serious consequences. This guide explains what each algorithm does, why MD5 is broken for security purposes, and exactly when to use each one.
What Is a Cryptographic Hash Function?
A hash function takes an input of any size and produces a fixed-length output called a digest or hash. Good cryptographic hash functions have four properties: deterministic (same input always produces same output), fast to compute, pre-image resistant (cannot reverse the hash to find the input), and collision resistant (cannot find two different inputs that produce the same hash).
The fourth property — collision resistance — is where MD5 fails completely in 2026, and why SHA-256 is the modern standard.
MD5: Fast but Cryptographically Broken
MD5 (Message Digest Algorithm 5) was designed by Ron Rivest in 1991 and produces a 128-bit (32 hex character) digest. For over a decade it was the standard for file checksums and digital signatures. In 2004, researchers demonstrated the first practical MD5 collision — two different inputs producing the same hash. By 2008, researchers created a rogue CA certificate using MD5 collisions, demonstrating that the algorithm was broken for certificate signing. By 2012, the Flame malware used MD5 collisions to forge Windows Update signatures.
MD5 is now cryptographically broken. A modern GPU can compute over 60 billion MD5 hashes per second, making brute-force attacks against MD5-hashed passwords trivial. Rainbow tables — precomputed tables of common passwords and their MD5 hashes — allow instant lookup of billions of hashed passwords with no computation at all.
MD5 output
MD5("Hello, World!") = 65a8e27d8879283831b664bd8b7f0ad4
MD5("") = d41d8cd98f00b204e9800998ecf8427e
MD5("hello") = 5d41402abc4b2a76b9719d911017c592
MD5("hellp") = 53b7c7f0fddb6e46fba1b0d96be1c2be # one char different → completely different hash
SHA-256: The Modern Standard
SHA-256 (Secure Hash Algorithm 256-bit) is part of the SHA-2 family, published by NIST in 2001. It produces a 256-bit (64 hex character) digest. As of 2026, no practical collision attack against SHA-256 exists. The algorithm is used in Bitcoin (proof of work), TLS certificates, code signing, HMAC authentication, and the vast majority of modern security-critical applications.
SHA-256 is slower than MD5 by design for some use cases, but still fast enough for checksums and data integrity — a modern CPU computes SHA-256 at around 500MB/second for large files, which is imperceptible for typical file sizes.
SHA-256 output
SHA256("Hello, World!") = dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986d
SHA256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
SHA256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Side-by-Side Comparison
| Property | MD5 | SHA-256 |
|---|---|---|
| Output length | 128 bits (32 hex chars) | 256 bits (64 hex chars) |
| Collision resistance | ❌ Broken since 2004 | ✅ No known attacks |
| Pre-image resistance | ⚠️ Weakened | ✅ Strong |
| Speed (software) | Very fast (~8 GB/s on modern CPU) | Fast (~500 MB/s on modern CPU) |
| GPU attack speed | 60+ billion/sec | 10+ billion/sec |
| Used in TLS certs | ❌ Deprecated by all CAs | ✅ Standard |
| Used in Bitcoin | No | ✅ Core algorithm |
| Password hashing | ❌ Never use | ⚠️ Use bcrypt/Argon2 instead |
| File checksums | ⚠️ OK for non-security use | ✅ Recommended |
When to Use SHA-256
File integrity verification. SHA-256 checksums confirm that a downloaded file has not been corrupted or tampered with. Software distributions (Linux ISOs, Python releases, npm packages) publish SHA-256 checksums alongside their files. After downloading, compute the hash and compare — any difference indicates corruption or tampering.
HMAC authentication. HMAC-SHA256 is the standard for API request signing, webhook verification, and message authentication codes. It combines a secret key with your data to produce a tag that proves both the message origin and integrity. GitHub webhooks, Stripe webhooks, and most major APIs use HMAC-SHA256 for payload verification.
Digital certificates and TLS. All modern TLS certificates use SHA-256 signatures. Certificate authorities stopped issuing SHA-1 certificates in 2017 after collision attacks made them insecure.
Data deduplication and content addressing. Git uses SHA-1 (being migrated to SHA-256) to identify every commit, tree, and blob by content hash. Content-addressable storage systems use SHA-256 to identify unique content — if two files have the same hash, they are identical, with no false positives possible.
Caching and ETags. Generate an ETag for an HTTP response by hashing its content. If the content changes, the hash changes, and clients know to re-fetch. Use SHA-256 truncated to 16 characters for a compact ETag that is effectively collision-free at typical cache sizes.
When MD5 Is Still Acceptable
MD5 remains acceptable for non-security purposes where speed matters and collision resistance is irrelevant. Checksumming large files for corruption detection (not tampering detection) during internal transfers is a common example — a one-in-a-trillion chance of undetected random corruption is acceptable for a backup job; deliberate forgery is not a concern in this context. Cache keys derived from non-sensitive data, non-cryptographic content fingerprinting, and hash table implementations are other examples where MD5's speed advantage is useful and its cryptographic weaknesses are irrelevant.
Never use MD5 for: password hashing, digital signatures, certificate signing, security tokens, HMAC, or any context where an adversary might try to create a collision.
Computing Hashes in Code
JavaScript (Web Crypto API)
async function sha256(message) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
const hash = await sha256('Hello, World!');
// "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986d"
// SHA-256 of a file
async function sha256File(file) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
return Array.from(new Uint8Array(hashBuffer))
.map(b => b.toString(16).padStart(2, '0')).join('');
}
Node.js
const crypto = require('crypto');
// SHA-256
const sha256 = crypto.createHash('sha256').update('Hello, World!').digest('hex');
// MD5 (only for non-security use)
const md5 = crypto.createHash('md5').update('Hello, World!').digest('hex');
// HMAC-SHA256 (API signing)
const hmac = crypto.createHmac('sha256', 'secret-key')
.update(JSON.stringify(payload))
.digest('hex');
Python
import hashlib
# SHA-256
sha256 = hashlib.sha256(b'Hello, World!').hexdigest()
print(sha256)
# SHA-256 of a file (streaming for large files)
sha256 = hashlib.sha256()
with open('large-file.bin', 'rb') as f:
for chunk in iter(lambda: f.read(65536), b''):
sha256.update(chunk)
print(sha256.hexdigest())
# HMAC-SHA256
import hmac as hmac_lib
mac = hmac_lib.new(b'secret-key', msg=b'message', digestmod=hashlib.sha256)
print(mac.hexdigest())
What About SHA-1, SHA-512, and SHA-3?
SHA-1 (160-bit) is deprecated for security use since 2017 — practical collisions were demonstrated by Google's SHAttered attack in 2017. Avoid for anything security-related; it remains in Git's object model for legacy reasons but is being phased out.
SHA-512 produces a 512-bit digest and is marginally stronger than SHA-256. It can be faster on 64-bit hardware because it processes data in 64-bit words rather than 32-bit. Use SHA-512 when your threat model requires maximum security margin, or when performance profiling shows it is faster on your specific hardware.
SHA-3 is a completely different algorithm (Keccak sponge construction) standardised by NIST in 2015. It provides an alternative to SHA-2 with a different design, providing defence-in-depth if a weakness were ever found in SHA-2. For most applications SHA-256 is sufficient — choose SHA-3 only if you have a specific requirement for algorithm diversity.
Generate and compare all these hashes instantly using ToolPry's Hash Generator — it computes MD5, SHA-1, SHA-256, and SHA-512 client-side for both text and file inputs.
Frequently Asked Questions
Can SHA-256 be reversed?
Not in practice. SHA-256 is a one-way function — given a hash, there is no algorithm to recover the original input. The only approach is brute force: try every possible input until you find one that produces the same hash. For short inputs like passwords, this is feasible (which is why you should use bcrypt or Argon2 for passwords, not SHA-256 directly). For arbitrary data, it is computationally infeasible.
Is SHA-256 good for password hashing?
SHA-256 alone is not suitable for password hashing — it is too fast. A modern GPU can compute 10 billion SHA-256 hashes per second, making brute-force attacks feasible against SHA-256 password hashes. Use bcrypt, Argon2id, or scrypt instead — these are intentionally slow and memory-hard, designed to make brute-force attacks computationally expensive regardless of hardware improvements. SHA-256 is appropriate for HMAC, file integrity, and data fingerprinting, not for storing passwords.
How do I verify a file checksum on the command line?
## macOS shasum -a 256 filename.zip # SHA-256 md5 filename.zip # MD5 ## Linux sha256sum filename.zip md5sum filename.zip ## Windows (PowerShell) Get-FileHash filename.zip -Algorithm SHA256 Get-FileHash filename.zip -Algorithm MD5