☕ Buy me a coffee — $3

MD5 (Message Digest 5)

Overview

MD5 (Message Digest 5) is a widely-used cryptographic hash function that produces a 128-bit hash value. Designed by Ronald Rivest in 1991, MD5 was commonly used for data integrity verification and password hashing.

However, MD5 is now considered cryptographically broken and unsuitable for security purposes. Collision attacks can be performed in seconds, making it vulnerable to various security threats. MD5 should not be used for any security-critical applications.

MD5 is worth studying not because you should use it, you should not, but because its history is one of the clearest illustrations in cryptography of how "cryptographically broken" happens, and how long the migration away from a broken primitive takes even after the mathematics is settled. MD5 was proposed in 1992 and considered secure. The first theoretical weakness was reported in 1996. The first full collision was published in 2004. A real attack on a public certificate authority was demonstrated in 2008. And yet MD5 is still, in 2026, embedded in production systems: legacy Docker image manifests, older torrent files, some file synchronisation tools, git-lfs metadata, ETags in many HTTP servers. That gap between "known broken" and "gone" is the story worth taking away.

History and the Migration Away From MD5

Ronald Rivest, the R of RSA, designed MD5 in 1991 and published it as RFC 1321 in April 1992. It was a refinement of the earlier MD4, itself designed by Rivest in 1990, which had already been shown to have theoretical weaknesses. MD5's design goals were speed (crucial for the low-powered hardware of the era), simplicity, and resistance to the specific attacks that had broken MD4. It succeeded on the first two counts and was thought to have succeeded on the third.

The first serious cryptanalytic result appeared in 1996: Hans Dobbertin found a collision in MD5's compression function, but not in the full hash. This was a warning shot, the compression function is the primitive that the full hash is built out of, so a break in the compression function typically foreshadows a break in the full hash. Bruce Schneier and other cryptographers began recommending against MD5 for new applications shortly afterwards, and NIST published SHA-1 as an alternative.

The real break came in August 2004, when Xiaoyun Wang, Feng Xu, Hui Chen and Xiuyuan Lai presented at CRYPTO 2004 a technique that produced full-hash MD5 collisions in roughly one hour of compute time on the hardware of the day. Wang's team went on to break SHA-1 by similar methods in 2005. The Wang attack was refined by others over the next several years; by 2007 finding an MD5 collision took a few seconds on a laptop.

The moment that changed how the industry treated MD5 was December 2008, when a group of researchers led by Alexander Sotirov used a chosen-prefix collision attack to create a rogue certificate authority. They obtained a legitimate MD5-signed SSL certificate from a real CA (RapidSSL), then constructed a second certificate that had the same MD5 hash but different content, and crucially, the second certificate marked itself as an intermediate CA authorised to issue further certificates. Every browser in the world trusted the forged CA. Sotirov's team disclosed the attack responsibly and never weaponised it, but it demonstrated that MD5 was no longer usable for signatures. Public CAs stopped signing MD5 certificates immediately; browsers phased out trust for MD5-signed intermediates over the following two years.

The final large-scale malicious exploitation was Flame, discovered in 2012. Flame was a state-sponsored espionage malware, targeting systems in the Middle East, that used an MD5 chosen-prefix collision to forge a Microsoft code-signing certificate, the same trust anchor that authorises Windows Update. Compromised machines received malicious updates that appeared to be signed by Microsoft. Analysis of Flame revealed a level of cryptographic sophistication only available to a nation-state actor, and the specific MD5 attack it used required computational resources estimated at around $200,000 in 2012 dollars. Microsoft revoked the trust anchors within days of the disclosure and switched to SHA-1 (then in 2016 to SHA-2) for all future Windows Update signing.

Structure of the Algorithm

MD5 belongs to the Merkle–Damgård family of hash functions, a design pattern that Ralph Merkle and Ivan Damgård introduced independently in 1979. In this construction the input is broken into fixed-size blocks (512 bits for MD5), padded so the total length is a multiple of the block size, and then fed one block at a time into a compression function along with the current state. The compression function outputs a new state of the same size (128 bits for MD5), and the final state after processing the last block is the hash output.

MD5's compression function itself has a specific structure: it takes the current 128-bit state (arranged as four 32-bit words A, B, C, D) and the current 512-bit message block (arranged as 16 32-bit words), and runs 64 rounds of mixing. Each round takes one of the 16 message words and one of A, B, C, D, applies a non-linear function to three of them, adds the fourth and the message word, rotates by a fixed amount, and updates one of the state variables. The non-linear function changes every 16 rounds, cycling through four variants that Rivest called F, G, H and I. This structure is very fast on 32-bit hardware, each round is a handful of AND, OR, XOR and ADD operations, which is exactly what made MD5 so widely deployed in the first place.

