MoeWalls
304 words
2 minutes
RSA 101
Overview
You’re given RSA parameters and a ciphertext. Factoring n via FactorDB yields a very small prime p = 101 and a large prime q. Standard RSA decryption m = c^d mod n returns a number that doesn’t decode to ASCII.
The twist: the original message M was larger than the modulus n, so encryption implicitly reduced it modulo n. After decryption, you get M mod n; to recover M, you add back (a multiple of) n.
Given Parameters
p = 101q = 313846144900241708687128313929756784551n = 31698460634924412577399959706905435239651e = 65537c = 23648999580642514140599125257944114844209
Math
- phi(n) = (p - 1)(q - 1)
- d = e^-1 mod phi(n)
- m_dec = c^d mod n
- If original M >= n, encryption sent M mod n. After decryption we get m_dec = M mod n.
- Recover M by testing M = m_dec + k*n for small k >= 0 until bytes decode. Here k = 1 works.
Solution Script
import sympy as sp
p = 101q = 313846144900241708687128313929756784551n = 31698460634924412577399959706905435239651e = 65537c = 23648999580642514140599125257944114844209
# Sanity checksassert p * q == nassert sp.isprime(p) and sp.isprime(q)
phi = (p - 1) * (q - 1)d = pow(e, -1, phi)
m_dec = pow(c, d, n)print("m_dec =", m_dec)
# Try adding multiples of n until it decodesdef try_decode(x: int): try: h = hex(x)[2:] if len(h) % 2: h = "0" + h return bytes.fromhex(h).decode() except Exception: return None
flag = Nonefor k in range(0, 5): candidate = m_dec + k * n s = try_decode(candidate) if s and s.startswith("v1t{") and s.endswith("}"): flag = s print("k =", k, "->", flag) break
assert flag is not NoneWhy This Works
- RSA encrypts modulo
n. If the original messageMis larger thann, the actual encrypted value is based onM mod n. - Decryption returns the reduced message. Adding one modulus (or a few) reconstructs a valid preimage that maps to ASCII.
Flag
v1t{RSA_101_b4by}