Merkle–Damgård Construction — the digest IS the internal state
The structural skeleton behind MD5, SHA-1 and SHA-2: pad the message, split it into fixed-size blocks, and iterate a compression function h_i = f(h_{i-1}, block_i) starting from a fixed IV — the final chaining value *is* the digest, nothing is mixed in or discarded at the end. That one design choice (no finalization step that hides state) is the root cause of several distinct attacks, so recognizing "this hash is Merkle–Damgård" is the first triage step, not a detail.
The signal that betrays it
- The target hash is MD5, SHA-1, or full SHA-2 (SHA-256/SHA-512) — any classic iterated hash built the textbook way. (Confirmed against Wikipedia: the Merkle–Damgård construction is exactly this pad → fixed-IV → iterate-compression-function → output-last-state shape.)
- You see a naive keyed MAC of the shape H(secret || message) rather than HMAC — that phrasing alone is the tell that the digest can be resumed from.
- The challenge or its comments talk about "internal state", "chaining value", or expose padding bytes (0x80 then zero bytes then a length field) — that's MD-padding leaking through, a dead giveaway of the construction.
- You're given (or can influence) an existing valid (message, digest) pair and asked to produce a tag for a *longer* message you don't fully control the prefix of — the shape of a length-extension setup.
How it's exploited
The mechanism in one sentence: because finalization does nothing but output the last chaining value, anyone who knows a digest already possesses the full internal state needed to resume hashing — they never need to have seen the bytes that produced it.
- Resume hashing from a known digest. Load the digest of secret || message as your own compression function's starting registers; continue processing new blocks from there. This is the entire mechanism behind Hash Length Extension — forge H(secret‖msg‖extra) from a digest alone — that page has the operational tooling (hashpumpy) and the length-brute-forcing loop when len(secret) isn't given.
- Reconstruct the glue padding exactly. MD padding is 0x80, then zero bytes, then the message bit-length as a big-endian field — but the field width and block size depend on the algorithm: 64-bit length field with a 64-byte block for MD5/SHA-1/SHA-256, versus a 128-bit length field with a 128-byte block for the SHA-512 family (SHA-512, SHA-384, SHA-512/224, SHA-512/256). It depends only on the *combined* length of everything hashed so far — always computable, never guessable:
``python
def md_pad(total_len_bytes, block_size=64, len_field_bytes=8):
bitlen = total_len_bytes * 8
reserved = len_field_bytes + 1
pad = b"\x80" + b"\x00" * ((block_size - reserved - total_len_bytes) % block_size)
return pad + bitlen.to_bytes(len_field_bytes, "big")
``
Get this wrong by even one byte, the wrong endianness, or the wrong length-field width for the algorithm (e.g. using 8 bytes instead of 16 for SHA-512) and the forged tag simply fails to verify, with no partial-credit signal to debug from.
- Exploit the same state-leak for multicollisions, not just extension. Because the chaining value is the *entire* state carried between blocks, an attacker can build 2^t messages that all collide for roughly the cost of only t single-block collisions (Joux's trick) — see Multicollision Attack — Joux's trick: 2^t colliding messages for the price of t single-block collisions for the construction. Length extension and multicollisions are two different attacks that share exactly one root cause: no hidden state.
- Davies–Meyer fixed points ride the same skeleton. Because each block's output feeds directly and predictably into the next compression call, specially-crafted fixed-point blocks let you splice no-op blocks in anywhere — see Fixed-Point Hash — Davies-Meyer no-op blocks that let you insert or expand a message for free for expandable-message and second-preimage use.
Related
Hash Length Extension — forge H(secret‖msg‖extra) from a digest alone Multicollision Attack — Joux's trick: 2^t colliding messages for the price of t single-block collisions Fixed-Point Hash — Davies-Meyer no-op blocks that let you insert or expand a message for free HMAC Fundamentals — the nested MAC that tells you when to STOP trying length-extension Sponge Construction — why length-extension does NOT work on SHA-3/Keccak
What does NOT work
- Assuming any hash-shaped construction is Merkle–Damgård. Check the actual output stage before reaching for length-extension or multicollision reasoning: HMAC's nested `H(K⊕opad || H(K⊕ipad || m))` never exposes the raw state after the secret is mixed in, so there's nothing to resume from — the whole class of structural attacks on this page simply doesn't apply. Confirm which construction you're looking at first; don't burn time writing an exploit against HMAC-anything using MD reasoning. Full pivot options once HMAC is confirmed are in HMAC Fundamentals — the nested MAC that tells you when to STOP trying length-extension.
- Applying the same reasoning to SHA-3/Keccak. The sponge construction deliberately keeps part of its state (the capacity) hidden and never output, by design — that's the specific property that makes length-extension impossible against it. See Sponge Construction — why length-extension does NOT work on SHA-3/Keccak for why the construction itself (not a patch on top) closes this off.
- Treating the truncated SHA-2 variants as automatically safe or automatically vulnerable by name alone. SHA-384, SHA-512/224 and SHA-512/256 discard part of the final internal state before output, so the MD-state leak is closed for them too, even though they're built on the same Merkle–Damgård skeleton as full SHA-512 — don't let "it's SHA-2 family" override checking whether the *specific* variant truncates its output.
- Guessing padding instead of computing it. The 0x80/zero-fill/length-field padding is fully determined by the combined byte length and the algorithm's length-field width and endianness — trial-and-error on padding bytes wastes time that exact computation (or hashpumpy, see Hash Length Extension — forge H(secret‖msg‖extra) from a digest alone) avoids entirely.
Verified against
15 claims checked against these sources · 1 refuted and removed
Source: Sinapsi — verified compositional memory, queryable by LLMs. Query this wiki live from your assistant over MCP, or build your own verified wiki (public, or private for your team). CC BY 4.0 — reuse with attribution to Sinapsi.