MD5 vs SHA-256 for Checksums: Which Should You Actually Use?
"MD5 is broken, never use it" is the advice you'll hear, and it's half right — which makes it dangerous. Whether MD5 is fine or reckless for a checksum depends entirely on one question you have to answer first: is anyone trying to fool you? This guide separates the two jobs a checksum does, shows which hash each one needs, and explains why reaching for a stronger hash is often the wrong fix.
You’re on a download page that lists an MD5. Or you’re deciding what to publish next to your own release. Either way, the same question comes up: is MD5 still OK, or do you need SHA-256? Search for it and you get one loud answer — “MD5 is broken, never use it.” That advice is half right. The wrong half is what gets people into trouble. Follow it blindly and one of two things happens. You waste effort where MD5 was perfectly fine. Or, worse, you switch to SHA-256, feel safe, and miss that the thing you actually needed was never a stronger hash at all.
Here’s the honest version. “Which hash?” is not a question about which algorithm is better. It’s a question about who you’re defending against. People reach for a published hash to pursue two very different goals — and MD5 is completely fine for one of them and useless for the other. Until you know which goal you’re after, no answer is correct.
One scope note up front: this article is about file checksums — confirming that data hasn’t changed. Storing passwords is a different problem with a different answer. For that, use a purpose-built password hash like Argon2id or bcrypt — never MD5, and not plain SHA-256 either.
The one idea: two jobs, one question
You compare a published hash to reach one of two goals. They are not the same goal, and a bare hash serves them very differently.
- Catch accidental corruption. A dropped connection truncated the file. A flaky disk flipped a bit. A mirror served a stale copy. Nobody designed the difference — it’s random damage, and you trust the source that gave you the reference value. This is integrity against accident, and a bare hash handles it on its own.
- Resist deliberate tampering. Someone wants you to accept a malicious file, and they are actively working to make its hash match the one you expect. This is authenticity, and here a bare hash is only part of the answer: it’s a necessary layer, not the whole defense. Finishing this job takes a signature (or an HMAC) on top.
The whole MD5-versus-SHA-256 decision turns on one question: is there an adversary? For goal 1, there isn’t — and MD5 does the job. For goal 2, there is — MD5 fails outright, and SHA-256 becomes the minimum at the hash layer. But keep goal 2’s catch in view: the hash is one layer of that defense, never all of it. Get the threat model right and the algorithm follows. Get it wrong and you either gold-plate a problem that didn’t need it, or you trust a hash to do something no bare hash can do.
What “MD5 is broken” actually means
The break has a precise name, and the precision is the whole point. A cryptographic hash is meant to have a few properties. MD5 has lost exactly one of them, and kept the others.
- Collision resistance — nobody can find two different inputs with the same hash. This is what MD5 lost. Off-the-shelf tools produce MD5 collisions on a laptop today. (Producing a collision whose two files also have specific, useful contents — a chosen-prefix collision — is much more work, and how hard depends on the attack.) SHA-1 fell too: the 2017 SHAttered attack produced a real SHA-1 collision.
- Preimage and second-preimage resistance — given a hash, nobody can build an input that produces it (preimage); and given one file, nobody can find a different file with the same hash (second-preimage). MD5 still holds both, in any practical sense. There is no feasible attack that takes a specific, existing MD5 value, or a given file, and produces a match.
That difference is exactly why MD5 still works for job 1. Accidental corruption is not a crafted collision. A truncated download or a flipped bit is one file that changed — not two files built to match. And MD5’s output still changes reliably when the input changes. Checking a download against a hash a trusted publisher already computed is a substitution question — it leans on preimage and second-preimage resistance, which MD5 hasn’t lost. But that does not make MD5 safe for authentication, because its collision resistance is broken, and that is the door real attacks walk through.
So what does the collision break actually let an attacker do? It needs two files, both under their control. Picture a service that will sign any file you submit. The attacker crafts a harmless-looking file and an evil twin that share one MD5. They submit the harmless one, get it signed, then ship the twin — and the signature still checks out, because the hash matches. This isn’t theory. The Flame malware used an MD5 collision to forge a Microsoft code-signing certificate. Researchers built rogue certificate-authority certs the same way. The pattern never changes: the attacker has to influence the “good” file, not just the bad one. The moment your pipeline lets them, a collision-broken hash is an open door — and closing it costs nothing, so there’s no reason to leave it open.
A quick map of the field
Before the details, one table to keep the names straight:
| Algorithm | Output | Collision resistance | Reach for it when |
|---|---|---|---|
| CRC32 | 32-bit | None (not its job) | Pure speed; catching accidental errors; no security at all |
| MD5 | 128-bit | Broken | Legacy non-adversarial checks, dedup, cache keys |
| SHA-1 | 160-bit | Broken | Nothing new; only old-system compatibility |
| SHA-256 | 256-bit | No practical attack known | The safe hash default for public or signed workflows |
| SHA-512 | 512-bit | No practical attack known | Same safety as SHA-256, sometimes faster on 64-bit |
| BLAKE3 | 256-bit+ | No practical attack known | New systems that want top speed |
The rest of this guide is really about reading that third and fourth column correctly.
When MD5 is genuinely fine
Set fashion aside. MD5 is a reasonable pick when you have good reason to believe there’s no adversary, and you either value speed or already have MD5 values on hand.
- Catching accidental corruption from a source you trust. You copy a file across a flaky network, or pull it from your own internal mirror, and want to confirm it arrived intact.
- Deduplication and cache keys. You hash blobs to spot “these two are identical,” or to key a cache. Nobody inside that system is deliberately trying to force a collision.
- Consuming an MD5 a trusted publisher gave you. A project you trust, over a channel you trust, only publishes an MD5. Checking it still catches the accidental damage it was meant to catch. It’s not worthless. It’s just not protection against a tampered file.
One caveat, stated plainly. “Fine” here means not wrong — not recommended for new work. And if all you need is to catch accidental corruption fast, a non-cryptographic checksum like CRC32 or xxHash is often the better tool. It’s built for that one job, it’s faster, and it carries no “security” label for someone to misread later.
When you must use SHA-256 (or better)
The rule for anything an adversary could touch is simple: SHA-256, at minimum, at the hash layer. You meet it more often than you think — it’s the hash under most of the systems you already use.
- Public downloads that could be tampered with. Anything a user fetches over the open internet, where a mirror or a man-in-the-middle could swap the file.
- Software supply chains. A Docker image is pinned by its SHA-256 digest (
sha256:…). An npm package records a Subresource Integrity hash, usually SHA-512 in base64. These exist so a substituted artifact fails the check. - Security-adjacent identifiers. TLS certificate fingerprints, signed content, and hash-derived identifiers that must resist a deliberate collision. (Secret tokens are a different matter — those should come from a cryptographically secure random generator, not from picking a hash algorithm.)
- Content addressing, where a collision is a security bug and not just a nuisance. This is why Git is moving off SHA-1: two different commits with the same ID would break the model’s core assumption.
For new work, default to SHA-256 even when today’s use looks non-adversarial. Threat models change over time. An internal tool gets exposed. A “trusted” pipeline gains an untrusted input. And on a processor with SHA instructions, SHA-256 costs almost nothing over MD5. In a greenfield project, there is almost never a reason to reach for MD5.
”But isn’t a longer hash safer?” — bits and speed
Two instincts push people toward SHA-512, or toward “the strongest one.” Both are worth correcting.
First, longer is not automatically safer. The problem with MD5 and SHA-1 is a structural break in collision resistance — not too few bits. More output bits do raise the cost of a generic, brute-force collision search, but SHA-256 already has an enormous margin there; you will not run out of it. What extra length can’t do is fix a structural weakness, and it can’t add authenticity. SHA-512 doesn’t repair anything SHA-256 lacks, because SHA-256 isn’t missing it.
Second, the strongest hash is not the slowest, and MD5 is no longer the fastest. Modern CPUs have hash instructions built in — SHA-NI on x86, crypto extensions on ARM. With them, SHA-256 runs at gigabytes per second, often matching or beating MD5. BLAKE3 goes further, using SIMD and multiple cores, and is usually the fastest cryptographic hash you can pick. If you truly need raw throughput and no security at all, a CRC32 — especially on platforms with a hardware CRC instruction — beats all of them. “MD5 is faster” was a real argument a decade ago. On today’s hardware it rarely holds.
So pick SHA-512 for a real reason — a longer digest, or a speed edge on a 64-bit server. Not for a security bump you won’t get.
The trap: a stronger hash is not tamper-proofing
Swapping MD5 for SHA-256 quietly encourages one mistake, so let’s state it flatly. Upgrading the algorithm does not, by itself, protect against tampering. These are two different axes, and confusing them is what turns “we use SHA-256” into a false sense of security.
- MD5 → SHA-256 raises collision resistance. It matters only when an attacker crafts inputs.
- Bare hash → signature adds authenticity. It matters whenever an attacker can change both the file and its published hash.
Say a download and its checksum live on the same page. An attacker controls that page. They replace the file and rewrite the hash to match. It makes no difference whether that hash is MD5 or SHA-512. The check passes. You’re fooled. The fix is not a longer digest. For public distribution, it’s a signature — GPG, or Ed25519/minisign: the publisher signs with a private key, you verify with their widely-published public key, and now the attacker can’t forge the reference without it. An HMAC solves the same problem only in a closed setting where both sides already share a secret key — a webhook, or two internal services — so it’s not an option for a public download. That’s exactly why Linux distributions ship a signed checksums file, not just a stronger hash. (When two values simply don’t line up, that’s a different question — walked through in why doesn’t my checksum match.)
The decision, in one pass
Answer these in order and the algorithm falls out.
- Could an adversary craft the input or swap the file? If yes → SHA-256 or better at the hash layer. No exceptions. MD5 and SHA-1 are off the table.
- Is this a public download, or anything security-adjacent? Treat that as a “yes” to question 1. Publish SHA-256, and sign it. The signature is what defeats a tampered reference; the hash length isn’t.
- Purely accidental-corruption detection, no adversary, and you control or trust the source? Then MD5 is fine. Though a non-cryptographic checksum (CRC32, xxHash) usually fits better and runs faster — and for anything new, SHA-256 is the safe default anyway.
- Verifying a file someone else published? Use whatever algorithm they published. If that’s only MD5, and you trust the source and the channel, it still confirms accidental integrity. But prefer publishers who give you SHA-256 plus a signature.
To compute a hash yourself, the command line is enough. On Linux: md5sum file, sha256sum file. On macOS the tools are named differently: md5 -r file, shasum -a 256 file. On Windows PowerShell: Get-FileHash file -Algorithm SHA256. For a quick check in the browser, drop a file — or paste text — into the hash generator. It computes one algorithm at a time, so pick the one your reference names (MD5, SHA-256, SHA-512, SHA-3, BLAKE2b/BLAKE2s/BLAKE3, and more), then switch algorithms to compare. Note that it outputs hexadecimal, not the base64 that SRI uses — so for an integrity="sha256-…" value you’ll convert one side.
Underneath all four questions is the single idea from the top. The choice is a threat-model decision, not a ranking. MD5 isn’t universally “broken,” and SHA-256 isn’t universally “the answer.” MD5 is broken for exactly one thing — resisting a deliberate collision — and that one thing is precisely what a security checksum needs, and what an accidental-corruption check does not. Decide whether there’s an adversary first. And when there is, remember: the hash is the baseline, never the whole defense.