hashle
hashle is a Python library and CLI for performing hash length extension (HLE) attacks against vulnerable Merkle-Damgard hash constructions.
Given H(secret || known_data), an assumed length for secret, and attacker controlled data, hashle computes a new message and a valid signature for H(secret || known_data || glue_padding || append_data) -- all without ever knowing secret.
Credit
Inspired by the C tool hash_extender and hlextend.
Supported algorithms
Every hash algorithm supported by hash_extender's C engine is implemented in
pure Python:
| Algorithm | Digest size | Block size | Notes |
|---|---|---|---|
md4 |
128 bits | 64 bytes | |
md5 |
128 bits | 64 bytes | |
ripemd160 |
160 bits | 64 bytes | |
sha |
160 bits | 64 bytes | Original 1993 SHA-0 |
sha1 |
160 bits | 64 bytes | |
sha256 |
256 bits | 64 bytes | |
sha512 |
512 bits | 128 bytes | |
sm3 |
256 bits | 64 bytes | |
tiger192v1 |
192 bits | 64 bytes | Uses 0x01 padding byte |
tiger192v2 |
192 bits | 64 bytes | "Tiger2", uses 0x80 padding |
whirlpool |
512 bits | 64 bytes |
All algorithms are implemented on top of a single generic, resumable Merkle-Damgard engine (hashle.algorithms.base.HashAlgorithm) that mirrors hash_extender_engine.c's padding and state-resumption logic, so adding a new algorithm only requires implementing its compression function.
Installation / development
This project uses uv for dependency
management. Always prefix Python invocations with uv run:
uv sync
uv run hashle --help
uv run pytest
CLI usage
List supported algorithms
uv run hashle list-algorithms
Compute a hash (useful for generating test signatures)
uv run hashle hash sha256 --data "hello world"
Perform a length extension attack
uv run hashle extend \
--signature a2b636472dbba4e53a5e13f1f92f24a9f5d1794d911e7727f268ed8b470b0bfc \
--data "count=10&lat=37.351&user_id=1&long=-119.827&waffle=eggo" \
--append "&waffle=liege" \
--format sha256 \
--secret-length 9
Output:
Type: sha256
Secret length: 9
New signature: 2e3a006cf5447ef611bdf0cebeb061e676f53dbfeb162aa57233a5bf273a327c
New string: count=10&lat=37.351&user_id=1&long=-119.827&waffle=eggo\x80 &waffle=liege
Key options (mirroring hash_extender's CLI):
--data/--file,--data-format(raw|hex) -- the known message.--signature-- the known hex digest ofsecret + data.--append/--append-file,--append-format-- attacker-controlled data to append.--format/-f-- one or more algorithm names to target, orallto try every algorithm whose digest length matches--signature.--secret-length-- assumed secret length, or--secret-min/--secret-maxto brute force a range of lengths.--out-data-format/--out-signature-format(raw|hex) -- output encoding.--quiet-- print only the new signature and new data (one pair of lines per secret length / algorithm combination), for easy scripting.
Library usage
from hashle import extend, hash_data
signature = hash_data("sha256", b"secretkey" + b"count=10")
result = extend(
algorithm="sha256",
signature=signature,
known_data=b"count=10",
secret_length=len(b"secretkey"),
append_data=b"&admin=true",
)
print(result.new_message) # forged message (excludes the secret)
print(result.new_signature) # valid signature for secret + new_message
Testing
uv run pytest
The test suite (tests/):
test_hashlib_parity.py-- cross-checks every hashlib-backed algorithm againsthashlibfor message lengths 0-255 and several reference strings.test_known_vectors.py-- checks the algorithms hashlib doesn't provide (md4, sha0, tiger192v1/v2, whirlpool) against published/reference-compiled test vectors.test_length_extension.py-- round-trip tests of the actual attack across every algorithm and a sweep of secret/known/append lengths, modeled onhlextend/hlextend_testscript.py.test_cli.py-- end-to-end tests of the Typer CLI.
Release files for hashle 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hashle-0.0.1.tar.gz | 57.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hashle-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 103.1 kB
Release files / hashle-0.0.1.tar.gz
| Download URL | hashle-0.0.1.tar.gz |
|---|---|
| Size | 57.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d91c7ebb561caab5a98a7a56d771b661730fecfc312ed7fb3c28f026858dc3dc
|
|
BLAKE2b-256 checksum How to use checksums |
743c26c6978e3430cab1e1540c8c5dc783f87a85c73710172a7b145e233ee6f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / hashle-0.0.1-py3-none-any.whl
| Download URL | hashle-0.0.1-py3-none-any.whl |
|---|---|
| Size | 45.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c46818bc524b7907ed9b97fe490d18dfb05e3195b2ade82f2c92eebe02bb5b0
|
|
BLAKE2b-256 checksum How to use checksums |
7a3a2dbb5a16c411bf5090dde695af9ca7d1747a12fed221de67bf5e6bc29874
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|