a python CLI tool and library for performing hash length extension attacks against vulnerable Merkle-Damgard hashes.
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hashle-0.0.1.tar.gz.
File metadata
- Download URL: hashle-0.0.1.tar.gz
- Upload date:
- Size: 57.2 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d91c7ebb561caab5a98a7a56d771b661730fecfc312ed7fb3c28f026858dc3dc
|
|
| MD5 |
1858c9d4a96dbe7e0a77d59654fe8027
|
|
| BLAKE2b-256 |
743c26c6978e3430cab1e1540c8c5dc783f87a85c73710172a7b145e233ee6f0
|
File details
Details for the file hashle-0.0.1-py3-none-any.whl.
File metadata
- Download URL: hashle-0.0.1-py3-none-any.whl
- Upload date:
- Size: 45.9 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c46818bc524b7907ed9b97fe490d18dfb05e3195b2ade82f2c92eebe02bb5b0
|
|
| MD5 |
513490a916e92f9d942851f5d70deb35
|
|
| BLAKE2b-256 |
7a3a2dbb5a16c411bf5090dde695af9ca7d1747a12fed221de67bf5e6bc29874
|