from sage.allimport * import secrets from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import sha256 from pwn import process, remote import ast
results = [] for G in polys: io.recvuntil(b"polynomial: ") res = ast.literal_eval(io.recvlineS().strip()) results.append((G, res))
residues = [] for G, res in results: iv = (x**16).inverse_mod(G) ress = [iv * int2poly(r) % G for r in res] residues.append(ress)
T = [crt([0] * i + [1] + [0] * (len(polys) - i - 1), polys) for i inrange(len(polys))] P = prod(polys) arr = [] for i inrange(len(polys)): for res in residues[i]: arr.append(T[i] * res % P) ln = len(polys) * 16 mat = matrix([x.padded_list(ln) for x in arr]) sol = mat[:, -16 * extra :].left_kernel_matrix()[0] key = bv2int(sol * mat) cipher = AES.new( sha256(long_to_bytes(key)).digest()[:16], AES.MODE_CTR, nonce=b"12345678" ) print(cipher.decrypt(enc_flag)) # SEKAI{CrCrCRcRCRcrcrcRCrCrC}
import secrets from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import sha256
from flag import FLAG
isIrreducible = [Truefor i inrange(1 << 17)]
definit(): for f inrange(2, 1 << 17): if isIrreducible[f]: ls = [0] # store all multiples of polynomial `f` cur_term = f while cur_term < (1 << 17): ls = ls + [x ^ cur_term for x in ls] cur_term <<= 1
for g in ls[2:]: # the first two terms are 0, f respectively isIrreducible[g] = False
msg <<= 16 for i inrange(msglen - 1, -1, -1): if (msg >> (i + 16)) & 1: msg ^= (gen_poly << i)
return msg
deforacle(secret, gen_poly): l = int(13.37) res = [secrets.randbits(16) for _ inrange(l)] res[secrets.randbelow(l)] = getCRC16(secret, gen_poly) return res
defmain(): init() # build table of irreducible polynomials
from sage.allimport * import secrets from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import sha256 from pwn import process, remote import ast import itertools from tqdm import tqdm import random
defbv2int(bv): returnsum([int(b) << i for i, b inenumerate(bv)])
R = GF(2)["x"] x = R.gen()
defint2poly(i): return R(int2bv(i, 17))
isIrreducible = [Truefor i inrange(1 << 17)]
definit(): for f inrange(2, 1 << 17): if isIrreducible[f]: ls = [0] # store all multiples of polynomial `f` cur_term = f while cur_term < (1 << 17): ls = ls + [x ^ cur_term for x in ls] cur_term <<= 1
for g in ls[2:]: # the first two terms are 0, f respectively isIrreducible[g] = False
init() irr = [i for i, b inenumerate(isIrreducible) if b and (1 << 16) <= i]
defget_polys(n): start = 15 return [int2poly(i) for i in irr[start : start + n]]
extra = 133 polys = get_polys(extra) extra -= 512 // 16 print(len(polys)) int_polys = [bv2int(f) for f in polys]
results = [] for G in polys: io.recvuntil(b"polynomial: ") res = ast.literal_eval(io.recvlineS().strip()) results.append((G, res))
residues = [] for G, res in results: iv = (x**16).inverse_mod(G) ress = [iv * int2poly(r) % G for r in res] residues.append(ress)
T = [crt([0] * i + [1] + [0] * (len(polys) - i - 1), polys) for i inrange(len(polys))] P = prod(polys) arr = [] for i inrange(len(polys)): for res in residues[i]: arr.append(T[i] * res % P) ln = len(polys) * 16 mat = matrix([x.padded_list(ln) for x in arr])
ker = mat[:, -16 * extra :].left_kernel_matrix() print(ker.dimensions()) # for i in tqdm( # itertools.product(range(2), repeat=ker.dimensions()[0]), # total=2 ** ker.dimensions()[0], # ): # sol = vector(i) * ker # key = bv2int(sol * mat) # cipher = AES.new( # sha256(long_to_bytes(key)).digest()[:16], AES.MODE_CTR, nonce=b"12345678" # ) # flag = cipher.decrypt(enc_flag) # if flag.isascii(): # print(flag)
# -log((12/13)**113,2).n() ~= 13
defbrute(id): r = random.Random(secrets.token_bytes(16)) attempts = 0 whileTrue: attempts += 1 if attempts % 100 == 0: print(id, attempts) sidx = [] for i inrange(0, 13 * 113, 13): sidx.append(r.choice(range(i, i + 13))) sidx = tuple(sidx) lk = ker[:, sidx].left_kernel_matrix() print(lk.dimensions()) if lk.dimensions()[0] > 8: continue sol_space = lk * ker for i in itertools.product(range(2), repeat=sol_space.nrows()): sol = vector(i) * sol_space key = bv2int(sol * mat) cipher = AES.new( sha256(long_to_bytes(key)).digest()[:16], AES.MODE_CTR, nonce=b"12345678", ) flag = cipher.decrypt(enc_flag) if flag.isascii(): whileTrue: # to ensure that the flag will not be overwritten by other processes :) print(flag) break else: continue break
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor(max_workers=4) as executor: executor.map(brute, range(4)) # SEKAI{4R3_Y0U_cRc_M4s73R?}
from sage.allimport * import secrets from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import sha256 from pwn import process, remote import ast import itertools from tqdm import tqdm, trange import random
defbv2int(bv): returnsum([int(b) << i for i, b inenumerate(bv)])
R = GF(2)["x"] x = R.gen()
defint2poly(i): return R(int2bv(i, 17))
isIrreducible = [Truefor i inrange(1 << 17)]
definit(): for f inrange(2, 1 << 17): if isIrreducible[f]: ls = [0] # store all multiples of polynomial `f` cur_term = f while cur_term < (1 << 17): ls = ls + [x ^ cur_term for x in ls] cur_term <<= 1
for g in ls[2:]: # the first two terms are 0, f respectively isIrreducible[g] = False
init() irr = [i for i, b inenumerate(isIrreducible) if b and (1 << 16) <= i]
defget_polys(n): start = 15 return [int2poly(i) for i in irr[start : start + n]]
total = 133 polys = get_polys(total) extra = total - 512 // 16 print(len(polys)) int_polys = [bv2int(f) for f in polys]
results = [] for G in polys: io.recvuntil(b"polynomial: ") res = ast.literal_eval(io.recvlineS().strip()) results.append((G, res))
residues = [] for G, res in results: iv = (x**16).inverse_mod(G) ress = [iv * int2poly(r) % G for r in res] residues.append(ress)
T = [crt([0] * i + [1] + [0] * (len(polys) - i - 1), polys) for i inrange(len(polys))] P = prod(polys) arr = [] for i inrange(len(polys)): for res in residues[i]: arr.append(T[i] * res % P) ln = len(polys) * 16 mat = matrix([x.padded_list(ln) for x in arr])
ker = mat[:, -16 * extra :].left_kernel_matrix() print(ker.dimensions()) # not zero :(
# with Utaha's idea # sol would be in the form of # [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, ...] # + ? * [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...] # + ? * [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...] # ... # + ? * [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, ...] # + ? * [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, ...] # ... # so sol-base would be in 12*133 dim space instead of 13*133 dim space
F = GF(2) vecs = [] for i in trange(total): for j inrange(13 - 1): v = vector(F, [0] * total * 13) v[13 * i] = 1 v[13 * i + j + 1] = 1 vecs.append(v) V = matrix(vecs) base = vector(F, [0] * total * 13) for i inrange(total): base[13 * i] = 1
Ap = mat[:, 512:] rhs = -base * Ap lhs = V * Ap x0 = lhs.solve_left(rhs) lk = lhs.left_kernel_matrix() print(lk.dimensions()) for i in itertools.product([0, 1], repeat=lk.nrows()): x = x0 + vector(i) * lk sol = x * V + base key = bv2int(sol * mat) cipher = AES.new( sha256(long_to_bytes(key)).digest()[:16], AES.MODE_CTR, nonce=b"12345678", ) flag = cipher.decrypt(enc_flag) if flag.isascii(): print(flag) print(i) # but for a overwhleming majority of cases, this is (0, 0, 0, ...) break # SEKAI{4R3_Y0U_cRc_M4s73R?}