X Xerobit

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,...

Mian Ali Khalid · · 4 min read
Use the tool
Hash Generator
Generate MD5, SHA-1, SHA-256, and SHA-512 hashes client-side.
Open Hash Generator →

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

PropertyMD5SHA-256
Output size128 bits (32 hex chars)256 bits (64 hex chars)
SpeedVery 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 posts

Related tool

Hash Generator

Generate MD5, SHA-1, SHA-256, and SHA-512 hashes client-side.

Written by Mian Ali Khalid. Part of the Encoding & Crypto pillar.