# N = 7766768698831459057447624753799597048605145237159899787468949300915452509464565099496679099145810975822175634998097262892579678554704760323902554901001931 # c = 3032034114991327495494398063970483186189941361342590220935258419146172566936781482456512156238329348954750763279841189333666924656636066281016492074315344 # e mod 65537 = 1 # PHI_mod_65537 = 43577
q = getPrime(16) 只有 16 bit,也就是一个很小的素数因子,所以 N 可以直接被快速分解,一旦分解出 p,q,RSA 就能正常求私钥解密。
解题脚本:
from Crypto.Util.number import inverse, long_to_bytes, GCD import sympy as sp
N = 7766768698831459057447624753799597048605145237159899787468949300915452509464565099496679099145810975822175634998097262892579678554704760323902554901001931 c = 3032034114991327495494398063970483186189941361342590220935258419146172566936781482456512156238329348954750763279841189333666924656636066281016492074315344
# 1) factor N: q is 16-bit prime q = None for prime in sp.primerange(2, 1 << 16): if N % prime == 0: q = prime break
p = N // q phi = (p - 1) * (q - 1)
# 2) recover e from e = 65537*k + 1 for k inrange(2, 200): e = 65537 * k + 1 if GCD(e, phi) == 1: break
# 3) decrypt d = inverse(e, phi) m = pow(c, d, N) print(long_to_bytes(m))
# (Optional) quick sanity: hint2 should be multiple of q1 assert hint2 % q1 == 0
# ====== Part 2: recover r from gcd(hint5-1, n2), then get m2 from (hint5-1)/r^2 ====== r = GCD(hint5 - 1, n2) assert r != 1and n2 % r == 0, "Failed to recover r"
# Because hint5 < r^3, we can extract m2 exactly from binomial expansion: # hint5 ≡ 1 + m2*r^2 (mod r^3) and 0 <= hint5 < r^3 => hint5-1 = m2*r^2 m2_int = (hint5 - 1) // (r * r) m2 = long_to_bytes(m2_int)
print("[+] r =", r) print("[+] m2 =", m2)
# (Optional) recover q2 from gcd(hint3-hint4, n2) q2 = GCD(hint3 - hint4, n2) # gcd may return q2 or q2*r (rare if (hint3-hint4) also multiple of r) if q2 % r == 0: q2 //= r assert q2 != 1and n2 % q2 == 0, "Failed to recover q2"
p2 = n2 // (q2 * r)
print("[+] q2 =", q2) print("[+] p2 =", p2)
# ====== assemble flag ====== flag = m1 + m2 print("\n[+] FLAG =", flag.decode(errors="replace"))
# 生成私钥偏移数组:把 key 每个字符的 Unicode 十进制展开成数字序列 shift_array = [] if private_key: for ch in private_key: shift_array.extend(int(d) for d instr(ord(ch)))
# 三种长度类型对应的数据位数(trits 数) len_table = [6, 9, 12]
out = [] pos = 0 char_index = 0
defneed(n: int): if pos + n > len(encoded_str): raise ValueError(f"密文不足:当前位置 {pos} 需要 {n} 个符号,但总长 {len(encoded_str)}")
while pos < len(encoded_str): # 1) 读取 2 位随机偏移编码 need(2) a = encoded_str[pos] b = encoded_str[pos + 1] pos += 2 if a notin mapping or b notin mapping: raise ValueError(f"出现非法符号:{a}{b} (pos={pos-2})")
import random import string CHARS = "哈基米南北绿豆阿西噶压库那鲁曼波欧马自立悠嗒步诺斯哇嗷冰踩背叮咚鸡大狗叫袋鼠兴奋剂出示健康码楼上下来带一段小白手套胖宝牛魔呵嘿喔" random.seed(777) a = random.sample(range(64), 64) CHARS1 = "".join((CHARS[a.index(i)] for i inrange(64))) CHARS = CHARS1 CHAR_TO_INDEX = {char: idx for idx, char inenumerate(CHARS)}
if __name__ == "__main__": encoded = "叮鼠背叮康豆绿步叫豆北哇基豆喔袋哈阿牛鼠南健牛出基来阿鸡马北豆库" result="" for char in encoded: targetIndex = CHAR_TO_INDEX[char] for i in string.printable: i=str(i) index = -1 if"A" <= i <= "Z": index = ord(i) - ord("A") else: if"a" <= i <= "z": index = ord(i) - ord("a") + 26 else: if"0" <= i <= "9": index = ord(i) - ord("0") + 52 else: if i == "+": index = 62 else: if i == "/": index = 63 if index == targetIndex: result+=i print(result) break