This page could not start. Browsers block JavaScript modules loaded over
file://, so opening the .html straight from disk will not work. Serve the
directory over HTTP instead — from the project folder run
python3 -m http.server and open http://localhost:8000/.
(Deployed on GitHub Pages this does not apply.)
MD4, MD5, SHA-1 and SHA-2 all use the Merkle–Damgård construction: the message is padded to a whole number of blocks, and each block is fed through a compression function that updates a small internal state. When the last block is done, that state is the digest.
So a digest is a resumable checkpoint. This is the whole reason the attack works.
Applications commonly adopt the
H(secret || data) construction to prove that the data they issued
comes back untampered. Publishing both the data and its hash makes it possible to
extend the hash with arbitrary data. You can append your
own bytes and produce a hash the server will accept, without ever learning the secret.
The one catch is padding. The original hash internally padded
secret || data out to a block boundary, so your appended bytes
actually land after that padding. The forged message therefore has to carry that padding
in the middle of it. This includes the \x80\x00\x00... run plus a length field,
known as glue padding.
Given it the hash, the known data it covers, what you want to append, and the secret's length in
bytes, you can append data without knowning the secret. It returns the forged hash and the new message. Supported
algorithms are sha256, sha1, sha512,
md5, md4, ripemd160, ripemd128,
sm3, whirlpool, tiger192v1 and
tiger192v2. Data and appended data can be entered as text or as hex.
It will not help you against SHA-3 or BLAKE2, which are built so that the digest never exposes the whole internal state. Nor against SHA-384 or SHA-512/256, which truncate a SHA-512 state and withhold 128 and 256 bits respectively.
This is a direct JavaScript port of
iagox86/hash_extender by
Ron Bowes (BSD 3-Clause). The padding and extension logic are ports of that
project's hash_append_data() and hash_gen_signature_evil().
All credit for the tool and the technique writeup goes there.
If you happen to know the secret, this proves the attack end to end: it recomputes
H(secret || data) to confirm it matches your signature, then
recomputes H(secret || new data) to confirm it matches the
forged one. Useful for building a demo, or for sanity-checking a target's key length.
Plenty of people have already explained this attack well, so rather than write another version, here are the ones worth your time:
H(secret || data) constructions that make this attack possible in
the first place, and what to use instead.