MD5 and SHA-1 still turn up everywhere: next to software downloads, in old configuration files, in database columns named password_md5, and in the output of almost every hash tool, ours included. Both are labelled broken, yet both still produce exactly the same digest for the same input that they always did. So what actually broke, and why does it matter for some jobs and not others?
The short answer is that researchers learned to make two different inputs share a digest on demand. This post walks through how that happened, the real attacks that turned a research result into forged certificates, and what to use instead. If you want the basics of hashing first, what hashing is and how it works covers digests, one-way functions and password storage.
What "broken" means for a hash#
A cryptographic hash is supposed to stand up to three kinds of attack:
- Preimage. Given a digest, find any input that produces it.
- Second preimage. Given a specific input, find a different input with the same digest.
- Collision. Find any two inputs that share a digest, both of them your choice.
Collisions are the easiest of the three to find, because of the birthday paradox. You do not need to hit one particular digest; you only need any two of your attempts to land on the same value. For a hash with an n-bit output that takes roughly 2n/2 attempts instead of 2n. MD5's 128 bits give a brute-force collision cost of about 264 tries, and SHA-1's 160 bits give about 280. Those numbers were the safety margin.
A hash counts as broken when someone finds a shortcut that beats that margin. MD5 and SHA-1 were both broken this way, for collisions specifically. Preimage resistance is a different story. According to RFC 6151, the best known preimage attack on MD5 still needs about 2123 operations, which is far out of reach. Nobody can take the MD5 of your file and conjure a different file that matches it. What an attacker can do is prepare two files in advance that match each other, and that turns out to be enough.
How MD5 fell#
MD5 was designed by Ron Rivest and published as RFC 1321 in April 1992. Cracks showed up early. In 1993 and 1996 researchers found weaknesses in its internal compression function, the building block it applies to each chunk of input. That was not yet a collision in MD5 itself, but it was enough for cryptographers to start recommending alternatives.
The decisive result came in 2004, when Xiaoyun Wang and colleagues published real MD5 collisions: pairs of different messages with identical digests. Improvements came quickly. By 2006 a collision took about a minute on a notebook PC, and in 2007 Marc Stevens reported finding them in ten seconds or less on an ordinary desktop. From then on, producing an MD5 collision was no longer an achievement. It was a script.
Two kinds of collision#
The early collisions had a limit that let some people shrug them off. They were identical-prefix collisions: both messages begin with the same content, then diverge in a block of random-looking bytes that the attack computes. You could not take two meaningful documents of your choosing and make them collide.
A chosen-prefix collision removes that limit. The attacker picks two different starting points, say a harmless certificate and a malicious one, and computes a tail for each so that the two complete messages share a digest. It costs far more, but it is the version that breaks real systems. Almost every signature scheme signs a hash of the document rather than the document itself, because hashes are small. If two documents share a hash, a signature over one is also a valid signature over the other.
From research to forged certificates#
In December 2008 a research team including Alexander Sotirov and Marc Stevens showed exactly that. They obtained an ordinary website certificate from RapidSSL, a certificate authority that still signed with MD5, and used a chosen-prefix collision so that its signature was also valid for a second certificate they had built alongside it. That second certificate was a CA certificate, trusted by common browsers, able to issue certificates for any website at all. The collision search ran on a cluster of more than 200 PlayStation 3 consoles. To keep the result harmless, they backdated it so it had already expired.
Four years later the technique turned up in the wild. The Flame espionage malware, identified in May 2012, carried components signed with a counterfeit Microsoft certificate. Its authors had found a Microsoft Terminal Server Licensing certificate that still used MD5 and could be used for code signing, and used a new variant of the chosen-prefix attack to forge one of their own. Code signed with it appeared to come from Microsoft.
Neither attack needed MD5's preimage resistance to fail. Both only needed someone trusted to keep signing MD5 digests after collisions were known. That is what "broken" means in practice: any signature over an MD5 hash may be a signature an attacker can reuse. RFC 6151 says it plainly: MD5 must not be used for digital signatures. For background on how authorities sign certificates, see how SSL certificates work.
How SHA-1 fell#
SHA-1 was published by NIST in 1995 as part of FIPS 180-1, with a 160-bit digest, and for about a decade it was the default choice. In 2005 Wang's team showed that SHA-1 collisions could be found with far less work than the 280 birthday bound. Nobody could afford to run that attack yet, but the margin was gone, and the push toward SHA-2 began.
The theoretical break became a demonstrated one on 23 February 2017. Researchers from CWI Amsterdam and Google announced SHAttered: two visibly different PDF files with the same SHA-1 digest. It took about nine quintillion SHA-1 computations, which the team put at roughly 6,500 years of CPU time plus 110 years of GPU time. That is expensive, but well within reach of a large company or a government.
SHAttered was an identical-prefix collision. In January 2020, Gaëtan Leurent and Thomas Peyrin published a practical chosen-prefix collision for SHA-1, the kind that forges signatures, and estimated its cost at around $45,000 of rented GPU time. They demonstrated it by building a forged PGP key that could inherit a certification signature made for a different key. GnuPG responded by treating SHA-1 identity signatures created after January 2019 as invalid.
NIST has since set December 31, 2030 as the date to stop using SHA-1 in the last protocols that still specify it, and recommends moving to SHA-2 or SHA-3.
Git is the best-known holdout, because it names every commit and file by its SHA-1. After SHAttered, Git switched in version 2.13 to a hardened SHA-1 implementation that detects that attack. Git can also create repositories that name objects with SHA-256, but its documentation notes there is currently no interoperability between SHA-256 and SHA-1 repositories, which is a large part of why most projects have not moved.
What MD5 and SHA-1 are still fine for#
Broken for collisions does not mean useless. The question to ask is simple: does anyone gain by creating two inputs with the same digest? If not, the collision attacks do not apply.
- Catching accidental corruption. A flipped bit in a download or a backup is random, and random errors do not craft collisions. An MD5 checksum still catches them.
- Deduplication and cache keys on data you control, where no hostile party chooses the inputs.
- HMAC-MD5 and HMAC-SHA1 in existing protocols. HMAC mixes a secret key into the hash, and its security does not rest on collision resistance. RFC 6151 says the known attacks on HMAC-MD5 do not seem to indicate a practical vulnerability when it is used as a message authentication code, while also saying new protocol designs should not use it.
What is not fine: signatures, certificates, verifying a file that someone else could have swapped, and anything where an attacker gets to supply one of the inputs. Password storage is a separate mistake. Any fast hash is wrong for it, broken or not; passwords need a deliberately slow function such as bcrypt, scrypt or Argon2.
What replaced them#
- SHA-2 (SHA-256, SHA-384 and SHA-512) is the default today, and no practical collision attack against it is known. One quirk to remember: SHA-256 and SHA-512 are open to a length-extension attack, so never build a message authentication code as
hash(secret + message). Use HMAC, which is designed around that weakness. - SHA-3, standardised by NIST as FIPS 202 in 2015, is built on a completely different internal design called Keccak, so a future break in SHA-2 is unlikely to carry over. It is not affected by length extension.
- BLAKE2 and BLAKE3 are fast, well-studied hashes that are popular in software, though they are not NIST standards.
For almost every new use, SHA-256 is the right answer. Reach for SHA-3 when a specification calls for it or when you want a design unrelated to SHA-2.
Finding MD5 and SHA-1 in your own setup#
- DNSSEC. Zones signed with algorithm 5 (RSASHA1) or 7 (RSASHA1-NSEC3-SHA1) still depend on SHA-1. Our DNSSEC validator lists the algorithms a zone uses and flags those two as weak; DNSSEC explained covers what a key rollover involves.
- Certificates. Open your site's certificate in the browser's certificate viewer and check the signature algorithm, which should name SHA-256 or stronger. The SSL Inspector reports a certificate's SHA-256 fingerprint, which is the reliable way to tell two certificates apart.
- Code and configuration. Search for
md5andsha1in anything that signs, authenticates, issues tokens or verifies downloads, and judge each use with the question above. - Checksums you publish. Offer SHA-256 alongside or instead of MD5, so users can verify against something an attacker cannot collide.
You can see all of this side by side in our hash generator. Paste any text and it computes MD5, SHA-1, SHA-256, SHA-384 and SHA-512 in your browser, with the two broken algorithms labelled. The digests look equally random. What changed over the past twenty years is not the output, but what an attacker can do to produce it.
Compare hash algorithms
Compute MD5, SHA-1, SHA-256, SHA-384 and SHA-512 for any text, entirely in your browser. Nothing you type is sent to a server.
Open the Hash Generator →