from random import randrange from Crypto.Util.number import * from gmpy2 import * from flag import flag
m1 = flag[:len(flag)//2] m2 = flag[len(flag)//2:]
defgcd(a,b): while b: a,b = b,a%b return a
e = 196611 t = getPrime(1024) whileTrue: p = getPrime(512) q = getPrime(512) if p > (t//2)**(0.5) or q > (t//2)**(0.5) or q < (t//4)**(0.5): continue if gcd(p,t)==1and gcd(p,q)==1: break
n = p*q a = inverse(p,t) b = a*q % t
x = randrange(1, (t//2)**(0.5)) c1 = pow(bytes_to_long(m1), e, n) c2 = (x*b+bytes_to_long(m2)) % t
from Crypto.Util.number import * import gmpy2 e = 196611 n = 65923160983714159174054470515573655706226330836484887232047084356206551027110611733852661357129720187920709446876218553615531690351151400345537469812811754017254876997964169603223262682390304358781343907306701677293241401311458582376923692545390056409390040815766533450665171898894960981350098449471585835983 t = 156735006421025159162464822189709647625666833755415833041315380970290330967501247763901201324107388364754932161997024416664716046695306206076067986718008348395105538562568685715810261941446669628131228936345994680854906523779208112907313194284266511667655498806866506447714590977347633499249461638469397646143 b = 102828034489985130292237328415914374036194592912123145515988805200145853584202889332537743985786669465808768348444018770207326799609832768446997902851310627183128143736647178489337894207754483450029034766480012064411339544711254824382201113260666700562674152083497595259510709102443621597274104424732970983346 c1 = 53919877044806667590191317976457216703097157378893548902917302837026217993556841959874040719754382894805766098772727554793887109758342211929068651122821912401228458881370271005861714431415278512010429891161410017074563692738062898727179931757587022730420443768861148908495675732837105452751476067158477074416 c2 = 93209672266652558201721906871222852586159974489807496213149282485691823460173568938838492468817777256382818737811311622582977800840264981574839834478715137925028333166737702156942511501971498573467635899900227942924329380167513249979806622469774326486417222407610460860379054991133760924378877816208820000726 PR.<a> = PolynomialRing(Zmod(t)) f = a ** 2 * n - b root = f.roots() print(root) #[(116231959510358160812755793831584335959100766156535932861226868172580463216816375971999356944597603556117791659485819216769100213826425384473081766229007741782651362591487751335698862068456452058850711298569225829628888753311404538439325209285849892423108708117681509739698109141926240416541118397102587818568, 1), (40503046910666998349709028358125311666566067598879900180088512797709867750684871791901844379509784808637140502511205199895615832868880821602986220489000606612454175971080934380111399872990217569280517637776768851226017770467803574467987984998416619244546790689184996708016481835421393082708343241366809827575, 1)]
a 是质数,所以后面那个是 a,之后用 a 分解 n。发现 e 和 phi 公约数是 3,比较小,用 sage 的 roots 函数就可以解
a = 40503046910666998349709028358125311666566067598879900180088512797709867750684871791901844379509784808637140502511205199895615832868880821602986220489000606612454175971080934380111399872990217569280517637776768851226017770467803574467987984998416619244546790689184996708016481835421393082708343241366809827575 p = gmpy2.invert(a,t) q = n // p phi = (p - 1) * (q - 1)
d = gmpy2.invert(e // 3,phi) c = pow(c1,d,n) flag1 = b'' R.<x> = Zmod(p)[] f = x ^ 3 - c f = f.monic() res1 = f.roots() R.<x> = Zmod(q)[] f = x ^3 - c f = f.monic() res2 = f.roots() for i in res1: for j in res2: ai = [int(i[0]),int(j[0])] mi = [p,q] flag = CRT_list(ai,mi) flag = long_to_bytes(flag) ifb'flag'in flag: flag1 = flag break print(flag1) #b'flag{9ad0f091075c06'
from secret import flag from Crypto.Util.number import * assert(flag[:5]=='flag{') flag = flag[5:-1] num1 = bytes_to_long(flag[:7]) num2 = bytes_to_long(flag[7:14]) num3 = bytes_to_long(flag[14:])
defECC1(num): p = 146808027458411567 A = 46056180 B = 2316783294673 E = EllipticCurve(GF(p),[A,B]) P = E.random_point() Q = num*P print E print'P:',P print'Q:',Q
defECC2(num): p = 1256438680873352167711863680253958927079458741172412327087203 #import random #A = random.randrange(389718923781273978681723687163812) #B = random.randrange(816378675675716537126387613131232121431231) A = 377999945830334462584412960368612 B = 604811648267717218711247799143415167229480 E = EllipticCurve(GF(p),[A,B]) P = E.random_point() Q = num*P print E print'P:',P print'Q:',Q factors, exponents = zip(*factor(E.order())) primes = [factors[i] ^ exponents[i] for i inrange(len(factors))][:-1] print primes dlogs = [] for fac in primes: t = int(int(P.order()) / int(fac)) dlog = discrete_log(t*Q,t*P,operation="+") dlogs += [dlog] print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order print num print crt(dlogs,primes)
defECC3(num): p = 0xd3ceec4c84af8fa5f3e9af91e00cabacaaaecec3da619400e29a25abececfdc9bd678e2708a58acb1bd15370acc39c596807dab6229dca11fd3a217510258d1b A = 0x95fc77eb3119991a0022168c83eee7178e6c3eeaf75e0fdf1853b8ef4cb97a9058c271ee193b8b27938a07052f918c35eccb027b0b168b4e2566b247b91dc07 B = 0x926b0e42376d112ca971569a8d3b3eda12172dfb4929aea13da7f10fb81f3b96bf1e28b4a396a1fcf38d80b463582e45d06a548e0dc0d567fc668bd119c346b2 E = EllipticCurve(GF(p),[A,B]) P = E.random_point() Q = num*P print E print'P:',P print'Q:',Q
#part1 p = 146808027458411567 a = 46056180 b = 2316783294673 E = EllipticCurve(GF(p),[a,b]) P = E(119851377153561800,50725039619018388) Q = E(22306318711744209,111808951703508717) flag1 = P.discrete_log(Q) # print(long_to_bytes(flag1))
#part2 p = 1256438680873352167711863680253958927079458741172412327087203 a = 377999945830334462584412960368612 b = 604811648267717218711247799143415167229480 E = EllipticCurve(GF(p),[a,b]) P = E(550637390822762334900354060650869238926454800955557622817950,700751312208881169841494663466728684704743091638451132521079) Q = E(1152079922659509908913443110457333432642379532625238229329830,819973744403969324837069647827669815566569448190043645544592)
#part3 p = 11093300438765357787693823122068501933326829181518693650897090781749379503427651954028543076247583697669597230934286751428880673539155279232304301123931419 a = 490963434153515882934487973185142842357175523008183292296815140698999054658777820556076794490414610737654365807063916602037816955706321036900113929329671 b = 7668542654793784988436499086739239442915170287346121645884096222948338279165302213440060079141960679678526016348025029558335977042712382611197995002316466 E = EllipticCurve(GF(p),[a,b]) P = E(10121571443191913072732572831490534620810835306892634555532657696255506898960536955568544782337611042739846570602400973952350443413585203452769205144937861,8425218582467077730409837945083571362745388328043930511865174847436798990397124804357982565055918658197831123970115905304092351218676660067914209199149610) Q = E(964864009142237137341389653756165935542611153576641370639729304570649749004810980672415306977194223081235401355646820597987366171212332294914445469010927,5162185780511783278449342529269970453734248460302908455520831950343371147566682530583160574217543701164101226640565768860451999819324219344705421407572537)
defSmartAttack(P,Q,p): E = P.curve() Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ])
P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True) for P_Qp in P_Qps: if GF(p)(P_Qp.xy()[1]) == P.xy()[1]: break
Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True) for Q_Qp in Q_Qps: if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]: break
#!/usr/bin/env python3 from random import randrange from Crypto.Cipher import AES
p = 193387944202565886198256260591909756041
i = lambda x: pow(x, p-2, p)
defadd(A, B): (u, v), (w, x) = A, B assert u != w or v == x if u == w: m = (3*u*w + 4*u + 1) * i(v+x) else: m = (x-v) * i(w-u) y = m*m - u - w - 2 z = m*(u-y) - v return y % p, z % p
defmul(t, A, B=0): ifnot t: return B return mul(t//2, add(A,A), B ifnot t&1else add(B,A) if B else A)
defadd(A, B): (u, v), (w, x) = A, B assert u != w or v == x if u == w: m = (3*u*w + 4*u + 1) * i(v+x) else: m = (x-v) * i(w-u) y = m*m - u - w - 2 z = m*(u-y) - v return y % p, z % p
其中 if u == w: m = (3*u*w + 4*u + 1) * i(v+x) ,函数 i 为求逆元,通过对此判别式积分可以推算出曲线方程为y2=x3+2x2+x+C,又因为点 (4,10) 在曲线上,可以得出C=0,则曲线方程为y2=x3+2x2+x。其存在奇点(−1,0)。
#sage p = 193387944202565886198256260591909756041 # P.<x> = GF(p)[] PR.<x> = PolynomialRing(Zmod(p)) f = x ** 3 + 2 * x ** 2 + x P = (4,10) Q = (65639504587209705872811542111125696405,125330437930804525313353306745824609665) # root = f.roots() # print(root) #Singular point (-1,0) k = 193387944202565886198256260591909756040 ff = f.subs(x = x - 1) print(ff.factor()) #(x + 193387944202565886198256260591909756040) * x^2 PP = (P[0] - 193387944202565886198256260591909756040,P[1]) QQ = (Q[0] - 193387944202565886198256260591909756040,Q[1]) t = GF(p)(193387944202565886198256260591909756040).square_root()
u = (PP[1] + t * PP[0]) / (PP[1] - t * PP[0]) % p v = (QQ[1] + t * QQ[0]) / (QQ[1] - t * QQ[0]) % p x = v.log(u) #x = 4470735776084208177429085432176719338
结果发现用这个 x 无法求出 flag,说明还要算上阶,最后得到 flag
1 2 3 4 5 6 7 8 9 10 11 12 13
#sage x = 4470735776084208177429085432176719338 print(x) kk=u.multiplicative_order() enc = bytes.fromhex('b3669dc657cef9dc17db4de5287cd1a1e8a48184ed9746f4c52d3b9f8186ec046d6fb1b8ed1b45111c35b546204b68e0') whileTrue: x += kk if x > p: break aes = AES.new(long_to_bytes(x),AES.MODE_CBC,bytes(16)) flag = aes.decrypt(enc) print(flag) b'rwctf{Singular_Elliptic_Curve_is_easy_to_break} '
from Crypto.Util.number import * from flag import flag
key = bytes_to_long(flag) f = open('message.txt','r').read().split('\n') cipher = open('cipher.txt','w') for i in f: i = bytes_to_long(i.encode()) c = i ^ key cipher.write(hex(c)[2:]+'\n') cipher.close()
import Crypto.Util.strxor as xo import libnum, codecs, numpy as np
defisChr(x): iford('a') <= x and x <= ord('z'): returnTrue iford('A') <= x and x <= ord('Z'): returnTrue returnFalse
definfer(index, pos): if msg[index, pos] != 0: return msg[index, pos] = ord(' ') for x inrange(len(c)): if x != index: msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')
defknow(index, pos, ch): msg[index, pos] = ord(ch) for x inrange(len(c)): if x != index: msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(ch)
dat = []
defgetSpace(): for index, x inenumerate(c): res = [xo.strxor(x, y) for y in c if x!=y] f = lambda pos: len(list(filter(isChr, [s[pos] for s in res]))) cnt = [f(pos) for pos inrange(len(x))] for pos inrange(len(x)): dat.append((f(pos), index, pos))
c = [codecs.decode(x.strip().encode(), 'hex') for x inopen('cipher.txt', 'r').readlines()] print(c) msg = np.zeros([len(c), len(c[0])], dtype=int)
getSpace()
dat = sorted(dat)[::-1] for w, index, pos in dat: infer(index, pos)
import gmpy2 from Crypto.Util.number import * p = 157528135408677299394292236808407130951620182277485861264162367221003923311026835340974796733969066338128486003687892984888625395846811728890576334899010454107820204146796395164875654422020481368009883567020291526109447619934985261676396363315066221941991907441551816700543054518214048084585510572273143302929 q = 1442705299941797183684818615170726432069333234814734331406043466619811163894111214168224392907643854069 c = 133435253885105904681139014309955886539710389070811311502821772509611736349656307170673935962481372815353262899448626430304691786429011183960239913678295381009683495881961582566729076446859372293063364241805786413804485568317533502444560563638886447542766320382309683259017825708340404274999458766205770820533 u = 120769987044261474693385398937509234270805384830942774998331036756015602254500864686090818859805146371437761470282545762646846799062287962879226076629580866415238728781778876557024691706000280566550610727659583989813062963375313642707997246101611714406510716765838248871330574233154650330128833595352286430109 mat = [ [u,0,0], [p,1,0], [c,0,1] ] mat = matrix(ZZ,mat) s = int(mat.LLL()[0][0]) t = (c - s) * gmpy2.invert(u,p) % p e = gmpy2.invert(t,q) d = gmpy2.invert(e,q - 1) m = pow(s,d,q) assert c == (inverse(e, q) * u + pow(m, e, q)) % p for i inrange(100): ans = m + i * q flag = long_to_bytes(ans) ifb'ISCTF'in flag: print(flag)
defGenerateRSAKey(): n, phi = 1, 1 for i inrange(4): whileTrue: p = getPrime(1000) if isPrime(p): break n *= p phi *= (p - 1) e = getPrime(randint(20, 24)) d = inverse(e, phi) return n, e, d
classTask(socketserver.BaseRequestHandler): def_recvall(self): BUFF_SIZE = 9182 data = b'' whileTrue: part = self.request.recv(BUFF_SIZE) data += part iflen(part) < BUFF_SIZE: break return data.strip()
defprintf(self, msg, newline=True): if newline: msg += "\n" self.request.sendall(msg.encode())
defhandle(self): signal.alarm(1200) self.printf(banner) n, e, d = GenerateRSAKey() flag = _flag flag = bytes_to_long(os.urandom(390) + b" " + flag.encode() + b" " + os.urandom(30)) for ___ inrange(1607087): self.printf(menu) try: op = int(self.scanf()) if op == 1: self.printf(f"n={n}") self.printf(f"e={e}") self.printf(f"c={pow(flag, e, n)}") elif op == 2: m = int(self.scanf("Enter your plaintext in decimal format >")) c = pow(m, e, n) msg = long_to_bytes(c).hex()[-2:] self.printf(f"The last byte of your Ciphertext is: {msg}") elif op == 3: c = int(self.scanf("Enter your ciphertext in decimal format >")) m = pow(c, d, n) msg = long_to_bytes(m).hex()[-2:] self.printf(f"The last byte of your Plaintext is: {msg}") else: break except: self.printf("Wrong Input") break self.printf("Quitting...")
if __name__ == "__main__": HOST, PORT = '0.0.0.0', 10003 server = ForkedServer((HOST, PORT), Task) server.allow_reuse_address = True print("Server at 0.0.0.0 port " + str(PORT)) server.serve_forever()
详细参考 RSA LSB Oracle 攻击原理分析,大概介绍一下题目。
一个 RSA 系统,首先给出初始的公钥 (n,e) 及公钥加密信息之后得到的密文 c,之后与系统交互,构造密文 c 与靶机交互,给出密钥解密后明文 m 的最后一字节 (可以理解成最后 256 位)。也可以构造明文 m 与靶机交互,给出明文加密后密文 c 的最后一字节 (用处不大,毕竟这个环节本地都能运算)。
参考了资料之后,应该这样理解这个密码系统。
首先将明文 m 转化成 256 进制,即m=256nan+256n−1an−1+256n−2an−2+⋯+2562a2+2561a1+2560a0,问题转化求所有的 a。
import gmpy2 from pwn import * from Crypto.Util.number import * defgetinit(): r.recvuntil(b'> ') r.send(b'1') r.recvuntil(b'n=') n = int(r.recvline()[:-1].decode()) r.recvuntil(b'e=') e = int(r.recvline()[:-1].decode()) r.recvuntil(b'c=') c = int(r.recvline()[:-1].decode()) return n,e,c
defgetm(c): r.recvuntil(b'> ') r.send(b'3') r.recvuntil(b"Enter your ciphertext in decimal format >") r.send(str(c).encode()) r.recvuntil(b'The last byte of your Plaintext is: ') m = int(r.recvline()[:-1].decode(),16) return m
r = remote('124.223.224.73',10003) n,e,c = getinit() Mod = 256 inv = gmpy2.invert(Mod,n) cnt = 0 flag = 0 pad = 0 ans = 0 whileTrue: cc = pow(inv,e * cnt,n) * c % n mm = getm(cc) ans = (mm - (inv * pad) % n) % Mod pad = pad * inv + ans flag += ans * Mod ** cnt cnt += 1 print(cnt,long_to_bytes(flag)) ifb'0xGame'in long_to_bytes(flag): print(long_to_bytes(flag)) break r.interactive()
from Crypto.Util.number import * # from secret import flag flag = b'flag{*****}' p = getPrime(512) q = getPrime(512) while q > p: q = getPrime(512) a = getPrime(1023) b = getPrime(1023) e = 65537 n = p * q r = p - q t = (a * pow(r,3,n) + b * r + 1) % n q_high = q >> 300 c = pow(bytes_to_long(flag),e,n)
构造s2q≡ng−1modN,同余式右边全为已知量。且 N 值过大,同余式左边不发生取模,为真实值,之后再 gcd 即可的得到 q 的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
from Crypto.Util.number import * import gmpy2 e = 0x10001 N = 19351301035801508116955552063316327463227928638319284082504070745230119792307421099534903837766317639913937954784857576991401214861067471772614753337821871108189780331081099041824669243928056765115068764246765680962348646383991303828426125303844394268682191775232611288039200316595279055408827296256289143602827525373267536643865729646353071637054367702218515803980122435811129935450486950137279824491461041391572264371799797200331838690523349105589985032730668315787318829244743317257793753147209875458127340875400367081865762286565978620979196410411241442894450955280237513249393612603560410291825805553536595543937 g = 101172011079013273946711882340439823149055809449035744718659818796135714101721641190114954130041477714466321498903210220694435354795744225843314447645623337668697058127975104586375292636080114347294697007231487782548846095107329445479367324424672776003899748234353857872627585595343736452088156885081907758727085723312506489549364721644636251780350312413098132506051531311685636921117457469745637347738336829350634994271419554741425590636953154753970902976959308323838617091060754826727417688836026597614894745348808019654100196615719730109909578899299246848916182034705259206906552769087038179288139086772719994577168184701096922291610523676039127012518100023765548552210944426749474888311751069936144583375194023227887848704267587915237057432609663328145608194550736074250822416779448467084842127165553649513397606464059847361880649213934069715996589751778384513724306521043255299443480482640183740131563318058454711913397533436985618182923646192481486120942073719321372236539019107909910597047133371708017755744495134116771999521953654596632221519266339372439452558083199640035069852530373510758859460350025736629801086757717838159774542506755335660607766677992105601518694405113552321342152041808586187181800679845672788746273313 n = 90106928919727272173474070618911951313216606598108495724382284361415375454490594410306345748069424740100772955015304592942129026096113424198209327375124576666577469761124470792842854884924199449996929134613382626394351988541980388358156143332979538058465890179760337315789398915560641465656968797050755849799 c = 51609249982849856103564442566936515708380814106997783395400669324617748952940831076546581735494963467680719842859574144530848473300102236821201997786375946601413660428461473204032985053128283751860315027843200214217715401391736262811016964783589439740884991543059175666298728428567481043422497862838127903980 tmp = n * gmpy2.invert(g,N) % N q = gmpy2.gcd(tmp,n) p = n // q phi = (p - 1) * (q - 1) d = gmpy2.invert(e,phi) m = pow(c,d,n) print(long_to_bytes(m))
格子的做法是,构造等式s2g=p+kN,其中 g,N 为已知值构造格
[s2k][gN10][ps2]
之后格基规约即可得到p 和s2,exp 如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
from Crypto.Util.number import * import gmpy2 e = 0x10001 N = 19351301035801508116955552063316327463227928638319284082504070745230119792307421099534903837766317639913937954784857576991401214861067471772614753337821871108189780331081099041824669243928056765115068764246765680962348646383991303828426125303844394268682191775232611288039200316595279055408827296256289143602827525373267536643865729646353071637054367702218515803980122435811129935450486950137279824491461041391572264371799797200331838690523349105589985032730668315787318829244743317257793753147209875458127340875400367081865762286565978620979196410411241442894450955280237513249393612603560410291825805553536595543937 g = 101172011079013273946711882340439823149055809449035744718659818796135714101721641190114954130041477714466321498903210220694435354795744225843314447645623337668697058127975104586375292636080114347294697007231487782548846095107329445479367324424672776003899748234353857872627585595343736452088156885081907758727085723312506489549364721644636251780350312413098132506051531311685636921117457469745637347738336829350634994271419554741425590636953154753970902976959308323838617091060754826727417688836026597614894745348808019654100196615719730109909578899299246848916182034705259206906552769087038179288139086772719994577168184701096922291610523676039127012518100023765548552210944426749474888311751069936144583375194023227887848704267587915237057432609663328145608194550736074250822416779448467084842127165553649513397606464059847361880649213934069715996589751778384513724306521043255299443480482640183740131563318058454711913397533436985618182923646192481486120942073719321372236539019107909910597047133371708017755744495134116771999521953654596632221519266339372439452558083199640035069852530373510758859460350025736629801086757717838159774542506755335660607766677992105601518694405113552321342152041808586187181800679845672788746273313 n = 90106928919727272173474070618911951313216606598108495724382284361415375454490594410306345748069424740100772955015304592942129026096113424198209327375124576666577469761124470792842854884924199449996929134613382626394351988541980388358156143332979538058465890179760337315789398915560641465656968797050755849799 c = 51609249982849856103564442566936515708380814106997783395400669324617748952940831076546581735494963467680719842859574144530848473300102236821201997786375946601413660428461473204032985053128283751860315027843200214217715401391736262811016964783589439740884991543059175666298728428567481043422497862838127903980 mat = matrix(ZZ,[[g,1],[N,0]]).LLL() print(mat) p = abs(mat[0][0]) assert n % p == 0 q = n // p phi = (p - 1) * (q - 1) d = gmpy2.invert(e,phi) m = int(pow(c,d,n)) print(long_to_bytes(m))
defhandle(): print("Welcome to Lazy platform! If you want to decrypt some messages, you can't do that here, you'll have to do it on your own")
whileTrue: print("Choose one of the following options") print("[1] Encrypt") print("[2] Decrypt") print("[3] Get encrypted flag") print("[4] Exit") option = input("> ")
if option == "1": message = input("Enter a message to encrypt: ") key = getrandbytes(32) iv = getrandbytes(16) ciphertext = AES.new(key, AES.MODE_CBC, iv).encrypt( pad(message.encode(), AES.block_size)) print("Ciphertext:", ciphertext.hex()) print("Key:", key.hex()) print("IV:", iv.hex()) elif option == "2": print("I can't do that at the moment, I'm cooking a pizza") elif option == "3": key = getrandbytes(32) iv = getrandbytes(16) ciphertext = AES.new(key, AES.MODE_CBC, iv).encrypt( pad(FLAG, AES.block_size)) print("Ciphertext:", ciphertext.hex()) elif option == "4": print("Bye bye!\n") break else: print("Invalid option") print()
if __name__ == "__main__": signal.alarm(TIMEOUT) handle()
程序的逻辑很简单,一个交互题,其中就两个选项有用,其中一个加密自己给出的明文,另一个给你 flag 的密文,通过 aes 加密,值得注意的是,可以无限次交互,限定了时间应该只是确保你是用程序去实现交互的。
当选择加密自己的明文时,题目会把加密用的 key 和 iv 给你,也就是说可以获得很多组 key 和 iv,明文随便选就好。注意一下函数 getrandbytes
num = [......] rc = RandCrack() [rc.submit(i) for i in num] # print(hex(rc.predict_getrandbits(64))[2:])#18a3217abb50885a print(hex(rc.predict_getrandbits(48))[2:])#18a3bb50885a
from gmpy2 import invert from Crypto.Util.number import * defbaby_step_giant_step(step, modulo, ct, pt): known_small_powers = {1: 0} prev = 1 for i inrange(1, step): curr = (prev * pt) % modulo known_small_powers[curr] = i prev = curr subtractor = inverse_mod(power_mod(pt, step, modulo), modulo) x = ct i = 0 while x notin known_small_powers: i += 1 x = (x * subtractor) % modulo return step * i + known_small_powers[x]
defpohlig_hellman(g, c, s, n, factors): res = [0] * len(factors) modulus = [] for i, (q, e) inenumerate(factors): for j inrange(e): gi = power_mod(g, s // q, n) ci = power_mod(c * power_mod(inverse_mod(g, n), res[i], n),s // q**(j + 1), n) dlogi = baby_step_giant_step(isqrt(q), n, ci, gi) res[i] += dlogi * (q**j) res[i] = res[i] % (q**e) modulus.append(q**e) print("[+] dlog modulo {0} == {1}".format(q**e, res[i])) print(long_to_bytes(res[i])) exit() print("\n[*] res = ", res) print("[*] modulus = ", modulus) dlog = CRT(res, modulus) print("\n[+] dlog modulo {0} == {1}".format(prod(modulus), dlog)) return dlog deffind_order(g, s, ff): for p, e in ff: while s % p == 0and power_mod(g, s // p, n) == 1: s //= p ifnot power_mod(g, s, n) == 1: s *= p return s
g = 3 s = 0xb4ec8caf1c16a20c421f4f78f3c10be621bc3f9b2401b1ecd6a6b536c9df70bdbf024d4d4b236cbfcb202b702c511aded6141d98202524709a75a13e02f17f2143cd01f2867ca1c4b9744a59d9e7acd0280deb5c256250fb849d96e1e294ad3cf787a08c782ec52594ef5fcf133cd15488521bfaedf485f37990f5bd95d5796b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 n = 0xb4ec8caf1c16a20c421f4f78f3c10be621bc3f9b2401b1ecd6a6b536c9df70bdbf024d4d4b236cbfcb202b702c511aded6141d98202524709a75a13e02f17f2143cd01f2867ca1c4b9744a59d9e7acd0280deb5c256250fb849d96e1e294ad3cf787a08c782ec52594ef5fcf133cd15488521bfaedf485f37990f5bd95d5796b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ff = [ (2, 1024), (127049168626532606399765615739991416718436721363030018955400489736067198869364016429387992001701094584958296787947271511542470576257229386752951962268029916809492721741399393261711747273503204896435780180020997260870445775304515469411553711610157730254858210474308834307348659449375607755507371266459204680043,1) ] for p, e in ff: assert power_mod(g, s // p, n) != 1 assert power_mod(g, s, n) == 1 c = 0xaf99914e5fb222c655367eeae3965f67d8c8b3a0b3c76c56983dd40d5ec45f5bcde78f7a817dce9e49bdbb361e96177f95e5de65a4aa9fd7eafec1142ff2a58cab5a755b23da8aede2d5f77a60eff7fb26aec32a9b6adec4fe4d5e70204897947eb441cc883e4f83141a531026e8a1eb76ee4bff40a8596106306fdd8ffec9d03a9a54eb3905645b12500daeabdb4e44adcfcecc5532348c47c41e9a27b65e71f8bc7cbdabf25cd0f11836696f8137cd98088bd244c56cdc2917efbd1ac9b6664f0518c5e612d4acdb81265652296e4471d894a0bd415b5af74b9b75d358b922f6b088bc5e81d914ae27737b0ef8b6ac2c9ad8998bd02c1ed90200ad6fff4a37 dlog = pohlig_hellman(g, c, s, n, ff)
N = 1024 p = getPrime(N) q = getPrime(N) assert GCD(p * q, (p - 1) * (q - 1)) == 1
n = p * q s = n ** 2 λ = (p - 1) * (q - 1) // GCD(p - 1, q - 1) g = getRandomRange(1, s) L = lambda x : (x - 1) // n μ = pow(L(pow(g, λ, s)), -1, n)
defencrypt(m): r = getRandomRange(1, n) c = (pow(g, m, s) * pow(r, n, s)) % (s) return c
defdecrypt(c): m = (L(pow(c, λ, s)) * μ) % n return m
print(f"public key (n, g) = ({n}, ?)") print(f"E(4) = {encrypt(4)}") print() print("Encrypt 'Please give me the flag' for your flag:") c = int(input()) m = decrypt(c)
if long_to_bytes(m) == b"Please give me the flag": print("Okay!") withopen("flag.txt") as f: print(f.read()) else: print("Hmm... not quite.")
第一次接触同态加密的签名题,这个 Paillier 密码系统 wiki 里面也介绍的很详细。来看加同态加密的加法和乘法
D(E(m1,r1)×E(m2,r2)modn2)=m1+m2modn
D(E(m1,r1)×gm2modn2)=m1+m2modn
D(E(m1,r1)m2modn2)=m1m2modn
D(E(m,r)kmodn2)=kmmodn
回到本题,题目给的条件有 E (4) 和 n 已经待签名的值 m,需要构造一个 ans 满足D(ans)=mmodn,由于 g 未知,不能通过加法构造,又因为待签名值 m 为奇数,只能构造D(E(4,r)−4n−mmodn2))=mmodn,且需满足 n-m%4==0,如果取不到合适的数据就接着取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from Crypto.Util.number import * import gmpy2 from pwn import * context(log_level = 'debug') whileTrue: r = remote('tjc.tf',31996) r.recvuntil(b'public key (n, g) = (') line = r.recvline()[:-1].decode() n = int(line[:line.find(',')]) r.recvuntil(b'E(4) = ') e4 = int(r.recvline()[:-1].decode()) m = bytes_to_long(b'Please give me the flag') if (n - m) % 4 == 0: ans = pow(e4,-(n - m) // 4,pow(n,2)) r.recvuntil(b'Encrypt \'Please give me the flag\' for your flag:') r.sendline(str(ans).encode()) r.interactive() else: continue
果然是题目做少了,这题给了一个加密之后的点,给了公钥 n,e,第一步考虑的就是能不能把 n 分解出来。当时做题的时候没注意,除了给了 p 和 q 的位数,还可以通过代入加密点的方法再得到一组关系从而求解出 q,就可以把 n 给分解出。椭圆曲线可变换为2x3−2y2+2xq+q−1≡0(modp)
之后 cop 可以得到 q 的结果
1 2 3 4 5 6 7 8 9 10
from Crypto.Util.number import * import gmpy2 x,y = (338555080220637081961629108201515088631648910827927160728143665306856840891283037339677849661861227903908933145477264046446986150577658634798201036502060805774599658207669111688439996110692201008037849119605962378316457201998475046620515963725786423440494993922281942396227626532022005579340476627086260000576524772862121364339849726687865874619472513654142054490221489754144358483093331358263771080584662872680106076787261957704707055652825959314984924849600101, 936859805496385391559236776246883920797971062581544240268575675825570737296851006237870839271568976317212531276234406232945021531066674291887782791534409966305833225084692612867437424551505174720475931132798839349207246806850341280754752239303350596733681932273450149927797735966407187594725231158980098119489003450563623494155562513634618466910170109518754662675054081897025489520391417883488720972781393802142478712026232107041683271177224983497203599032383279) n = 988000511804778695813521569460767024014375863209856154754147082419975777208656083311740358048468580712106204105426217752071608551112269505247365548210006567296850568411531004204795967810292432041395592133501302461324005142940183488044983348152371980166614840414803124031222965874472013554869981954785271467321919039144942853506143787908194930700818770224752026306092706366253640515130802157497666497193713819097381223915943111321812676982912146706199692543488639 e = 0x10001 PR.<q> = PolynomialRing(Zmod(n)) f = 2 * pow(x,3) - 2 * pow(y,2) + 2 * x * q + q - 1 f = f.monic() root = f.small_roots(X=2^512,beta=0.4) print(root)
之后再回过头来看生成加密点的原理,之前看 crt 的过程,不明白为什么他要分别 mod p 再 mod q,现在知道是如果不经过这样一个换环的操作,是没有办法得到点的,在 mod n 的情况,n 不是质数,无法代入求点无法开根,所以得先将 n 给分解了,然后在换环 q,在 GF (q) 中求出 e 的逆元 d,之后就得到原始点了,完整 wp
from Crypto.Util.number import getPrime, bytes_to_long from gmpy2 import next_prime from os import urandom p = getPrime(512) q = next_prime(p) f = open('flag.txt', 'rb') flag = bytes_to_long(f.read() + urandom(80)) f.close() n = p * q noise = 1 for i inrange(1, p): noise = (noise * i) % n e = 65537 m = noise * flag % n c = pow(m, e, n) f = open('cipher.txt', 'w') f.write(f'n = {n}\n') f.write(f'c = {c}\n') f.close() n = 85300075344029411815824595503988243445862905766678219075505308650733618833670564881852727486124268400610986787128098448019033364495139613324970241727110931819892696714818851281415775513570277910383275087114654129682377412912019832281317957560043184535419626656895668221654944747681971549122289940681069900407 c = 9573652589542765552302771253681350397003834739308979745013100413124314842798363931809688570564520116621700487372591176287735200842509675988724251662626729985842786542792501720096155870937426730816107184806453412679852267311433564241907769415712680798333238722253896962273334726781549003053182286964079196169
一眼看到阶乘,肯定得用威尔逊定理解,威尔逊定理简单普及一下:当且仅当 p 为素数时满足(p−1)!=−1(modp)
p 和 q 很靠近,能直接分解出,m 也能求出,现在就有式子m≡(p−1)!×flag(modn)
考虑到 p<q,且 p 和 q 的值已知,考虑求出 (p-1)! 在 mod q 的环境下的值,然后中国剩余定理可求得 x 有(p−1)!≡x(modn)
from Crypto.Util.number import * import gmpy2 import sympy import os from functools import reduce
defunion(x1, x2): a1, m1 = x1 a2, m2 = x2 d = gmpy2.gcd(m1, m2) assert (a2 - a1) % d == 0 p1,p2 = m1 // d,m2 // d _,l1,l2 = gmpy2.gcdext(p1,p2) k = -((a1 - a2) // d) * l1 lcm = gmpy2.lcm(m1,m2) ans = (a1 + k * m1) % lcm return ans,lcm
defexcrt(ai,mi): tmp = zip(ai,mi) return reduce(union, tmp) n = 85300075344029411815824595503988243445862905766678219075505308650733618833670564881852727486124268400610986787128098448019033364495139613324970241727110931819892696714818851281415775513570277910383275087114654129682377412912019832281317957560043184535419626656895668221654944747681971549122289940681069900407 c = 9573652589542765552302771253681350397003834739308979745013100413124314842798363931809688570564520116621700487372591176287735200842509675988724251662626729985842786542792501720096155870937426730816107184806453412679852267311433564241907769415712680798333238722253896962273334726781549003053182286964079196169 e = 65537 q = gmpy2.iroot(n,2)[0] q = sympy.nextprime(q) p = n // q phi = (p - 1) * (q - 1) d = gmpy2.invert(e,phi) m = pow(c,d,n) print(m) ass = 1 for i inrange(p,q - 1): ass = ass * i % q tmp = gmpy2.invert(ass,q) ai = [tmp,-1] mi = [q,p] ans = excrt(ai,mi)[0] print(ans) flag = m * gmpy2.invert(ans,n) % n print(long_to_bytes(flag))
p 和 q 的高 124 位是相同的,中间 600 位 q 和 p 互相取反,最后 300 被混淆。看到最后 300 被混淆很容易想到用 cop 求出最后的 300 位,高 124 位直接对 n 开方取前 124 位就得到了。问题就在中间的 600 位如何利用取反关系求得。
p=hight128+x+l1q=hight128+y+l2,其中 + 表示拼接会直观一些,hight128 表示可求出的 128 位,l1 和 l2 表示最后被混淆的 300 位,中间 600 位 x 与 y 满足关系式x+y=2600−1。所以我们尝试改变 p 和 q 的值,p 相应减少多少,q 就相应增大多少 (仅中间 600 位)
_n=_p×_q=(a−x)×(b+x)=ab+x(a−b)−x2
我们先分别赋值 p 和 q 为极大极小值,由于最后 300 位不知道,p 和 q 赋的极大值默认最后 300 位为 0,中间求出来的数不能准确得求出 600 位,求出来的 p 会比实际值更小一些。
1 2 3 4 5 6 7 8 9 10 11
from Crypto.Util.number import * import gmpy2 n = 29229445599118483001701466306458274418313207587536209963238059476868917454504410032112597117546615733598387274665904107870896556998881063494600049216084775281584147609749667294182462818941181246561319625259137178286553974862986352158857172427903588054746932151579636584132759169528954347728678147797597780996214188968831836400285920685337294608990778009074569367505456248478822993714411937836237079928768898433354626698856023139709607246825672149802133458391862603953992754636020632951723690379324712160511376119409228990756977864084382454893999090811914709514495628598844102290648843131526073812299407141152746828211 e = 65537 c = 27262929902030666496793680198378375783118765007240773797447297373974049739280501484190475741272400002678990305397801039585302141612980217637827689855495194137917731223794004541444801329963350663757702880339071040394112003443782577628934852778346806832338683188416557851657662851936237381508536575784367362155948842050537160648323422133865019281159422760012328176817578911979109809017343487277094564311771567762098406452929665999529576409514599383724142729549969108272634307034039737849698091566761416686112727060743246758998947423163006255390922762318010959938510994940492040924944342464117140526367088683519638709681