CyberSecurityRumble | PADY McPADaFACE

#!/usr/bin/env python3
from random import SystemRandom
from config import p,q,e,flag

print("="*50)
print(open(__file__).read())
print("~"*50)

random = SystemRandom()

flag = int.from_bytes(flag,"big")

n = p*q
assert(p<q<2*p)

print(f"{n=}")
print(f"{e=}")

def pad(m):
    assert(m<2**128)
    r = random.randrange(2**(p.bit_length()-65))
    return m+r**2

def encrypt(m):
    return pow(pad(m), e, n)

for i in bin(flag)[2:]:
    print(encrypt(int(i)))

 m_i' = r_i^2 + m_iRSA暗号化している。 c'_ijacobi記号を見ることによって m_i'quadratic residueかどうかがわかる。厳密にはわからなくて、jacobi記号 m_i'quadratic residueなら必ず1を返すというだけで、 m_i'がnon quadratic residueのときにも1を返す可能性がある。そこで平文が固定されていることを利用して、インスタンスを何個か手に入れて、絶対に-1を返さないものは m_i'がquadratic resude、つまり m_i = 0としてやる。逆に、一つでも-1を返すものは m_i = 1がわかる

from ptrlib import Socket

# https://rosettacode.org/wiki/Jacobi_symbol#Python
def jacobi(a, n):
    assert n > 0
    assert n % 2 == 1

    a = a % n
    result = 1
    while a != 0:
        while a % 2 == 0:
            a = a//2
            n_mod_8 = n % 8
            if n_mod_8 in (3, 5):
                result = -result
        a, n = n, a
        if a % 4 == 3 and n % 4 == 3:
            result = -result
        a = a % n

    if n == 1:
        return result
    else:
        return 0


def collect(numofbits=None):
    sock = Socket("localhost", 9999)
    sock.recvuntil("~~~~~~~~\n")
    n = int(sock.recvlineafter("n="))
    e = int(sock.recvlineafter("e="))

    cs = []
    while True:
        if numofbits:
            if len(cs) >= numofbits:
                break
        else:
            print(len(cs))
        try:
            c = int(sock.recvline(timeout=1))
            cs.append(c)
        except (TimeoutError, KeyboardInterrupt):
            break
    return n, e, cs

ns = []
css = []
for i in range(10):
    if i == 0:
        n, _, cs = collect()
    else:
        n, _, cs = collect(len(css[0]))
    ns.append(n)
    css.append(cs)

bits = ""
for i in range(len(css[0])):
    is_one = False
    for j in range(len(ns)):
        if jacobi(css[j][i], ns[j]) == -1:
            is_one = True
            break

    if is_one:
        bits += "1"
    else:
        bits += "0"

m = int(bits, 2)
print(bytes.fromhex(hex(m)[2:]))