Pragyan CTF 2019 writeup
Easy RSA
以下の値が渡される。eが大きいのでWiener's Attackができるのではと考える。
n = 413514550275673527863957027545525175432824699510881864021105557583918890022061739148026915990124447164572528944722263717357237476264481036272236727160588284145055425035045871562541038353702292714978768468806464985590036061328334595717970895975121788928626837881214128786266719801269965024179019247618967408217 e = 217356749319385698521929657544628507680950813122965981036139317973675569442588326220293299168756490163223201593446006249622787212268918299733683908813777695992195006830244088685311059537057855442978678020950265617092637544349098729925492477391076560770615398034890984685084288600014953201593750327846808762513 c = 337907824405966440030495671003069758278111764297629248609638912154235544001123799434176915113308593275372838266739188034566867280295804636556069233774555055521212823481663542294565892061947925909547184805760988117713501561339405677394457210062631040728412334490054091265643226842490973415231820626551757008360
以下、solverです。
from fractions import Fraction def egcd(a, b): x,y, u,v = 0,1, 1,0 while a != 0: q, r = b//a, b%a m, n = x-u*q, y-v*q b,a, x,y, u,v = a,r, u,v, m,n gcd = b return gcd, x, y def decrypt(p, q, e, ct): n = p * q phi = (p - 1) * (q - 1) gcd, a, b = egcd(e, phi) d = a pt = pow(ct, d, n) return hex(pt)[2:-1].decode("hex") def continued_fractions(n,e): cf = [0] while e != 0: cf.append(int(n/e)) N = n n = e e = N%e return cf def calcKD(cf): kd = list() for i in range(1,len(cf)+1): tmp = Fraction(0) for j in cf[1:i][::-1]: tmp = 1/(tmp+j) kd.append((tmp.numerator,tmp.denominator)) return kd def int_sqrt(n): def f(prev): while True: m = (prev + n/prev)/2 if m >= prev: return prev prev = m return f(n) def calcPQ(a,b): if a*a < 4*b or a < 0: return None c = int_sqrt(a*a-4*b) p = (a + c) /2 q = (a - c) /2 if p + q == a and p * q == b: return (p,q) else: return None def wiener(n,e): kd = calcKD(continued_fractions(n,e)) for (k,d) in kd: if k == 0: continue if (e*d-1) % k != 0: continue phin = (e*d-1) / k if phin >= n: continue ans = calcPQ(n-phin+1,n) if ans is None: continue return (ans[0],ans[1]) n = 413514550275673527863957027545525175432824699510881864021105557583918890022061739148026915990124447164572528944722263717357237476264481036272236727160588284145055425035045871562541038353702292714978768468806464985590036061328334595717970895975121788928626837881214128786266719801269965024179019247618967408217 e = 217356749319385698521929657544628507680950813122965981036139317973675569442588326220293299168756490163223201593446006249622787212268918299733683908813777695992195006830244088685311059537057855442978678020950265617092637544349098729925492477391076560770615398034890984685084288600014953201593750327846808762513 c = 337907824405966440030495671003069758278111764297629248609638912154235544001123799434176915113308593275372838266739188034566867280295804636556069233774555055521212823481663542294565892061947925909547184805760988117713501561339405677394457210062631040728412334490054091265643226842490973415231820626551757008360 (p,q) = wiener(n,e) print "p=", str(p) print "q=", str(q) plaintext = decrypt(p, q, e, c) print "pass:", plaintext
実行結果はこちらの通り。
p= 20849180417451853710316597265206450290754170726980118770375941268686670371486003295019076447328939684328124148947495424092191017095312378807096231649456257 q= 19833611777350261527711079937022117212864220836350357905133650650024955479645832765842667370773048457804959743454987087255447637313845649824446832388600281 pass: Here is your flag, pctf{Sup3r_st4nd4rd_W31n3r_4tt4ck}