import urllib.request
import json
import sys
BASE = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:5000"
def get(path):
with urllib.request.urlopen(BASE + path, timeout=10) as resp:
return json.loads(resp.read().decode())
info = get("/public_key")
n = int(info["n"])
e = int(info["e"])
c = int(info["ciphertext"])
print(f"[+] n bits = {n.bit_length()}")
print(f"[+] e = {e}")
def oracle(ct):
r = get(f"/oracle?ciphertext={ct}")
return r["even"]
# Атака Блейхенбахера
lower = 0
upper = n
current_c = c
# Количество итераций: n.bit_length() + запас
MAX_ITER = n.bit_length() + 10
for i in range(MAX_ITER):
current_c = (current_c * pow(2, e, n)) % n
is_even = oracle(current_c)
mid = (lower + upper) // 2
if is_even:
upper = mid
else:
lower = mid
# Каждые 100 итераций пробуем восстановить
if i % 100 == 0 or i == MAX_ITER - 1:
k = i + 1
# m ≈ upper * n / 2^k
m_approx = (upper * n) >> k
if m_approx > 0:
try:
b = m_approx.to_bytes((m_approx.bit_length() + 7) // 8, 'big')
if all(32 <= x < 127 for x in b):
print(f"[{i}] m ≈ {b}")
except:
pass
# Финальное восстановление
k = MAX_ITER
m_final = (upper * n) >> k
b = m_final.to_bytes((m_final.bit_length() + 7) // 8, 'big')
print(f"\n[+] Recovered: {b}")