defgeneratekeys(self, key: bytes) -> None: lfsr = LFSR(int.from_bytes(key, 'big')) for i inrange(self.rnd): b = 0 for j inrange(128): b = (b << 1) + lfsr.next() self.keys.append(b.to_bytes(16, 'big'))
defenc_block(self, x: int) -> int: x_bin = bin(x)[2:].rjust(128, '0') l, r = int(x_bin[:64], 2), int(x_bin[64:], 2) for i inrange(self.rnd): magic = c_uint64(0xffffffffffffffff) for m inbytes([int(bin(byte)[2::].zfill(8)[8::-1], 2) for byte in l.to_bytes(8, 'big')]): magic.value ^= c_uint64(m << 56).value for j inrange(8): if magic.value & 0x8000000000000000 != 0: magic.value = magic.value << 1 ^ 0x1b else: magic.value = magic.value << 1 magic.value ^= 0xffffffffffffffff t = bytes([int(bin(byte)[2::].zfill(8)[8::-1], 2) for byte inbytes(magic)]) t = aes(int(t.hex(), 16), self.keys[i]) & 0xffffffffffffffff t ^= aes(0xdeadbeefbaadf00dif i % 2else0xbaadf00ddeadbeef, self.keys[i]) & 0xffffffffffffffff l, r = r ^ t, l l ^= int.from_bytes(self.key[:8], 'big') r ^= int.from_bytes(self.key[8:], 'big') l, r = r, l y = (l + (r << 64)) & 0xffffffffffffffffffffffffffffffff return y
一个奇怪的Feistel结构,42轮密钥加密,提供了任意加密的功能。看起来无从下手,于是结合题目名搜了一会儿,发现了Big Brother Is Watching You_
A Closer Look at Backdoor
Construction,里面正好提到了Derek以及Feistel密码里存在的一种后门攻击。大致意思就是,Derek指代密码算法的设计者,在Feistel加密中故意留下一个后门用于窃取关键信息,而密码算法的使用者对此不得而知。论文里边提到了一种ZUGZWANG的Feistel网络,构造特定的输入可以使得每轮密文L部分陷入到两种不同的后门值中,一直持续到n轮结束,然后通过最后的密钥异或过程能提取出主密钥。
from pwn import * from Crypto.Util.number import * from ctypes import c_uint64 from Derek import Derek
context.log_level = 'debug'
sh=remote('94.74.90.243',42000) l64 = lambda :u64(sh.recvuntil("\x7f")[-6:].ljust(8,"\x00")) l32 = lambda :u32(sh.recvuntil("\xf7")[-4:].ljust(4,"\x00")) sla = lambda a,b :sh.sendlineafter(str(a),str(b)) sa = lambda a,b :sh.sendafter(str(a),str(b)) lg = lambda name,data : sh.success(name + ": 0x%x" % data) se = lambda payload: sh.send(payload) rl = lambda : sh.recvline() rv = lambda n : sh.recv(n) sl = lambda payload: sh.sendline(payload) ru = lambda a :sh.recvuntil(str(a)) rud = lambda a :sh.recvuntil(str(a),drop=True)
defgetinput(target): s=list(bytes.fromhex(target)) s[0]^=0x1b magic=int(''.join([ bin(b)[2::].zfill(8)[8::-1] for b in s][::-1]),2) magic = c_uint64(magic) magic.value ^= 0xffffffffffffffff t=magic.value ms=[] for i inrange(8): tmpm='' for j inrange(8): if t&1: t=((t^0x1b)>>1)|0x8000000000000000 t=t&0xffffffffffffffff tmpm+='1' else: t=t>>1 t=t&0xffffffffffffffff tmpm+='0' tmpm=int(tmpm[::-1],2) ms.append(tmpm^0xff) ms=ms[::-1] ms=bytes([ int(bin(m)[2::].zfill(8)[8::-1], 2) for m in ms]) ms=int.from_bytes(ms,'big') return ms
junk_msg = [os.urandom(120) for i inrange(65536)] for i inrange(len(msg)): junk_msg[i] = junk_msg[i][:i] + bytes([msg[i]]) + junk_msg[i][i+1:]
p = 990367536408524906540912485167816012092796554403092639917950993714265910699138052663068131070259292593771612112016905904144038137551264432483487958987773403759866096258076571660618998739176702013853258687325567753038298889168254166361474202422033630403618955865472205722190830457928271527937 g = 745013838642250986737914025336862504661062017981819269513542907265222774830330586097756124678061002877695509685688964126565784246358161149675046363463274308162223776270434432888284419417479549219965033745142547821863438374478028783067286583042510995247992045551680383288951502770625897136683
Zp = Zmod(p) g = Zp(g) junk_msg = [Zp(bytes_to_long(msg)) for msg in junk_msg] junk_cipher = []
for i inrange(65536): junk_cipher.append(ZZ(sum(junk_msg[j] * g^(i*j) for j inrange(65536))))
m = 10 t = ceil(tau * m) A = - ( (N - 1) ^ 2) f = u + A * x
defreplace_func(f): res=0 for coe,exp inzip(f.coefficients(),f.exponents()): mi=min(exp[0],exp[1]) tmp=coe * (u-1)^mi * x^(exp[0]-mi) * y^(exp[1]-mi) * u^exp[2] res+=tmp return res
polys=[] for k inrange(m + 1): for i inrange(m - k + 1): g = x^i * f^k * e^(m-k) polys.append(g)
for i inrange(1, t + 1): for k inrange(floor(m/t) * i, m + 1): h = y^i * f^k * e^(m-k) polys.append(replace_func(h))
print(len(polys))
monomials=[] for poly in polys: for v in poly.monomials(): if v notin monomials: monomials.append(v)
mat = [[0for j inrange(len(monomials))] for i inrange(len(polys))] print(monomials) for i, poly inenumerate(polys): for j, mono inenumerate(monomials): mat[i][j] = poly.monomial_coefficient(mono)*mono(X,Y,U)
#print(mat) mat = Matrix(ZZ, mat) mat = mat.LLL() #open('mat2.txt','w').write(str(list(mat))) #mat=eval(open('mat.txt','r').read()) print('LLL done!') pols = []
for i inrange(len(polys)): f = sum(mat[i][k] / monomials[k](X, Y, U) * monomials[k] for k inrange(len(monomials))) pols.append(f)
print(len(pols))
pols = [u-x*y-1]+pols #for i in range(len(pols)-1,3,-1): for i inrange(80,3,-1): print(i) try: v=Ideal(pols[:i]).variety(ring=ZZ) iflen(v)>0: print(v) y=int(v[0]['y']) pmq=sqrt(y) print(pmq) P.<p>=PolynomialRing(ZZ) f=p^2+p*pmq-N print(f.roots()) except Exception as e: print(e) pass
from Crypto.Util.number import * from tqdm import tqdm
lines=open('output3.txt','r').readlines() cs=[ int(lines[i].strip()) for i inrange(65536)] exec(lines[65537].strip()) exec(lines[65538].strip())
P=10145464108117104946528925393253025011804035401616805446033365549148734952013370668386041469047007957274792466373040522919369708124243037663040944850113697 Q=N//P d=inverse(e,(P-1)*(Q-1)) ZN=Zmod(N) n=65536 jc=[pow(c,d,N) for c in cs[:n]] #open('jc.txt','w').write(str(jc)) #jc=eval(open('jc.txt','r').read()) print('-----') p = 990367536408524906540912485167816012092796554403092639917950993714265910699138052663068131070259292593771612112016905904144038137551264432483487958987773403759866096258076571660618998739176702013853258687325567753038298889168254166361474202422033630403618955865472205722190830457928271527937 g = 745013838642250986737914025336862504661062017981819269513542907265222774830330586097756124678061002877695509685688964126565784246358161149675046363463274308162223776270434432888284419417479549219965033745142547821863438374478028783067286583042510995247992045551680383288951502770625897136683 Zp = Zmod(p) g = Zp(g)
flag=b'' jc=vector(Zp,jc) for i inrange(100): print(i) v=Zp(n)^-1*vector(Zp,[ g^-(i*j) for j inrange(n)]) jm=long_to_bytes(int(v*jc)) flag+=bytes([jm[i]]) print(flag) print(flag) #RCTF{G00d_J06_UR_cRypT0_ma5T3r__1997_L0VE_ZMJ_FOR3VER}
from Crypto.Util.number import getPrime, inverse, bytes_to_long
withopen('flag.txt', 'rb') as f: flag = f.read()
defv(k): if k == 0: return2 if k == 1: return r return (r * v(k - 1) - v(k - 2)) % (N * N)
defencrypt(m, e, N): c = (1 + m * N) * v(e) % (N * N) return c
p = getPrime(512) q = getPrime(512) N = p * q d = getPrime(512) r = getPrime(512) e = inverse(d, (p * p - 1) * (q * q - 1)) c = encrypt(bytes_to_long(flag), e, N) print(f"e = {e}") print(f"c = {c}") print(f"N = {N}")
from Crypto.Util.number import * from gmpy2 import iroot from tqdm import tqdm
e = 3121363059746835628022404544403822724460605553641332612055010587129451973002475126644668174294955070747985002800863652917895939538596303356113483509581841527286351537287500304267975061675901109982875778527827742120878835367386538561039072391997357702421691095861694681707017921391244519593945584755632901987840338065879901115934561426583008838453244051629340056867760923894623105542463500022221236457852502822707466528439969484890601953615303609725566617126458934095119670087068752543521167517461730977044465374505011791902510131823556603316457085145886999220426746234986984619161299098173535371540923264898459106461 c = 3023313363629909506923927199426293187583112749147539699346723655095868214179291222441307436555352537055690155418715652987685459938250844145450675418187664719327350488160722838989675928696633353180233455017609936874014883975932740217672705286265535646106053294507962613498142617741362730709360885118905440314573392981528077265110441270212385951070591696827167771592664502652520790612367259434545169836933571343480057141790292296952743986731389468760364416344837575740236416472589700581583016227273449673820568427641136163703116276104550877191839851640920430919278802098196408637904780725723268371465670950321881886863 N = 101946888552605033726177837709738163930032970477361664394564134626639467843553634920510447339985842689387519517553714582991506722045078696771986052246306068257957261478416093188640437503481862825381241480405463985516598520453211217206308826779669980833596066677262549841524134539729279446910817169620871929289
c = continued_fraction(e/(N^2 - 9*N//4 + 1)) p,q = var('p q') f1 = p * q - N for i in tqdm(range(2,len(c))): k = c.numerator(i) d = c.denominator(i) w = (e * d - 1) // k if (N+1)^2 - w + 1 < 0: continue if iroot((N+1)^2 - w ,2)[1]: print(int(d).bit_length()) W = int(iroot((N+1)^2 - w ,2)[0]) f2 = p + q - W print(solve([f1,f2],[p,q])) break
p = 11183005686209595001928972121695860070092013480977374483129957127854844677143979460482157275466240702921372008061294251388860670887956597721784208073814949 q = 9116233275131173602739752692268079943189703035300573582575042083296621527313939933344455320687281588438414528000594454794847729159565419506066306192152661
e = 3121363059746835628022404544403822724460605553641332612055010587129451973002475126644668174294955070747985002800863652917895939538596303356113483509581841527286351537287500304267975061675901109982875778527827742120878835367386538561039072391997357702421691095861694681707017921391244519593945584755632901987840338065879901115934561426583008838453244051629340056867760923894623105542463500022221236457852502822707466528439969484890601953615303609725566617126458934095119670087068752543521167517461730977044465374505011791902510131823556603316457085145886999220426746234986984619161299098173535371540923264898459106461 c = 3023313363629909506923927199426293187583112749147539699346723655095868214179291222441307436555352537055690155418715652987685459938250844145450675418187664719327350488160722838989675928696633353180233455017609936874014883975932740217672705286265535646106053294507962613498142617741362730709360885118905440314573392981528077265110441270212385951070591696827167771592664502652520790612367259434545169836933571343480057141790292296952743986731389468760364416344837575740236416472589700581583016227273449673820568427641136163703116276104550877191839851640920430919278802098196408637904780725723268371465670950321881886863 N = 101946888552605033726177837709738163930032970477361664394564134626639467843553634920510447339985842689387519517553714582991506722045078696771986052246306068257957261478416093188640437503481862825381241480405463985516598520453211217206308826779669980833596066677262549841524134539729279446910817169620871929289 d = int(inverse(e,(p**2-1)*(q**2-1)))
defseq(r , k , n): init_v = vector(Zmod(n) , [2 , r]) M = Matrix(Zmod(n) , [ [0 , -1], [1 , r ] ]) ret = ( init_v * M^(k-1))[1] return ret
from Crypto.Util.number import getPrime, bytes_to_long from random import randint, choices from string import ascii_uppercase, digits import signal
withopen('flag.txt', 'rb') as f: flag = f.read()
signal.alarm(300)
q = getPrime(160) whileTrue: key = "rctf_" + "".join(choices(ascii_uppercase + digits, k=15)) x = bytes_to_long("".join(sorted(key)).encode()) if x < q: break l = 2 T = [] U = [] for i inrange(90): t = randint(1, q) #u = (x * t - randint(1, q >> l)) % q u = x * t - randint(1, q >> l) T.append(t) U.append(u)