MD5 vs SHA-256: when each one is fine

Somewhere right now, a developer is about to hash a password with MD5 because a 2011 tutorial said so. Somewhere else, a code reviewer is rejecting a perfectly good file checksum because "MD5 is broken." They're both wrong — in different directions.

MD5 vs SHA-256 isn't a "which is better" question. It's a "what are you defending against" question. Answer that and the choice makes itself. Here's the whole argument, in a form you can defend in code review.

In this post
  • The one-sentence answer — up front, before the theory
  • What "broken" actually means (it's two different things)
  • Where MD5 is still fine, and where it's a liability
  • The password trap: why SHA-256 is also wrong there
  • A decision table you can screenshot

The one-sentence answer

Let's put the answer first, because you came here for it:

If you're detecting accidents — a corrupted download, bit rot in a backup — MD5 is still fine. If you're defending against a person — signatures, certificates, anything an adversary can touch — use SHA-256 or better.

That's it. The rest of this post is the reasoning, so the next time someone says "MD5 is broken" (true) or "MD5 is fine" (also true), you'll know which one they mean — and why they're both right.

Same job, different eras

Both are cryptographic hash functions: they take any input — a password, a novel, a 40 GB disk image — and produce a fixed-length fingerprint.

digests.txt — the empty string, hashed both ways
md5("")     = d41d8cd98f00b204e9800998ecf8427e
              └─ 32 hex chars · 128 bits

sha256("")  = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
              └─ 64 hex chars · 256 bits

Three properties make them useful:

  • Deterministic — same input, same digest, forever, on every machine.
  • One-way — you can't reverse a digest back into the input.
  • Avalanche — flip one bit of the input and the entire digest changes. The classic test vector "The quick brown fox jumps over the lazy dog" hashes to 9e107d9d… under MD5; change the last word to "cog" and the digest is unrecognizable.

MD5 is the elder — Ronald Rivest, 1992, RFC 1321, 128-bit output. SHA-256 is the flagship of the SHA-2 family, designed by the NSA and published by NIST, 256-bit output. Both were built to be collision-resistant. One of them aged badly.

What "broken" actually means

This is the section that makes the whole question make sense. "Broken" in cryptography isn't one thing — it's two, and the difference is everything.

A collision attack finds two different inputs that produce the same digest. The attacker controls both inputs.

A preimage attack starts from a digest and works backward to find the input. The attacker controls nothing — they're reversing.

MD5's collision resistance is gone. Practical collisions were demonstrated in 2004; by 2020 a chosen-prefix collision — the kind where you can make two documents that look different but hash the same — cost a few thousand dollars in cloud compute. In 2012 the Flame malware used an MD5 collision to forge a Microsoft code-signing certificate. That's not theoretical.

MD5's preimage resistance is weakened but not practically broken. You still can't take an MD5 digest and reverse it.

Why does the distinction matter? Because it tells you who your enemy is:

The adversary test

Ask one question: is a person actively trying to fool me? If the answer is no — you're fighting entropy — MD5 is fine. If the answer is yes, SHA-256 is the floor.

When you checksum a download, your enemy is entropy — a flaky network, a dying disk. Entropy doesn't craft collisions. MD5 catches accidental corruption just as well as SHA-256.

When you sign a document, your enemy is a person who will happily spend a few thousand dollars to forge your signature. Against a person, MD5 is a screen door.

Don't fall back to SHA-1

SHA-1 got its practical collision in 2017 (SHAttered) and has been deprecated for signing ever since. If you're tempted to "just use SHA-1" as a middle ground, don't. SHA-256 is the floor, not SHA-1.

Where MD5 is still fine

So where does MD5 still earn its keep? Anywhere the threat is accidents, not intent:

  • Download and backup integrity. You want to know the file arrived intact, not that it's unforgeable. MD5 does that.
  • Deduplication and cache keys. Two files colliding by chance means a cache miss, not a breach — and the odds are astronomically low.
  • ETags and content fingerprints. A fingerprint for looking things up, not for proving anything.
  • Legacy tooling. Some older package managers and backup tools only speak MD5. Fine — you're still just detecting corruption.

The pattern: in every one of these, nobody wins anything by forging a hash. There's no adversary, so the thing MD5 is bad at never comes up.

Where MD5 is a liability

And here's where it has to go:

  • Digital signatures. A signature is only as strong as the hash underneath it. If an attacker can craft two documents with the same MD5 digest, they get your signature on the innocent one and attach it to the malicious one.
  • Certificates. This is exactly how Flame forged a Microsoft cert. Certificate authorities stopped issuing MD5-signed certificates years ago for precisely this reason.
  • Anything an adversary chooses the input to. If someone else picks the data and you hash it, assume they're trying to collide it.

The password trap — SHA-256 is wrong too

Now the trap that catches even people who understood all of the above:

If you're storing passwords, SHA-256 is also wrong.

This surprises people. SHA-256 is secure, so why not hash passwords with it? Because "secure" and "appropriate" are different properties. General-purpose hashes are designed to be fast — modern hardware computes SHA-256 at billions of attempts per second. That speed is a feature for checksumming a disk and a catastrophe for password storage, because it's exactly what a brute-force attacker wants.

Passwords get a password hash

bcrypt, scrypt, or Argon2id — slow, salted, and built for the job. Never a general-purpose hash, no matter how secure it is. Speed is the enemy here, and SHA-256 is very, very fast.

So the honest answer to "MD5 or SHA-256 for passwords?" is neither. MD5 is broken, SHA-256 is too fast, and the right tools have been free for twenty years.

What about speed?

"But MD5 is faster" used to be a real argument. It's mostly not anymore.

In plain software, MD5 runs about 1.5–2× faster than SHA-256. But nearly every CPU made in the last decade has dedicated SHA instructions (Intel SHA-NI, ARM's crypto extensions) that accelerate SHA-256 by an order of magnitude — on those machines SHA-256 is often faster than MD5.

For checksumming even a large file, the difference is seconds. It was never worth trading signature security for — and on modern hardware the trade doesn't even exist.

The decision table

The whole post on one card:

decision-table.txt
job                                          verdict
───────────────────────────────────────────────────────────
download integrity (no adversary)            MD5 or SHA-256 — either
backups · bit-rot detection                  MD5 or SHA-256 — either
dedup · cache keys · ETags                   MD5 fine
digital signatures                           SHA-256
TLS · code-signing certificates              SHA-256
message authentication                       HMAC-SHA256
password storage                             NEITHER → bcrypt / Argon2id

That HMAC-SHA256 line is doing real work — it's the "HS256" in every JWT you've ever decoded. If that connection is new to you, the JWT decoding post walks through what the algorithm header actually means.

Screenshot the table. Tape it to the monitor. Bring it to code review.

Try it yourself

The hash generator computes MD5, SHA-1, SHA-256, SHA-512 and SHA-3 side by side — paste some text or drop a file and watch all five digests appear as you type.

Notice the honest badges: MD5 is labeled "broken" and SHA-1 "weak," right in the output, so the tool itself reminds you what each one is good for. It's the decision table, running in your browser.

Wrap-up

MD5 isn't broken for everything — just for the thing you're probably using it for. Accidents: MD5 is fine. Adversaries: SHA-256. Passwords: neither — bcrypt or Argon2id.

Next up: 401 vs 403 — and the gateway trio, for everyone who's ever stared at a red status code and wondered whose fault it is. (Spoiler: it's usually the proxy.)