A cryptographic hash maps input of any length onto a fixed number of bits. Three properties are wanted from one: you cannot recover the input from the output, you cannot find an input producing a given output, and you cannot find two inputs producing the same output.
That third property — collision resistance — is the one MD5 and SHA-1 have lost.
What "broken" actually means
MD5 collisions can be produced in seconds on a laptop. Chosen-prefix collisions, where an attacker controls meaningful parts of both inputs, are also practical — they were used in the Flame malware to forge a Microsoft code-signing certificate.
SHA-1 followed in 2017, when Google and CWI produced two different PDFs with the same SHA-1 digest. By 2020 a chosen-prefix attack was demonstrated for roughly $45,000 of compute — cheap enough for anyone who wants it.
Where MD5 is still fine
Collision resistance only matters when an adversary is involved. Detecting accidental corruption — a truncated download, a flipped bit, a partially written file — needs no such property, and MD5 does it as well as anything.
That is why package registries still publish MD5 checksums, and why it turns up in cache keys, deduplication and ETags. If the question is "did this arrive intact", MD5 answers it. If the question is "is this the file I was promised, and might someone be lying to me", it does not.
What to use instead
- SHA-256 — the sensible default. No practical attacks, hardware-accelerated on modern CPUs, universally available.
- SHA-512 — sometimes faster than SHA-256 on 64-bit hardware. Not meaningfully more secure for most purposes.
- BLAKE3 — considerably faster than either, well regarded, less universally available.
- SHA-3 — a structurally different design kept as insurance against a break in the SHA-2 family. Rarely necessary today.
Never for passwords
This is the most consequential misuse, and switching from MD5 to SHA-256 does not fix it.
These functions are designed to be fast. That is a virtue for checksumming a large file and a catastrophe for password storage: a commodity GPU tries billions of SHA-256 candidates per second against a stolen table. A fast hash means a fast attack.
Password hashing needs functions that are deliberately slow and memory-hard, with a per-password salt built in:
- Argon2id — the current recommendation, and the Password Hashing Competition winner.
- scrypt — memory-hard, well established.
- bcrypt — older and not memory-hard, but battle-tested and still acceptable. Note its 72-byte input limit.
Verifying integrity across systems
Two implementations of the same algorithm produce identical output, so a digest that disagrees means the input disagrees. In practice there are two usual reasons.
The first is a trailing newline. echo abc emits four bytes, not three, so echo abc | md5sum hashes abc\n and produces a completely different digest:
echo abc | md5sum
# 0bee89b07a248e27c83fc3d5951213c1
printf %s abc | md5sum
# 900150983cd24fb0d6963f7d28e17f72The second is character encoding. Hashes cover bytes, so é as UTF-8 (two bytes) and as Latin-1 (one byte) are different inputs. Both systems must encode the same way before hashing, and UTF-8 is the answer.
Hashing is not encryption
There is no key and no way back. Sites claiming to "decrypt MD5" are looking the digest up in a table of previously hashed strings, which works for common passwords and dictionary words and for nothing else. That such tables work at all is an argument for salting, not evidence that the function is reversible.
HMAC, and why plain hashing is not authentication
A hash proves nothing about who produced it — anyone can hash anything. To prove a message came from someone holding a shared secret, you need a MAC, and the standard construction is HMAC.
The naive alternative — hash(secret + message) — is broken against any Merkle–Damgård hash, which includes MD5, SHA-1 and SHA-256. A length extension attack lets someone who has the digest append data and produce a valid digest for the longer message, without ever knowing the secret. HMAC's nested construction exists specifically to prevent that.
// Broken — vulnerable to length extension
sha256(secret + message)
// Correct
hmacSha256(secret, message)Digest length and truncation
MD5 produces 128 bits, SHA-1 160 and SHA-256 256. Collision resistance is roughly half the digest length because of the birthday bound, so SHA-256 offers about 128 bits of it — comfortably beyond reach.
Truncating a digest is acceptable and common — Git used 7-character abbreviations of a SHA-1 for years — but every bit removed halves the collision resistance, and a short prefix collides sooner than intuition suggests. For a cache key that is fine. For anything where a collision would be exploited, keep the full digest.
Hash GeneratorMD5, SHA-1 and SHA-256 for any text, computed in your browser and checked against the published specification vectors.