theartofwar

Category
Cryptography
Points
205
Tags

So we got 2 file, output.txt and main.py

main.py:

from Crypto.Util.number import bytes_to_long, getPrime, long_to_bytes
import time


flag = open('flag.txt', 'rb').read()
m = bytes_to_long(flag)

e = getPrime(8)
print(f'e = {e}')

def generate_key():
    p, q = getPrime(256), getPrime(256)
    while (p - 1) % e == 0:
        p = getPrime(256)
    while (q - 1) % e == 0:
        q = getPrime(256)
    return p * q

for i in range(e):
    n = generate_key()
    c = pow(m, e, n)
    print(f'n{i} = {n}')
    print(f'c{i} = {c}')

output.txt:

❯ cat output.txt
e = 229
n0 = 4133000467509364935031235422549250721944804102635126859171287340663853905144304279207722105302316322260373188441296903081565640870622284840397538002237331
c0 = 3948516562901221579319242054999926100356598986131508069290749654122146258185357479755195245759062508504409839795634616384594556630261405196176415874727674
n1 = 10012310178440378644460341473165848881968550265291067580300168032729328228000061345651296737301058801752166581806744841746261097249355596503846722347988833
c1 = 7203369362959462243170744698257523975344935146787494714580742042030559300473546901912861737948713816740624292361174535303284449900823238173178576198697775
...
...
...
...
...
...
n228 = 8436105266779215397600464028220244463194349609028479668519755739586774034522217632224615906136235170783922483076839235183125889204826283386865406369080437
c228 = 89900466013784478553210494829116144898476776253278000711433633982268352924632956071541960485866929379189727059518179434642644257558019991914076483483

the main.py, it reads a flag message and converts it to an int m. It also generates a small prime public exponent e, also there is multiple ecryptions, it loops e times, in each loop it generates a new unique RSA modulus n_i and uses it to encrypt the same message m with the public exponent e, then the output process results in e different ciphertexts (c_i) and their corresponding moduli (n_i). Each spair satifies the congruence: $$ C_i = m^e (mod n_i) $$ to recover, we can use Chinese Reminder Theorem, it applies to the system of congruences. The CRT solves for a single value, lets call it M, that satifies all the conditions simultanenously

solver.py:

from Crypto.Util.number import long_to_bytes, inverse
from sympy import integer_nthroot

lines = open('output.txt').read().strip().splitlines()
e = int(lines[0].split('=')[1].strip())

ns = []
cs = []
for i in range(1, len(lines), 2):
    n = int(lines[i].split('=')[1].strip())
    c = int(lines[i+1].split('=')[1].strip())
    ns.append(n)
    cs.append(c)

from functools import reduce

def crt(cs, ns):
    N = reduce(lambda x, y: x * y, ns)
    result = 0
    for c, n in zip(cs, ns):
        Ni = N // n
        inv = inverse(Ni, n)
        result += c * Ni * inv
    return result % N

M = crt(cs, ns)
m, exact = integer_nthroot(M, e)
assert exact, "Root not exact, something went wrong"
print(long_to_bytes(m))
theartofwar Flag: tjctf{the_greatest_victory_is_that_which_require_no_battle}