import gmpy2 deftransform(x,y): #使用辗转相处将分数 x/y 转为连分数的形式 res=[] while y: res.append(x//y) x,y=y,x%y return res
defcontinued_fraction(sub_res): numerator,denominator=1,0 for i in sub_res[::-1]: #从sublist的后面往前循环 denominator,numerator=numerator,i*numerator+denominator return denominator,numerator #得到渐进分数的分母和分子,并返回
#求解每个渐进分数 defsub_fraction(x,y): res=transform(x,y) res=list(map(continued_fraction,(res[0:i] for i inrange(1,len(res))))) #将连分数的结果逐一截取以求渐进分数 return res
defwienerAttack(e,n): for (d,k) in sub_fraction(e,n): #用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数 if k==0: #可能会出现连分数的第一个为0的情况,排除 continue if (e*d-1)%k!=0: #ed=1 (mod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n) continue
phi=(e*d-1)//k #这个结果就是 φ(n) px,qy=get_pq(1,n-phi+1,n) if px*qy==n: p,q=abs(int(px)),abs(int(qy)) #可能会得到两个负数,负负得正未尝不会出现 d=gmpy2.invert(e,(p-1)*(q-1)) #求ed=1 (mod φ(n))的结果,也就是e关于 φ(n)的乘法逆元d return d print("该方法不适用")
e = 14058695417015334071588010346586749790539913287499707802938898719199384604316115908373997739604466972535533733290829894940306314501336291780396644520926473 n = 33608051123287760315508423639768587307044110783252538766412788814888567164438282747809126528707329215122915093543085008547092423658991866313471837522758159 d=wienerAttack(e,n) print("d=",d)
参考论文和 wiki
中的做法,后续的思路是使用这两个式子的不同关系去构造格,进而格基约化求得\(\phi(N)\)来实现\(N\)的分解。
两个小解密指数
三个小解密指数
低加密指数攻击 e=3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import gmpy2 from Crypto.Util.number import *
defdec(c, e, n): k = 0 whileTrue: mm = c + n*k result, flag = gmpy2.iroot(mm, e) ifTrue == flag: return result k += 1 n= 14067473525623615859223663589118945198091192669401088734569589535726733244095067264729942915265175903139441309376381225701454902095234966599914234681888481774607095853830772571665038109641511499155604914228117882196188074964226780922239011682486198651997912713999544628177959592818928976240251790858062449396082494272361535640237914373270152455829541596341184902017633404494979208958080467979235974182507427501682492000572071306960595992848840147393057648929439822116261337091431441205378542080755128597543738922210525692259529009107645032171097155449558362749512243918901171631681472217935131865121871798425854707759 e= 3 c= 2217344750798294937344050117513831761010547351781457575945714176628679412650463329423466955026804439931765627111856888102133234836914006818023839994342283023142702993182665344445325734299047409223354338948863171846780674244925724334091153701697864918695050507247415283070309
import os from Crypto.Util.number import * from hashlib import * magic=b'e0204eeaf14d72ab90e1f7ac69559dd182' LEN = 17 magic = os.urandom(LEN) print("Magic:", magic.hex()) print('Coud you use it to do encryption as hash?')
magic_num = bytes_to_long(magic) try: N = int(input('N:>')) e = int(input('E:>')) data = long_to_bytes(int(input('data:>'), 16)) if N >> (248) == magic_num: data2 = sha384(data).digest() num1 = bytes_to_long(data) num2 = bytes_to_long(data2) ifpow(num1, e, N) == num2: print(os.getenv('FLAG')) else: print('try harder!!!') else: print('try harder!') except Exception as e: print('invalid')
import gmpy2 from Crypto.Util.number import * import random from itertools import product defsqrtPrime(n, p): q = p - 1 m = 0 while q & 1 == 0: q >>= 1 m += 1
z = 1 whilepow(z, (p - 1) >> 1, p) == 1: z = random.randint(1, p - 1)
c = pow(z, q, p) t = pow(n, q, p) r = pow(n, (q + 1) >> 1, p) if t == 0: return0 m -= 2 while t != 1: whilepow(t, 2**m, p) == 1: c = c * c % p m -= 1 r = r * c % p c = c * c % p t = t * c % p m -= 1 return r
defLegendre(n,p): # 这里用勒让德符号来表示判断二次(非)剩余的过程 returnpow(n,(p - 1) // 2,p) defTonelli_Shanks(n,p): assert Legendre(n,p) == 1 if p % 4 == 3: print("1") returnpow(n,(p + 1) // 4,p) q = p - 1 s = 0 while q % 2 == 0: q = q // 2 s += 1 for z inrange(2,p): if Legendre(z,p) == p - 1: c = pow(z,q,p) break r = pow(n,(q + 1) // 2,p) t = pow(n,q,p) m = s if t % p == 1: return r else: i = 0 while t % p != 1: # 外层循环的判断条件 temp = pow(t,2**(i+1),p) # 这里写作i+1是为了确保之后内层循环用到i值是与这里的i+1的值是相等的 i += 1 if temp % p == 1: # 内层循环的判断条件 b = pow(c,2**(m - i - 1),p) r = r * b % p c = b * b % p t = t * c % p m = i i = 0# 注意每次内层循环结束后i值要更新为0 return r
e = 131074 e = 65537*2 n = 587926815910957928506680558951380405698765957736660571041732511939308424899531125274073420353104933723578377320050609109973567093301465914201779673281463229043539776071848986139657349676692718889679333084650490543298408820393827884588301690661795023628407437321580294262453190086595632660415087049509707898690300735866307908684649384093580089579066927072306239235691848372795522705863097316041992762430583002647242874432616919707048872023450089003861892443175057 c1 = 92883677608593259107779614675340187389627152895287502713709168556367680044547229499881430201334665342299031232736527233576918819872441595012586353493994687554993850861284698771856524058389658082754805340430113793873484033099148690745409478343585721548477862484321261504696340989152768048722100452380071775092776100545951118812510485258151625980480449364841902275382168289834835592610827304151460005023283820809211181376463308232832041617730995269229706500778999 c2 = 46236476834113109832988500718245623668321130659753618396968458085371710919173095425312826538494027621684566936459628333712619089451210986870323342712049966508077935506288610960911880157875515961210931283604254773154117519276154872411593688579702575956948337592659599321668773003355325067112181265438366718228446448254354388848428310614023369655106639341893255469632846938342940907002778575355566044700049191772800859575284398246115317686284789740336401764665472 cm = 357982930129036534232652210898740711702843117900101310390536835935714799577440705618646343456679847613022604725158389766496649223820165598357113877892553200702943562674928769780834623569501835458020870291541041964954580145140283927441757571859062193670500697241155641475887438532923910772758985332976303801843564388289302751743334888885607686066607804176327367188812325636165858751339661015759861175537925741744142766298156196248822715533235458083173713289585866 p = GCD(c1+c2,n) q = GCD(c1-c2,n) r = n//(p*q) phi=(p-1)*(q-1)*(r-1) d0=gmpy2.invert(65537,phi) m2=pow(cm,d0,n) cp=m2%p cq=m2%q cr=m2%r mp=sqrtPrime(cp,p) mq=sqrtPrime(cq,q) mr=sqrtPrime(cr,r)
import libnum from Crypto.Util.number import * import itertools n = 3326716005321175474866311915397401254111950808705576293932345690533263108414883877530294339294274914837424580618375346509555627578734883357652996005817766370804842161603027636393776079113035745495508839749006773483720698066943577445977551268093247748313691392265332970992500440422951173889419377779135952537088733 c = 2709336316075650177079376244796188132561250459751152184677022745551914544884517324887652368450635995644019212878543745475885906864265559139379903049221765159852922264140740839538366147411533242116915892792672736321879694956051586399594206293685750573633107354109784921229088063124404073840557026747056910514218246 p = 11104262127139631006017377403513327506789883414594983803879501935187577746510780983414313264114974863256190649020310407750155332724309172387489473534782137699 q=n//p e=196608 enc=c N=p*q
defget_oneroot(p, e): whileTrue: Zp = Zmod(p) g = Zp.random_element() g = g^((p-1) // e) for mult in divisors(e): if (mult != e): g2 = g^mult if (g2 == 1): break else: return g
defdecrypt(p, c, e): w = gcd(e, p-1) e1, p1 = e // w, (p-1) // w d = inverse_mod(e1, p1) c1 = pow(c, d, p) g, a, b = xgcd(p1, w) g = get_oneroot(p, w) m = pow(c1, b, p) return [ZZ(m * g^i) for i inrange(w)]
mp_list = decrypt(p, enc, e) print('Find root p OK') mq_list = decrypt(q, enc, e) print('Find root q OK') for mp, mq in itertools.product(mp_list, mq_list): m = crt([mp, mq], [p, q]) msg = long_to_bytes(int(m)) if (b'flag'in msg): print(msg)
#Sage import random import time from Crypto.Util.number import * # About 3 seconds to run 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(a, d) 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
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
deffindAllSolutions(mp, proot, cp, p): print("Start to find all the {:#x}th root of {} modulo {}.".format(e, cp, p)) start = time.time() all_mp = set() for root in proot: mp2 = mp * root % p assert(pow(mp2, e, p) == cp) all_mp.add(mp2) end = time.time() print("Finished in {} seconds.".format(end - start)) return all_mp
e = 0x1337 p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059 q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741 n = p * q c=10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
cp = c % p cq = c % q mp = AMM(cp, e, p) mq = AMM(cq, e, q) p_proot = findAllPRoot(p, e) q_proot = findAllPRoot(q, e) mps = findAllSolutions(mp, p_proot, cp, p) mqs = findAllSolutions(mq, q_proot, cq, q) print(mps, mqs)
# About 16 mins to run 0x1337^2 == 24196561 times CRT start = time.time() print('Start CRT...') for mpp in mps: for mqq in mqs: solution = CRT_list([int(mpp), int(mqq)], [p, q]) if check(solution): print(solution) print(time.time() - start)
end = time.time() print("Finished in {} seconds.".format(end - start))
for i inrange(5,200): sl = i*8 diff = bytes_to_long(b"dasctf{")*2^(sl+8) + bytes_to_long(b"}") #print(long_to_bytes(diff)) v = related_message_attack(C1, C2, diff, e, n) v = long_to_bytes(int(v)) ifall(0x20<=k<=0x7ffor k in v): print(v)