The Merkle–Damgård construction is elegant but has one structural weakness that matters for how MD5 fails: it is vulnerable to length-extension attacks. Given H(m) and the length of m, an attacker can compute H(m || padding || m') for arbitrary m' without knowing m. This is why you should never authenticate a message by hashing a secret key concatenated with the message. Use HMAC instead. This is not specific to MD5, SHA-1 and SHA-2 share the same weakness, because they use the same underlying construction. Only SHA-3, which uses a sponge construction rather than Merkle–Damgård, is not vulnerable to length extension.

Where MD5 Is Still (Legitimately) Used

"MD5 is broken" is true but under-nuanced. It is broken for exactly one property, collision resistance, and that break matters only in contexts where an adversary can influence the input. In contexts where there is no adversary, MD5 remains a fast, well-analysed 128-bit hash. It has legitimate uses in exactly these no-adversary contexts:

  • File integrity in non-adversarial contexts. Verifying that a file downloaded from a mirror matches the copy on the master server, when both are under friendly control. Linux distribution ISOs still frequently publish MD5 (as well as SHA-256) checksums for this reason, a small script that walks a directory checking MD5s against known values is a fast way to detect bit rot or partial downloads. An attacker who controlled the mirror could substitute a colliding file, but the threat model here is corruption, not attack.
  • Content-addressed storage without security requirements. Deduplication systems, cache-key generation, and change-detection heuristics all benefit from a fast fingerprint of file contents, and MD5 is faster than SHA-2 and adequate when the only concern is accidental collision (which is astronomically unlikely across normal workloads even for MD5).
  • Non-cryptographic bloom filters and hash tables. Any place a good hash function is needed but the security properties are not, MD5 is a reasonable drop-in. It has good distribution, is fast, and has been analysed extensively.
  • HMAC-MD5 in legacy protocols. Surprisingly, HMAC-MD5 is still secure, the HMAC construction dodges most of the ways MD5 has been broken. It is specified in RFC 2104 and still appears in some legacy authentication protocols (CHAP, some IPsec configurations). NIST and industry guidance is nonetheless to migrate away from HMAC-MD5 for defence-in-depth reasons.

Do not use MD5 for anything that could involve an adversary: never for signatures, never for TLS certificates, never for password storage (even beyond the broken-hash issue, fast hashes are the wrong tool for password storage, see the SHA chapter), never for detecting tampering, never for content integrity in a hostile environment. The line between "safe" and "unsafe" is exactly whether an adversary can influence the hash's inputs.

Common Misconceptions

  • "MD5 is broken because it can be reversed." It cannot. MD5 is broken for collision resistance, which is a different property. Pre-image resistance, the property that you cannot recover the input from the hash, still holds in practice. The best known pre-image attack is Sasaki and Aoki (2009) at 2123.4, which is faster than the 2128 brute force bound but entirely infeasible.
  • "MD5 hashes are unique." They are not. Collisions can be produced deliberately in seconds; accidental collisions are astronomically rare (the birthday bound is roughly 264 hashes, or 18 quintillion, before you expect one) but not impossible.
  • "Salting MD5 makes it safe for passwords." No. Salting stops precomputed rainbow tables but does nothing about throughput. A modern GPU can compute tens of billions of salted MD5 hashes per second, and every stolen password database is brute-forced individually. Password storage needs a slow, memory-hard KDF: Argon2id, scrypt, or bcrypt.
  • "MD5 collisions require special inputs and cannot happen in normal use." The 2004 Wang attack and its refinements produce collisions on arbitrary prefixes, chosen-prefix collisions mean an attacker can make two meaningful documents (say, two different contracts) hash to the same value. This is what enabled the Flame attack on Microsoft's code-signing infrastructure.

How It Works

MD5 processes input in 512-bit blocks:

  1. Padding: Add padding to make length multiple of 512 bits
  2. Append Length: Add original message length
  3. Initialize State: Set initial hash values
  4. Process Blocks: Apply compression function to each block
  5. Output: Produce 128-bit hash value

Implementation


import hashlib

def md5_hash(data):
    """Compute MD5 hash"""
    return hashlib.md5(data.encode()).hexdigest()

# Example usage
message = "Hello, MD5!"
hash_value = md5_hash(message)
print(f"MD5 Hash: {hash_value}")

# Note: MD5 should NOT be used for security purposes
# Use SHA-256 or SHA-512 instead
                

Specifications

  • Output Size: 128 bits (16 bytes)
  • Block Size: 512 bits
  • Rounds: 4 rounds of 16 operations (64 steps total)
  • Status: Cryptographically broken

Security Issues

MD5 has serious security vulnerabilities:

  • Collision resistance: completely broken. Two different inputs with the same hash can be produced in seconds on a laptop. Chosen-prefix collisions are also practical, which is what enabled the forged Microsoft code-signing certificate used by the Flame malware in 2012.
  • Pre-image resistance: not broken in practice. The best known pre-image attack is Sasaki & Aoki (2009) at 2123.4 operations, faster than the 2128 generic bound, but entirely infeasible. Given only a hash, you still cannot recover an input.
  • Consequence: MD5 is fatal anywhere an adversary can influence the input, signatures, certificates, deduplication, integrity checks against tampering. It is merely inadvisable where no adversary exists.

MD5 collisions were first demonstrated by Wang et al. in 2004. The distinction above matters: MD5 is broken for collision resistance, not for pre-image resistance, and conflating the two leads people to the wrong conclusions about which legacy uses are actually dangerous.

When to Use MD5

Do NOT use MD5 for security purposes. It may only be used for:

  • Non-security checksums (file integrity in non-adversarial environments)
  • Legacy system compatibility
  • Educational purposes

For security applications, always use SHA-256 or SHA-512 instead.

Secure Alternatives

  • SHA-256: Recommended for most applications
  • SHA-512: For high-security requirements
  • BLAKE3: Modern, very fast, parallelizable (BLAKE2 is its widely-deployed predecessor)
  • SHA-3 / SHAKE: Sponge construction, immune to length extension
  • Argon2id: For password hashing, never use a general-purpose hash for this

Related Algorithms

Explore other encryption algorithms: