Skip to content

Retired hashes

SHA-1, MD5, MD4 and RIPEMD-160: what broke each one, and where it still turns up. Check old data with them if you have to, but never sign with them.

Status and standards: see Hash functions in the main table.

A hash retires when collisions get cheap: two different inputs with the same digest, so a signature on one also covers the other. Preimages (going from a digest back to an input) hold out much longer, which is why HMAC built on these hashes lasted. For new work use SHA-256, SHA-3 or BLAKE2.

SHA-1

What it was. The NSA's 160-bit hash, published by NIST as FIPS 180-1 in 1995 and copied into RFC 3174. It is SHA-0 (FIPS 180, 1993) with one extra bit rotation in its message schedule. For about twenty years it was the usual hash inside certificate and code signatures.

What broke it. A 160-bit hash should take about 2⁸⁰ work to collide. Wang, Yin and Yu (CRYPTO 2005) found a way in about 2⁶⁹. In February 2017 CWI and Google published SHAttered, the first real collision: two different PDF files with the same SHA-1, for about 2⁶³ SHA-1 computations (6,500 CPU years and 100 GPU years). That is the ~63 bits in the main table.

Leurent and Peyrin's "SHA-1 is a Shambles" (USENIX Security 2020) did a chosen-prefix collision, where the attacker picks two different starting texts and then finds endings that make them collide. It also cost about 2⁶³, run on 900 rented GPUs for two months. They built two PGP keys with different user IDs whose certification signatures collide, so a signature made for one key also verifies on the other. GnuPG 2.2.18 (November 2019) treats SHA-1 identity signatures made after January 19, 2019 as invalid.

In December 2022 NIST set December 31, 2030 as the end of its move away from SHA-1, with a FIPS 180-5 that drops it.

Where you still see it.

  • Git. Object names are SHA-1 by default. Since 2.13 (2017) Git uses Marc Stevens and Dan Shumow's SHA-1 that detects inputs built by the known collision attacks. SHA-256 repositories arrived in 2.29 (2020), and Git 3.0 will make SHA-256 the default for new repositories. It has no release date yet.
  • Old certificates. Browsers stopped trusting SHA-1 TLS certificates in early 2017, but anything signed before then may still carry a SHA-1 signature. OpenPGP (RFC 9580, 2024) forbids making new ones.
  • HMAC-SHA-1, as in TOTP codes. That is still fine: RFC 6194 found no way to carry the collision attacks over to HMAC. See HMAC.

MD5

What it was. Ron Rivest's 128-bit hash, RFC 1321 (1992), a strengthened MD4. Through the 1990s it was the default for certificates, file checksums, $1$ passwords, and HMAC-MD5 in TLS and IPsec.

What broke it. In August 2004 Xiaoyun Wang, Dengguo Feng, Xuejia Lai and Hongbo Yu posted real collisions for MD5, MD4, HAVAL-128 and the original RIPEMD. Chosen-prefix collisions followed (Stevens, Lenstra and de Weger, EUROCRYPT 2007). In December 2008 a team used one, and about 200 PlayStation 3s, to turn an ordinary certificate signed with MD5 by a commercial CA into a rogue CA certificate that browsers trusted.

Then came Flame, espionage malware found in May 2012. It carried a forged certificate that chained up to Microsoft's root, made with a new variant of the chosen-prefix attack (Stevens, CRYPTO 2013). Microsoft revoked the CAs involved in Security Advisory 2718704. RFC 6151 (2011) had already said MD5 is no longer acceptable where collision resistance is needed.

Where you still see it.

  • Checksums, caches and deduplication where nobody is attacking. Python 3.9+ lets you say so: hashlib.md5(data, usedforsecurity=False) works even on builds that block MD5 for security use.
  • RADIUS, which authenticates server replies with an ad hoc MD5 construction. Blast-RADIUS (USENIX Security 2024) used a chosen-prefix collision to forge an accept for a failed login.
  • $1$ password hashes: see MD5-crypt.
  • HMAC-MD5 in old protocols. RFC 6151 says removing it is not urgent, but new designs should leave it out.

These two 128-byte inputs differ in six bits and have the same MD5. They are the collision from Wang and Yu's EUROCRYPT 2005 paper.

import hashlib

a = bytes.fromhex(
    "d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f89"
    "55ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5b"
    "d8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0"
    "e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70")
b = bytearray(a)
for i in (19, 45, 59, 83, 109, 123):    # flip the top bit of six bytes
    b[i] ^= 0x80

print(hashlib.md5(a).hexdigest())
print(hashlib.md5(b).hexdigest())       # the same: 79054025255fb1a26e4bc422aef54eb4
print(hashlib.sha256(a).digest() == hashlib.sha256(b).digest())   # False

MD4

What it was. Rivest's 1990 hash (RFC 1186, then RFC 1320 in 1992): 128 bits, three rounds, built for speed on 32-bit machines. MD5 and SHA-1 follow its design.

What broke it. Hans Dobbertin found collisions in 1996 at about 2²⁰ MD4 computations, and Wang et al. (EUROCRYPT 2005) cut that to about 2⁸. Preimages fell too: Leurent reached 2¹⁰⁰ in 2008, and later work about 2⁷⁸. RFC 6150 (2011) moved MD4 to Historic.

Where you still see it. Windows passwords. The NT hash behind NTLM is MD4 of the UTF-16 password, with no salt and a single pass (MS-NLMP, Section 3.3.1). The RC4-HMAC Kerberos key (RFC 4757) is the same value, and MS-CHAP uses it too. rsync used MD4 until 3.0.0 (2008).

import hashlib

try:
    print(hashlib.new("md4", "password".encode("utf-16-le")).hexdigest())
except ValueError:                      # OpenSSL 3 keeps MD4 in its legacy provider
    print("no MD4 in this build")
# 8846f7eaee8fb117ad06bdd830b7586c: the NT hash of "password"

RIPEMD-160

What it is. Hans Dobbertin, Antoon Bosselaers and Bart Preneel's 160-bit hash (FSE 1996), a stronger redo of the 1992 RIPEMD from the European RIPE project. It runs two different MD4-style lines of 80 steps side by side and combines them at the end. It is in ISO/IEC 10118-3.

Why it's legacy. Nothing has broken it. Collision attacks reach 40 of its 80 steps (Li, Liu and Wang, 2023), and a 2026 preprint claims 42. The limit is the size: a 160-bit digest gives at most 80-bit collision resistance. Bitcoin's Taproot spec calls that low, and a risk whenever an output holds data from more than one party.

Where you still see it. Bitcoin. HASH160, RIPEMD-160 of SHA-256, makes the 20-byte hashes in P2PKH and P2SH addresses and P2WPKH outputs. Taproot outputs (BIP 341) hold a 32-byte key instead. In OpenPGP, RFC 9580 forbids new signatures with it, as with MD5 and SHA-1.

See also

References

Weaker sources: Peter Selinger's MD5 collision page for the colliding bytes and their credit to Wang and Yu; Mozilla, "The end of SHA-1 on the Public Web" (2017) for the browser date.