Cryptography / Failure Analysis

Hash Collisions & Length-Extension Attacks

Evaluating cryptographic hash integrity requires distinguishing between theoretical weakness and practical cryptanalytic failure. This page provides executable cryptanalytic proofs: verifying real MD5 and SHA-1 collision pairs where distinct inputs yield identical digests, and executing a complete JavaScript length-extension attack that forges valid authentication tags against naive hash constructions.

1. MD5 Hash Collisions: Two Distinct Files, Identical Digest

A hash collision occurs when two distinct inputs x ≠ x’ yield identical digests H(x) = H(x’).

The two GIF files below (from security researcher Ange Albertini’s corkami collision collection) contain different binary image data but produce the identical MD5 digest:

Green circle GIF image representing MD5 collision file 1
md5-collision-1.gif (10,386 bytes)
Red X GIF image representing MD5 collision file 2
md5-collision-2.gif (10,386 bytes)

Client-Side Executable MD5 Collision Verification

Interactive Browser Playground

MD5 Cryptanalytic Collision Proof

Interactively compute MD5 digests and perform binary byte-by-byte comparison directly in your browser (Zero server calls / Executed locally via JavaScript).

If an integrity check accepts md5-collision-1.gif and records only its MD5 digest, md5-collision-2.gif can replace it without changing that digest because the two files were deliberately constructed as a collision pair. The required attacker state matters: this demonstrates substitution when the attacker can prepare or influence both candidate inputs, not arbitrary replacement of a fixed, pre-existing file. MD5 must not protect adversary-influenced integrity or authenticity workflows, but collision resistance and second-preimage resistance remain different search problems.

2. SHA-1 Collisions: The SHAttered Attack Strategy

In 2017, Google and CWI Amsterdam published the SHAttered attack, demonstrating the first practical SHA-1 collision using two distinct PDF documents sharing an identical SHA-1 hash. The compact 2,102-byte pair used in the interactive demo below is a separate reproduction, sourced from the same corkami collision collection — it demonstrates the same underlying collision property (two distinct files, one SHA-1 digest) but is not byte-identical to the original files Google and CWI published.

sha1-collision-1.pdf (2,102 bytes)
sha1-collision-2.pdf (2,102 bytes)

Client-Side Executable SHA-1 Collision Verification

Interactive Browser Playground

SHA-1 Collision Pair Proof

Interactively compute SHA-1 digests over a bundled SHA-1 collision pair (two distinct PDFs producing an identical digest, in the spirit of the SHAttered technique — not the exact files from the original published SHAttered pair) and verify binary divergence live via Web Crypto API.

3. Length-Extension Attack: Forging Naive Hash MACs

Naive MAC constructions built on Merkle–Damgård hash functions (MD5, SHA-1, SHA-256) are vulnerable to length-extension attacks:

MAC = H(Secret || Message)

Because a Merkle–Damgård hash output exposes the internal compression state H, an adversary who knows the message and the length of the secret — whether from prior knowledge or simply by guessing it (secret lengths are typically drawn from a small, brute-forceable range, e.g. common key sizes) — can resume hashing from that state to append malicious payload bytes Appended_Data without knowing Secret itself.

Client-Side Executable Length-Extension Forgery

Interactive Browser Playground

MD5 Length-Extension Attack Simulator

Interactively forge valid authentication MAC tags against a naive MD5(Secret || Message) construction by restoring internal compression state directly in your browser.

Defensive Countermeasure: Use a Proper Keyed MAC, Not a Naive Keyed Hash

Deploying HMAC-SHA256 (FIPS 198-1) neutralizes length-extension attacks by executing a nested double-hash algorithm:

HMAC(K, M) = H((K₀ ⊕ opad) || H((K₀ ⊕ ipad) || M))

Here K₀ is K normalized to the hash function’s block size — hashed down if longer, zero-padded if shorter (see RFC 2104 §2 and the Hash Functions & MACs page).

Modern hash constructions also resist length extension at the algorithm level, for two distinct structural reasons. Sponge-based functions (SHA-3 / FIPS 202) squeeze outputs through an internal capacity state that the attacker cannot observe or extend. BLAKE3 (BLAKE3 Specification) is not sponge-based — it is a Merkle-tree hash built over a compression function, and it resists length extension by construction because each chunk/node is processed with an explicit finalization flag that only the root node receives, so an attacker cannot extend a digest into a valid continuation of the tree.

That structural resistance describes the hash function, not a ready-made MAC — plain unkeyed SHA3-256(message) or unqualified BLAKE3(message) still authenticate nothing, since anyone can compute either without a secret. For actual message authentication, pair the key with the hash through a construction designed for it: KMAC128 / KMAC256 (SP 800-185) for the SHA-3 family, HMAC for Merkle–Damgård hashes (SHA-2), or BLAKE3’s own built-in keyed mode (keyed_hash) — not a hand-rolled H(key || message) or H(key || message) substitute using SHA-3 or BLAKE3 in place of H.

What I need to remember

MD5 and SHA-1 have broken collision resistance and are not acceptable for generating new digital signatures under NIST transition guidance. Prefix-MAC constructions such as H(key || message) are length-extension vulnerable when H is a Merkle–Damgård hash such as SHA-256; even with SHA-3 or BLAKE3, use a standard keyed construction—HMAC, KMAC, or BLAKE3 keyed mode—instead of inventing a MAC.

Primary references