在平常遇到的问题中,如果能求出公钥 n 的欧拉函数ϕ,可以说这个 RSA 加解密问题已经接近成功了。要求私钥 d 需要求出 e 在 phi 中的逆元使得e∗d−1≡k∗ϕ(n),但直接求逆元需要满足一个前提就是gcd(e,phi)==1,也就是说 e 与 phi 是互素的,如果不互素,问题的复杂度将会增加不少。
相信在这个问题中,有一道 CTF 题是比较出名的,NCTF2019,附件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
from flag import flag
e = 0x1337 p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059 q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741 n = p * q
assert(flag.startswith('NCTF')) m = int.from_bytes(flag.encode(), 'big') assert(m.bit_length() > 1337)
c = pow(m, e, n) print(c) # 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
看似白给,但是这题的逆元 d 是求不出来的,因为 e 与 phi 不互素,gcd(e,p−1)==gcd(e,q−1)==gcd(e,phi)==e。该题的具体解法最后讨论,下面是我对 e 与 phi 不互素问题的一些小总结。
from Crypto.Util.number import * from secret import flag flag = b'flag{*********}' m = bytes_to_long(flag) p = getPrime(1024) q = getPrime(1024) n = p * q e = 114 c = pow(m,e,n) print(c) print(p >> 200) print(n)
其中第一部分是一个 p 泄露高位的问题,老生常谈了,这里不过多赘述。求出 p 之后我们发现,e 与 phi 不互素且公约数t=gcd(e,phi)=6,当时出题的 flag 值未设很长,故可进行尝试,数论推导如下:
e′=e//t
d=gmpy2.invert(e′,phi)
用此公钥,即有如下关系
(mt)e′≡c(modn)
mt≡cd(modn)
其中mt 可求且mt<n,即直接对mt 进行开t 次方根即可。exp 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from Crypto.Util.number import * import gmpy2 c = 4981370648841772812759645290740849305394680703208798679296466901875830602835273402860232301263281323578956193947979697234640828088984992529165349436050379602381023059635247562226192384089521639938396211636613132291696135696985578958227320544060232615333466684704244997055833821133086665356126147182204658744167431612986909752009485714137028204041440181653812250548914729617593568901044728464293232061709058144788756823288190386071071979728390993033661221130338943191220680445314588574185565138844949934691183548291792150029676489045342419826189506616272247940278820931530398810621850374268800818970515221497093852109 e = 114 p = 99690105430259549732952386298363416480730988331578091065948950836198178325904426675017504756348563688521763268566954512895974110780822714951824351709232320913381679046309934991336770483285399157355308073567950907088479972767984569322594411195698421500521401221792581871025328456951904596576566123729811756413 n = 10315159385090642346129000730749042701431892949303034712476198921384639021767097119992198421632142955005047146294210952031882321038272269972695714084199530336742619691272883151455898061330316812891004827724782855036289498818157782936179413509824274682055131552093071749522986951202502017564120645520386407170556413591537187759567563157956331577316042296031033014710853038209000676314440817362756989634719336973373719581572614119144998829076893422175956726616346716072744575347893245428145235967836165207095908913238287634122873060994828380614739915448587956681845973466847711337763120292734433687845920176310499582951 q = 103472248730911851254553434648605804338564109979871343883653538836587422384404224866918549458325035655810767726029600292489262023711038658950506809510441640439838143226881684645307170720125749718552087605871880391263080540577543652043401824062555993901349884856226877853115632353980186588864859131611388824627 phi = (p - 1) * (q - 1) t = gmpy2.gcd(e,phi) print(t) _e = e // t d = gmpy2.invert(_e,phi) _m = pow(c,d,n) m = gmpy2.iroot(_m,t)[0] print(long_to_bytes(m))
from Crypto.Util.number import * import gmpy2 import os from functools import reduce
p = 145332367700944303747548912160113939198078051436029477960348968315913956664143693347226702600438608693933768134575289286283267810723137895903153829001826223446477799895493265422562348917012216790077395795861238257357035152687833639085415763850743538206986781418939737511715957738982536382066693822159860701263 q = 116660458253067608044065523310547233337730583902133756095473339390057738510707447906971188577217274861047379404014140178165569604404468897712846876108444468370709141219302291601408652742006268186059762087155933131837323952675627966299810891805398890428420575425160696531236660480933905879208166090591482794763 r = 157931722402853245421436270609912823260313730941283152856444641969403238646482562190531038393124087232554754746464603598717356255570166081501573727336977292059427220330169044611674973569766966838498453232642731737958791706086957762244686953294662693939604300864961637325536379321027705854708492453330690705531 s = 100973451687449518854742673778783266158999451072058606348222018797891147675959983616210003484476577612134482311993701677242007759556951494382833070563369964294544839433671087037596159753825249018950693369209927951667775267086896180395776150188902057785214767230658487267587289809918132337927575673868568976679 t = 93960345071948255233882121683650797512129333868351496468898834736770441398743300745703393838320587998953678254272245400344928586394089488734271897540051673996675973642347859306921527430850673334243441180183460927865980713929789963587608547554858491264614271309608925634272282292964002897650355047792764365447 c = 9144597920381774885442906257311149465702295057238600973973598305004391534618770363098565074541384771979931799878381439264848137810353858418200992191234142740194489573540381681161219332611454834544291634628456257670178843484698324641739324687497388018406214041657278323855749902661752448796122517061920880552011343608609622885787617238758769398972009949575526258430282648817039091284796330585349957724522615105102735930258969562103112238020133587096826386028128471852377225525357348919204333121695432662339443004327748973224423132988376298843862056631045488285859621661802413201793962883794915513510467912312842687601478117040419013468059983777273699192408773551806581458197324620065210523913467414181480875280203580147077789063808832356486197271376615883221558265591069223727607585313240243619515521180600435114131162272519949101464089935441251751426683447701142156416866113627126765919641034042927519834229168536331952275698122511502745177547569813354280565828372968703810158857859460406828090199683324760956105682902577189283246483314689365570862217407333103243336691401424548702387876409228977278498691200028282744239512091373110111792177228979867318546462714521296256938374618636206565791541769138267080789842400796973226733816939794717596194090232425688504890234304977612220790858557639246367437740975495450011676714198668471438814299689325208882261918460708833888406187912527346628912894921059735420931656953236560178909180587372589456926690219114173193202048332172538564489660440225377822914097420807957784201785024166011709377791129 n = p * q * r * s * t e = 2 # print(n) phi = (p - 1) * (q - 1) * (r - 1) * (s - 1) * (t - 1) R.<x> = Zmod(p)[] f = x ^ e - c f = f.monic() res1 = f.roots() R.<x> = Zmod(q)[] f = x ^e - c f = f.monic() res2 = f.roots()
R.<x> = Zmod(r)[] f = x ^e - c f = f.monic() res3 = f.roots()
R.<x> = Zmod(s)[] f = x ^e - c f = f.monic() res4 = f.roots()
R.<x> = Zmod(t)[] f = x ^e - c f = f.monic() res5 = f.roots() print(res1,res2,res3,res4,res5,sep='\n')
#一个手写的CRT板子,sage中的CRT_list函数会快些 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) for i in res1: for j in res2: for k in res3: for l in res4: for m in res5: ai = [i[0],j[0],k[0],l[0],m[0]] # print(ai) mi = [p,q,r,s,t] flag = excrt(ai,mi) flag = long_to_bytes(flag[0]) ifb'ctfshow'in flag: print(flag)
from Crypto.Util.number import * import gmpy2 import time import random from tqdm import tqdm defAMM(o, r, q): start = time.time() print('\n----------------------------------------------------------------------------------') print('Start to run Adleman-Manders-Miller Root Extraction Method') print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q)) g = GF(q) o = g(o) p = g(random.randint(1, q)) while p ^ ((q-1) // r) == 1: p = g(random.randint(1, q)) print('[+] Find p:{}'.format(p)) t = 0 s = q - 1 while s % r == 0: t += 1 s = s // r print('[+] Find s:{}, t:{}'.format(s, t)) k = 1 while (k * s + 1) % r != 0: k += 1 alp = (k * s + 1) // r print('[+] Find alp:{}'.format(alp)) a = p ^ (r**(t-1) * s) b = o ^ (r*alp - 1) c = p ^ s h = 1 for i inrange(1, t): d = b ^ (r^(t-1-i)) if d == 1: j = 0 else: print('[+] Calculating DLP...') j = - discrete_log(d, a) print('[+] Finish DLP...') b = b * (c^r)^j h = h * c^j c = c^r result = o^alp * h end = time.time() print("Finished in {} seconds.".format(end - start)) print('Find one solution: {}'.format(result)) return result
其中 AMM (o,r,q) 的返回值满足o≡resultr(modq),就是在有限域 q 中对 o 开 r 次根。还有一个比较方便的函数,但是没有具体研究过,作用也是在有限域内得到一个根。得到一个 x 满足xn≡a(modp)
1 2
from sympy.ntheory.residue_ntheory import nthroot_mod nthroot_mod(a,n,p)
from Crypto.Util.number import * from key import FLAG
defkeygen(size): q = getPrime(80) k = getPrime(944) whileTrue: p = q * k + 1 if isPrime(p): break k += 1 g = 2 whileTrue: ifpow(g, q, p) == 1: break g += 1 A = getRandomInteger(size) % q B = getRandomInteger(size) % q x = getRandomInteger(size) % q h = pow(g, x, p) return (g, h, A, B, p, q), (x)
defrand(A, B, q): global rand_state rand_state, ret = (A * rand_state + B) % q, rand_state return ret
defencrypt(pubkey, m): g, h, A, B, p, q = pubkey assert0 < m <= p r = rand(A, B, q) c1 = pow(g, r, p) c2 = (m * pow(h, r, p)) % p return (c1, c2)
assert ( A * s0 + B ) % q == s1 assert ( A * s1 + B ) % q == s2 assert ( A * s2 + B ) % q == s3 assert ( A * s3 + B ) % q == s4
p = 65211247300401312530078141569304950676358489059623557848188896752173856845051471066071652073612337629832155846984721797768267868868902023383604553319793550396610085424563231688918357710337401138108050205457200940158475922063279384491022916790549837379548978141370347556053597178221402425212594060342213485311 g = 27642593390439430783453736408814717946185190497201679721975757020767271070510268596627490205095779429964809833535285315202625851326460572368018875381603399143376574281200028337681552876140857556460885848491160812604549770668188783258592940823128376128198726254875984002214053523752696104568469730021811399216 h = 54585833166051670245656045196940486576634589000609010947618047461787934106392112227019662788387352615714332234871251868259282522817042504587428441746855906297390193418159792477477443129333707197013251839952389651332058368911829464978546505729530760951698134101053626585254469108630886768357270544236516534904
e = 12742153496769814072596 p = 65211247300401312530078141569304950676358489059623557848188896752173856845051471066071652073612337629832155846984721797768267868868902023383604553319793550396610085424563231688918357710337401138108050205457200940158475922063279384491022916790549837379548978141370347556053597178221402425212594060342213485311 c = 45326527081735095684632585216508484943819720696878842043540554720229674414296707918873385105075387912310299691748216658256439485784388880803922134863731374059731970174794936075890019917038396488161530769759774808480182049272235808430693365496648819656078275683885130420969875204155207145247880895891885126527 phi = p - 1 assertpow(m,e,p) == c
私钥 d 无法通过直接求逆元求出,且公约数 t=7438,但这题有一个特殊点的地方为,当得到e′=e//t 之后,得到的 e' 仍然不满足于 phi 互素,还有一个公约数 2,所以这题要先对 c 进行有限域内开二次方根,开完二次方根之后再将m7438 看作一个整体进行有限域内开根,即
设e=7438∗2∗e′
(flage′∗7438)2≡c(modp)
flage′∗7438≡c′(modp)
将flag7438 看成一个整体进行 RSA 解密之后,得到
flag7438≡c′′(modp)
问题转化成 c'' 在有限域 p 内开 7438 次根,但是 AMM 算法只能找到其中一个根,如何通过一个根找到其他的根,本篇文章给出了解法。用法大致如下,根据公式
(xep−1)e≡xq−1≡1
m0∗x(ep−1)(modp) 其中 m0 是求出来的一个根
1 2 3 4 5 6 7 8 9
deffindAllPRoot(p, e): print("Start to find all the Primitive {:#x}th root of 1 modulo {}.".format(e, p)) start = time.time() proot = set() whilelen(proot) < e: proot.add(pow(random.randint(2, p-1), (p-1)//e, p)) end = time.time() print("Finished in {} seconds.".format(end - start)) return proot
上述代码的返回值就是xep−1 的合集,故最终求出本题的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
_gcd = gmpy2.gcd(e,phi) #_gcd = 7438 e //= 2 _c = AMM(c,2,p) d = gmpy2.invert(e // _gcd,phi) _c = pow(_c,d,p) # _m = AMM(_c,7438,p) e = 7438 mps = findAllPRoot(p, e) for r in mps: m = _m * r % p flag = long_to_bytes(m) ifb'flag'in flag: print(flag) break
from Crypto.Util.number import * from secret import e,message
defpad(s): iflen(s)<3*L: s+=bytes(3*L-len(s)) return s
L=128 p = 127846753573603084140032502367311687577517286192893830888210505400863747960458410091624928485398237221748639465569360357083610343901195273740653100259873512668015324620239720302434418836556626441491996755736644886234427063508445212117628827393696641594389475794455769831224080974098671804484986257952189021223 q = 145855456487495382044171198958191111759614682359121667762539436558951453420409098978730659224765186993202647878416602503196995715156477020462357271957894750950465766809623184979464111968346235929375202282811814079958258215558862385475337911665725569669510022344713444067774094112542265293776098223712339100693 r = 165967627827619421909025667485886197280531070386062799707570138462960892786375448755168117226002965841166040777799690060003514218907279202146293715568618421507166624010447447835500614000601643150187327886055136468260391127675012777934049855029499330117864969171026445847229725440665179150874362143944727374907 n = p * q * r
assert isPrime(GCD(e,p-1)) and isPrime(GCD(e,q-1)) and isPrime(GCD(e,r-1)) and e==GCD(e,p-1)*GCD(e,q-1)*GCD(e,r-1) assertlen(message)>L andlen(message)<2*L assertb'SUSCTF'in message m=bytes_to_long(pad(message))
from Crypto.Util.number import * import gmpy2 import time import random from tqdm import tqdm p = 127846753573603084140032502367311687577517286192893830888210505400863747960458410091624928485398237221748639465569360357083610343901195273740653100259873512668015324620239720302434418836556626441491996755736644886234427063508445212117628827393696641594389475794455769831224080974098671804484986257952189021223 q = 145855456487495382044171198958191111759614682359121667762539436558951453420409098978730659224765186993202647878416602503196995715156477020462357271957894750950465766809623184979464111968346235929375202282811814079958258215558862385475337911665725569669510022344713444067774094112542265293776098223712339100693 r = 165967627827619421909025667485886197280531070386062799707570138462960892786375448755168117226002965841166040777799690060003514218907279202146293715568618421507166624010447447835500614000601643150187327886055136468260391127675012777934049855029499330117864969171026445847229725440665179150874362143944727374907 n = p * q * r c = 2832775557487418816663494645849097066925967799754895979829784499040437385450603537732862576495758207240632734290947928291961063611897822688909447511260639429367768479378599532712621774918733304857247099714044615691877995534173849302353620399896455615474093581673774297730056975663792651743809514320379189748228186812362112753688073161375690508818356712739795492736743994105438575736577194329751372142329306630950863097761601196849158280502041616545429586870751042908365507050717385205371671658706357669408813112610215766159761927196639404951251535622349916877296956767883165696947955379829079278948514755758174884809479690995427980775293393456403529481055942899970158049070109142310832516606657100119207595631431023336544432679282722485978175459551109374822024850128128796213791820270973849303929674648894135672365776376696816104314090776423931007123128977218361110636927878232444348690591774581974226318856099862175526133892 e = 757 * 66553 * 5156273 # c = c * gmpy2.invert(pow(256,128 * e,n),n) % n c = 280255407228236757409815887816839305916013793019016233556655881177084422973195335022587512823438603244476043620827618294521590422727109511126415701233621433629240428867472167324658030697632936334280396757560948574122348115659399270054958107088934452614887088952896264179020173433953077103667481291070508539455758662089418673467059205006535938089060238423612896891987917999584958061136036905447992065531255981463313994015042735163816799075348821119889190340460982992279626227831798343223551589026122303723190113833517871336399306996954589023298254133748866058614684423538364147817066529477497132575245720700870565926266788795913995176704128093239281548107568333922105485755437756178962461996506944599470241130124718452661102076116228019710853593988020056387355430180299354138576803527595019867293888047502553256446787799726850487133374683211529254614387387388363258745961934823313987871646019723020739519484511573598334592780 defAMM(o, r, q): start = time.time() print('\n----------------------------------------------------------------------------------') print('Start to run Adleman-Manders-Miller Root Extraction Method') print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q)) g = GF(q) o = g(o) p = g(random.randint(1, q)) while p ^ ((q-1) // r) == 1: p = g(random.randint(1, q)) print('[+] Find p:{}'.format(p)) t = 0 s = q - 1 while s % r == 0: t += 1 s = s // r print('[+] Find s:{}, t:{}'.format(s, t)) k = 1 while (k * s + 1) % r != 0: k += 1 alp = (k * s + 1) // r print('[+] Find alp:{}'.format(alp)) a = p ^ (r**(t-1) * s) b = o ^ (r*alp - 1) c = p ^ s h = 1 for i inrange(1, t): d = b ^ (r^(t-1-i)) if d == 1: j = 0 else: print('[+] Calculating DLP...') j = - discrete_log(d, a) print('[+] Finish DLP...') b = b * (c^r)^j h = h * c^j c = c^r result = o^alp * h end = time.time() print("Finished in {} seconds.".format(end - start)) print('Find one solution: {}'.format(result)) return result defonemod(p,r): t=p-2 whilepow(t,(p-1) // r,p)==1: t -= 1 returnpow(t,(p-1) // r,p) defsolution(p,root,e): g = onemod(p,e) may = set() for i inrange(e): may.add(root * pow(g,i,p)%p) return may
ep = 757 eq = 66553 er = 5156273 cp = pow(c,gmpy2.invert(eq*er,p-1),p) cq = pow(c,gmpy2.invert(ep*er,q-1),q) mp = AMM(cp,ep,p) mq = AMM(cq,eq,q) mps = solution(p,mp,ep) mqs = solution(q,mq,eq) for mpp in tqdm(mps): for mqq in mqs: ai = [int(mpp),int(mqq)] mi = [p,q] m = CRT_list(ai,mi) flag = long_to_bytes(m) ifb'SUSCTF'in flag: print(flag) exit(0)
板子从 V 神 blog 里嫖的其中函数 onemod () 和 solution () 组合求出剩下的根并进行组合
1 2 3 4 5 6 7 8 9 10 11 12
defonemod(p,r): t=p-2 whilepow(t,(p-1) // r,p)==1: t -= 1 returnpow(t,(p-1) // r,p) defsolution(p,root,e):#(质数环,AMM求出的一个根,需要开e次根) g = onemod(p,e) may = set() for i inrange(e): may.add(root * pow(g,i,p)%p) return may
from Crypto.Util.number import * import gmpy2 import time import random from tqdm import tqdm e = 0x1337 p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059 q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741 n = p * q c = 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
defAMM(o, r, q): start = time.time() print('\n----------------------------------------------------------------------------------') print('Start to run Adleman-Manders-Miller Root Extraction Method') print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q)) g = GF(q) o = g(o) p = g(random.randint(1, q)) while p ^ ((q-1) // r) == 1: p = g(random.randint(1, q)) print('[+] Find p:{}'.format(p)) t = 0 s = q - 1 while s % r == 0: t += 1 s = s // r print('[+] Find s:{}, t:{}'.format(s, t)) k = 1 while (k * s + 1) % r != 0: k += 1 alp = (k * s + 1) // r print('[+] Find alp:{}'.format(alp)) a = p ^ (r**(t-1) * s) b = o ^ (r*alp - 1) c = p ^ s h = 1 for i inrange(1, t): d = b ^ (r^(t-1-i)) if d == 1: j = 0 else: print('[+] Calculating DLP...') j = - discrete_log(d, a) print('[+] Finish DLP...') b = b * (c^r)^j h = h * c^j c = c^r result = o^alp * h end = time.time() print("Finished in {} seconds.".format(end - start)) print('Find one solution: {}'.format(result)) return result
defonemod(p,r): t=p-2 whilepow(t,(p-1) // r,p)==1: t -= 1 returnpow(t,(p-1) // r,p) defsolution(p,root,e): g = onemod(p,e) may = set() for i inrange(e): may.add(root * pow(g,i,p)%p) return may
cp = c % p cq = c % q # mp = AMM(cp,e,p) # mq = AMM(cq,e,q) mps = find_roots(c % p,e,p) mqs = find_roots(c % q,e,q) for mpp in tqdm(mps): for mqq in mqs: ai = [int(mpp),int(mqq)] mi = [p,q] m = CRT_list(ai,mi) flag = long_to_bytes(m) ifb'NCTF'in flag: print(flag) exit(0)
from Crypto.Util.number import * import gmpy2 c = e = n = p = q = phi = (p - 1) * (q - 1) t = gmpy2.gcd(e,phi) print(t) _e = e // t d = gmpy2.invert(_e,phi) _m = pow(c,d,n) m = gmpy2.iroot(_m,t)[0] print(long_to_bytes(m))
from Crypto.Util.number import * import gmpy2 p = q = c = n = e = phi = (p - 1) * (q - 1)
R.<x> = Zmod(p)[] f = x ^ e - c f = f.monic() res1 = f.roots() R.<x> = Zmod(q)[] f = x ^e - 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: print(flag)
from Crypto.Util.number import * import gmpy2 import time import random from tqdm import tqdm e = p = q = n = p * q c =
defAMM(o, r, q): start = time.time() print('\n----------------------------------------------------------------------------------') print('Start to run Adleman-Manders-Miller Root Extraction Method') print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q)) g = GF(q) o = g(o) p = g(random.randint(1, q)) while p ^ ((q-1) // r) == 1: p = g(random.randint(1, q)) print('[+] Find p:{}'.format(p)) t = 0 s = q - 1 while s % r == 0: t += 1 s = s // r print('[+] Find s:{}, t:{}'.format(s, t)) k = 1 while (k * s + 1) % r != 0: k += 1 alp = (k * s + 1) // r print('[+] Find alp:{}'.format(alp)) a = p ^ (r**(t-1) * s) b = o ^ (r*alp - 1) c = p ^ s h = 1 for i inrange(1, t): d = b ^ (r^(t-1-i)) if d == 1: j = 0 else: print('[+] Calculating DLP...') j = - discrete_log(d, a) print('[+] Finish DLP...') b = b * (c^r)^j h = h * c^j c = c^r result = o^alp * h end = time.time() print("Finished in {} seconds.".format(end - start)) print('Find one solution: {}'.format(result)) return result
defonemod(p,r): t=p-2 whilepow(t,(p-1) // r,p)==1: t -= 1 returnpow(t,(p-1) // r,p) defsolution(p,root,e): g = onemod(p,e) may = set() for i inrange(e): may.add(root * pow(g,i,p)%p) return may
cp = c % p cq = c % q mp = AMM(cp,e,p) mq = AMM(cq,e,q) mps = solution(p,mp,e) mqs = solution(q,mq,e) for mpp in tqdm(mps): for mqq in mqs: ai = [int(mpp),int(mqq)] mi = [p,q] m = CRT_list(ai,mi) flag = long_to_bytes(m) ifb'NCTF'in flag: print(flag) exit(0)