Partial-Match RSA Verification Exploit (Suffix Forgery via Small Modulus)
- •
What it is
- •
If a verifier only checks a small portion of a decrypted/verified value — e.g. splitting on a delimiter and checking only the last few bytes match a target string — an attacker can forge a value satisfying just that portion using arithmetic modulo a small power of 2 (or another small modulus matching the checked portion's byte-length), entirely decoupled from the real, large RSA modulus . If the forged value raised to the public exponent stays smaller than (no modular wraparound occurs), then exactly as an integer — so controlling 's value modulo a small directly controls the low bits of , which is exactly the portion the verifier inspects; the untouched high-order bits simply don't matter to a check that only looks at the tail.
- •
- •
When to apply
- •
Verification logic extracts and checks only a substring/suffix/prefix of the full decoded value (e.g.
.split(delimiter)[-1] == target) rather than requiring the entire decoded value to match exactly — and the checked portion is small enough, in bytes, that raising a same-sized candidate to the public exponent still stays well below the real modulus.
- •
- •
Math
- •
For a -bit odd target and odd , exponentiation by is a permutation of the odd residues modulo when . Compute , set , and verify . The shortcut does not apply unchanged to an even target. Also require if the verifier reduces modulo before checking the suffix.
- •
- •
Worked example
- •
Target suffix
\x00VOTE FOR PEDRO(15 bytes, 120 bits), : computing and gave a candidate whose cube (, only 359 bits) was far smaller than a real 1024+ bit — confirming no wraparound — and 's raw bytes ended in exactly the target suffix.
- •
- •
Python
- •
k_bits = len(target_suffix) * 8 mod = 1 << k_bits phi = 1 << (k_bits - 1) d = pow(e, -1, phi) x = pow(bytes_to_long(target_suffix), d, mod) # x**e < N (verify this bound explicitly), so pow(x, e, N) ends in target_suffix
- •
- •
- •
Cards
- •
Why can the real RSA modulus N be ignored entirely in this attack?
- •
As long as the forged value raised to e stays smaller than N, no modular reduction happens, so the result equals the small-modulus computation exactly — N never comes into play.
- •
- •
What makes φ(2^k) easy to compute and invert e against?
- •
φ(2^k) = 2^(k-1) always, and any odd e is automatically coprime to a power of 2, guaranteeing an inverse exists.
- •
- •