当前位置:   article > 正文

CTF学习笔记一——RSA加密_ctf rsa

ctf rsa

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制

在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK

正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。

RSA算法的具体描述如下:

(1)任意选取两个不同的大素数p和q计算乘积n=pq φ(n)=(p-1)(q-1)

(2)任意选取一个大整数e,满足gcd(e,φ(n))=1 ,也就是e φ(n )互质,整数e用做加密钥(注意:e的选取是很容易的,例如,所有大于p和q的素数都可用);

(3)确定的解密钥d,满足demodφ(n)=1 ,即de=kφ(n)+1,k1 是一个任意的整数;所以,若知道e和φn ,则很容易计算出d;

(4)公开整数n和e,秘密保存d;

(5)将明文m(m<n是一个整数)加密成密文c,加密算法为: 

c=E(m)=modn

(6)将密文c解密为明文m,解密算法为: 

m=D(c)=modn

然而只根据n和e(注意:不是p和q)要计算出d是不可能的。因此,任何人都可对明文进行加密,但只有授权用户(知道d)才可对密文解密

在证明上述公式之前,先了解一下欧拉代数定理。也就是若n, a为正整数,且n,a互质,则:modn=1φ(n) 为欧拉函数,表示小于n且和n互质的数的个数。特别的,当n为素数时,φ(n)=n-1 ,当p,q为素数时φ(pq)=(p-1)(q-1)

所以有

   CTF中,对于RSA题型的解题思路大体有如下几种:

1、 直接分解模数N

直接分解模数N是最直接的攻击方法,也是最困难的方法。具体的解析同上RSA安全性分析。

通常可以尝试利用在线网站factordb.com,这一类在线网站进行n的分解。

   例题:竞赛平台 (vidar.club)

图1 题目源码

c = 110674792674017748243232351185896019660434718342001686906527789876264976328686134101972125493938434992787002915562500475480693297360867681000092725583284616353543422388489208114545007138606543678040798651836027433383282177081034151589935024292017207209056829250152219183518400364871109559825679273502274955582  

n = 135127138348299757374196447062640858416920350098320099993115949719051354213545596643216739555453946196078110834726375475981791223069451364024181952818056802089567064926510294124594174478123216516600368334763849206942942824711531334239106807454086389211139153023662266125937481669520771879355089997671125020789  

题目只给了n和c的值,但n的值不是很大,可以爆破分解

图2 大数质因数分解

知道了p,q的值,那么密文很快就能求出来了,python代码如下:

  1. import gmpy2
  2. import binascii
  3. c = 110674792674017748243232351185896019660434718342001686906527789876264976328686134101972125493938434992787002915562500475480693297360867681000092725583284616353543422388489208114545007138606543678040798651836027433383282177081034151589935024292017207209056829250152219183518400364871109559825679273502274955582
  4. n = 135127138348299757374196447062640858416920350098320099993115949719051354213545596643216739555453946196078110834726375475981791223069451364024181952818056802089567064926510294124594174478123216516600368334763849206942942824711531334239106807454086389211139153023662266125937481669520771879355089997671125020789
  5. e = 65537
  6. p = 11239134987804993586763559028187245057652550219515201768644770733869088185320740938450178816138394844329723311433549899499795775655921261664087997097294813
  7. q = 12022912661420941592569751731802639375088427463430162252113082619617837010913002515450223656942836378041122163833359097910935638423464006252814266959128953
  8. # invert是求乘法逆元
  9. d = gmpy2.invert(e,(p-1)*(q-1))
  10. jiemi = hex(pow(c,d,n))[2:]
  11. print(binascii.unhexlify(jiemi))

得到flag的值

b'hgame{factordb.com_is_strong!}'

2、 利用公约数分解N

识别此类题目,通常会发现题目给了多个n,均不相同,并且都是2048bit,4096bit级别,无法正面硬杠,并且明文都没什么联系,e也一般取65537。

这种题目一般可以直接gcd(n1,n2)求出一个因数。

例题攻防世界 (xctf.org.cn)

图3 题目描述

Python代码如下:

  1. import gmpy2
  2. n1 = 23220619839642624127208804329329079289273497927351564011985292026254914394833691542552890810511751239656361686073628273309390314881604580204429708461587512500636158161303419916259271078173864800267063540526943181173708108324471815782985626723198144643256432774984884880698594364583949485749575467318173034467846143380574145455195152793742611717169602237969286580028662721065495380192815175057945420182742366791661416822623915523868590710387635935179876275147056396018527260488459333051132720558953142984038635223793992651637708150494964785475065404568844039983381403909341302098773533325080910057845573898984314246089
  3. n2 = 22642739016943309717184794898017950186520467348317322177556419830195164079827782890660385734113396507640392461790899249329899658620250506845740531699023854206947331021605746078358967885852989786535093914459120629747240179425838485974008209140597947135295304382318570454491064938082423309363452665886141604328435366646426917928023608108470382196753292656828513681562077468846105122812084765257799070754405638149508107463233633350462138751758913036373169668828888213323429656344812014480962916088695910177763839393954730732312224100718431146133548897031060554005592930347226526561939922660855047026581292571487960929911
  4. p = gmpy2.gcd(n1, n2)
  5. print('gcd(n1, n2):n', p)
  6. q1 = n1// p
  7. q2 = n2// p
  8. print('q1 is:n', q1)
  9. print('q2 is:n', q2)

求出了p和q的值,那么问题也就迎刃而解了,最后的flag答案为:flag{336BB5172ADE227FE68BAA44FDA73F3B}。

3、 构造平方数分解模数N

识别此类题目,通常会发现N的两个质因数p和q挨的非常近,这个时候就可以将N加一个比较小的数k,令N+k为平方数,从而解决此类题目。

例题:攻防世界 (xctf.org.cn)

图4 题目代码

设p=q+2k,k是一个相对比较小的数,因为n=pq,所以n=q^{2}+2kq,所以n+k^{2}=(q+k)^{2},我们只要爆破k,使得n+k^{2}是一个平方数,那么p和q就都解出来了。代码如下:

  1. n = 12194420073815392880989031611545296854145241675320130314821394843436947373331080911787176737202940676809674543138807024739454432089096794532016797246441325729856528664071322968428804098069997196490382286126389331179054971927655320978298979794245379000336635795490242027519669217784433367021578247340154647762800402140321022659272383087544476178802025951768015423972182045405466448431557625201012332239774962902750073900383993300146193300485117217319794356652729502100167668439007925004769118070105324664379141623816256895933959211381114172778535296409639317535751005960540737044457986793503218555306862743329296169569
  2. def is_square(n):
  3. low, high, ans = 0, n, -1
  4. while low <= high:
  5. mid = (low + high) // 2
  6. if mid * mid <= n:
  7. ans = mid
  8. low = mid + 1
  9. else:
  10. high = mid - 1
  11. if ans**2 == n:
  12. return True
  13. else:
  14. return False
  15. for i in range(1000):
  16. if is_square(n+i**2):
  17. print(i)
  18. break

得到k的值为716,所以可以解出pq的值,从而flag就出来了,代码如下:

  1. import gmpy2
  2. import binascii
  3. c = 4504811333111877209539001665516391567038109992884271089537302226304395434343112574404626060854962818378560852067621253927330725244984869198505556722509058098660083054715146670767687120587049288861063202617507262871279819211231233198070574538845161629806932541832207041112786336441975087351873537350203469642198999219863581040927505152110051313011073115724502567261524181865883874517555848163026240201856207626237859665607255740790404039098444452158216907752375078054615802613066229766343714317550472079224694798552886759103668349270682843916307652213810947814618810706997339302734827571635179684652559512873381672063
  4. n = 12194420073815392880989031611545296854145241675320130314821394843436947373331080911787176737202940676809674543138807024739454432089096794532016797246441325729856528664071322968428804098069997196490382286126389331179054971927655320978298979794245379000336635795490242027519669217784433367021578247340154647762800402140321022659272383087544476178802025951768015423972182045405466448431557625201012332239774962902750073900383993300146193300485117217319794356652729502100167668439007925004769118070105324664379141623816256895933959211381114172778535296409639317535751005960540737044457986793503218555306862743329296169569
  5. e = 65537
  6. p = 110428348144013242234907008083355974834266917027228724749730385104087025249352345946164980361082178532313669767485270254326404723948153912910688118140621712922649644396733499972695482991866293857864311557686710317462165131360819813493524457615383204504505224030129953230866877990529769205769592709254542472051
  7. q = 110428348144013242234907008083355974834266917027228724749730385104087025249352345946164980361082178532313669767485270254326404723948153912910688118140621712922649644396733499972695482991866293857864311557686710317462165131360819813493524457615383204504505224030129953230866877990529769205769592709254542470619
  8. # invert是求乘法逆元
  9. d = gmpy2.invert(e,(p-1)*(q-1))
  10. jiemi = hex(pow(c,d,n))[2:]
  11. print(binascii.unhexlify(jiemi))

flag{5c9c885c361541e0b261f58b61db8cec}

4、 共模攻击

共模攻击,也称同模攻击。

同模攻击利用的大前提就是,RSA体系在生成密钥的过程中使用了相同的模数n。

在CTF题目中,就是同一明文,同一n,不同e,进行加密。

m,n相同;e,c不同,且e1 和 e2互质

例题:攻防世界 (xctf.org.cn)

题目给了四个文件,先用代码看一下题目信息:

  1. from Crypto.PublicKey import RSA
  2. from Crypto.Util.number import *
  3. f1 = open('publickey1.pem',"rb").read()
  4. f2 = open('publickey2.pem',"rb").read()
  5. c1 = open('cipher1.txt',"rb").read()
  6. c2 = open('cipher2.txt',"rb").read()
  7. pub1 = RSA.importKey(f1)
  8. pub2 = RSA.importKey(f2)
  9. n1 = pub1.n
  10. e1 = pub1.e
  11. n2 = pub2.n
  12. e2 = pub2.e
  13. c1 = bytes_to_long(c1)
  14. c2 = bytes_to_long(c2)
  15. print("n1 =",n1)
  16. print("e1 =",e1)
  17. print("c1 =",c1)
  18. print("n2 =",n2)
  19. print("e2 =",e2)
  20. print("c2 =",c2)

得到:

n1

13060424286033164731705267935214411273739909173486948413518022752305313862238166593214772698793487761875251030423516993519714215306808677724104692474199215119387725741906071553437840256786220484582884693286140537492541093086953005486704542435188521724013251087887351409946184501295224744819621937322469140771245380081663560150133162692174498642474588168444167533621259824640599530052827878558481036155222733986179487577693360697390152370901746112653758338456083440878726007229307830037808681050302990411238666727608253452573696904083133866093791985565118032742893247076947480766837941319251901579605233916076425572961

e1 = 117

c1

12847007370626420814721007824489512747227554004777043129889885590168327306344216253180822558098466760014640870748287016523828261890262210883613336704768182861075014368378609414255982179769686582365219477657474948548886794807999952780840981021935733984348055642003116386939014004620914273840048061796063413641936754525374790951194617245627213219302958968018227701794987747717299752986500496848787979475798026065928167197152995841747840050028417539459383280735124229789952859434480746623573241061465550303008478730140898740745999035563599134667708753457211761969806278000126462918788457707098665612496454640616155477050

n2

13060424286033164731705267935214411273739909173486948413518022752305313862238166593214772698793487761875251030423516993519714215306808677724104692474199215119387725741906071553437840256786220484582884693286140537492541093086953005486704542435188521724013251087887351409946184501295224744819621937322469140771245380081663560150133162692174498642474588168444167533621259824640599530052827878558481036155222733986179487577693360697390152370901746112653758338456083440878726007229307830037808681050302990411238666727608253452573696904083133866093791985565118032742893247076947480766837941319251901579605233916076425572961

e2 = 65537

c2

6830857661703156598973433617055045803277004274287300997634648800448233655756498070693597839856021431269237565020303935757530559600152306154376778437832503465744084633164767864997303080852153757211172394903940863225981142502888126928982009493972076013486758460894416710122811249903322437742241269681934551237431668187006176418124934488775505816544733929241927900392924886649420943699356314278255683484998359663404611236056664149725644051300950988495549164517140159041907329062655574220869612072289849679613024196448446224406889484578310512232665571188351621585528255501546941332782446448144033997067917984719103068519

发现n1和n2的值是相等的,那么就可以通过共模攻击解决此题,原理如下:

共模攻击即用两个及以上的公钥(n,e)来加密同一条信息m

已知有密文:

       

条件:

当e1,e2互质,则有gcd(e1,e2)=1

根据扩展欧几里德算法,对于不完全为 0 的整数 a,b,gcd(a,b)。那么一定存在整数 x,y 使得 gcd(a,b)=ax+by

带入本题,则得到:

e1×s1+e2×s2 = 1s1s2 为变量。

因为e1和e2为正整数,又由于s1、s2皆为整数,但是一正一负,此时假设s1为正数,s2为负数。

这里需要用到两条幂运算的性质:

(a × b) mod p = (a mod p × b mod p) mod p 公式一

mod p = ​​​​​​​  mod p公式二

因为c1 = ​​​​​​​mod n,c2 = ​​​​​​​ mod n,需要证明m=( ​​​​​​​)mod n

先代入公式一可得:

( ​​​​​​​)mod n = ( ​​​​​​​)mod n​​​​​​​

=( ​​​​​​​ )mod n  //代入公式二

=( ​​​​​​​)mod n  //消掉mod n

=( ​​​​​​​)mod n   //同底数幂相乘,底数不变,指数相加

又因为m<n,所以( ​​​​​​​)mod n =m mod n=m

以下为求s1,s2的python代码:

  1. e1 = 117
  2. e2 = 65537
  3. def ext_gcd(a, b): #扩展欧几里得算法
  4. if b == 0:
  5. return 1, 0, a
  6. else:
  7. x, y, gcd = ext_gcd(b, a % b) #递归直至余数等于0(需多递归一层用来判断)
  8. x, y = y, (x - (a // b) * y) #辗转相除法反向推导每层a、b的因子使得gcd(a,b)=ax+by成立
  9. return x, y, gcd
  10. print(ext_gcd(e1,e2))

得到s1=30808,s2=-55,带入上面公式,得到flag:

  1. import binascii  
  2. c1 = 12847007370626420814721007824489512747227554004777043129889885590168327306344216253180822558098466760014640870748287016523828261890262210883613336704768182861075014368378609414255982179769686582365219477657474948548886794807999952780840981021935733984348055642003116386939014004620914273840048061796063413641936754525374790951194617245627213219302958968018227701794987747717299752986500496848787979475798026065928167197152995841747840050028417539459383280735124229789952859434480746623573241061465550303008478730140898740745999035563599134667708753457211761969806278000126462918788457707098665612496454640616155477050  
  3. n = 13060424286033164731705267935214411273739909173486948413518022752305313862238166593214772698793487761875251030423516993519714215306808677724104692474199215119387725741906071553437840256786220484582884693286140537492541093086953005486704542435188521724013251087887351409946184501295224744819621937322469140771245380081663560150133162692174498642474588168444167533621259824640599530052827878558481036155222733986179487577693360697390152370901746112653758338456083440878726007229307830037808681050302990411238666727608253452573696904083133866093791985565118032742893247076947480766837941319251901579605233916076425572961  
  4. c2 = 6830857661703156598973433617055045803277004274287300997634648800448233655756498070693597839856021431269237565020303935757530559600152306154376778437832503465744084633164767864997303080852153757211172394903940863225981142502888126928982009493972076013486758460894416710122811249903322437742241269681934551237431668187006176418124934488775505816544733929241927900392924886649420943699356314278255683484998359663404611236056664149725644051300950988495549164517140159041907329062655574220869612072289849679613024196448446224406889484578310512232665571188351621585528255501546941332782446448144033997067917984719103068519  
  5. s1 = 30808  
  6. s2 = -55  
  7. jiemi = hex(pow(pow(c1,s1,n)*pow(c2,s2,n),1,n))[2:]    
  8. print(binascii.unhexlify(jiemi))  
  9. flag{interesting_rsa}

5、 低指数攻击

加密指数指的是e,e一般选取65535,当e很小,可直接破解。这类攻击在CTF题中,一般是 e=3

图5 低指数攻击原理

例题:BUUCTF在线评测 (buuoj.cn)

图6 题目描述

从题目发现,e的值非常的小,为3。由于 ​​​​​​​ ,因而 ​​​​​​​,只要爆破k,使得kn+c 是一个立方数即可。Python代码如下:

  1. import gmpy2  
  2. from Crypto.Util.number import *   
  3. n = 0x52d483c27cd806550fbe0e37a61af2e7cf5e0efb723dfc81174c918a27627779b21fa3c851e9e94188eaee3d5cd6f752406a43fbecb53e80836ff1e185d3ccd7782ea846c2e91a7b0808986666e0bdadbfb7bdd65670a589a4d2478e9adcafe97c6ee23614bcb2ecc23580f4d2e3cc1ecfec25c50da4bc754dde6c8bfd8d1fc16956c74d8e9196046a01dc9f3024e11461c294f29d7421140732fedacac97b8fe50999117d27943c953f18c4ff4f8c258d839764078d4b6ef6e8591e0ff5563b31a39e6374d0d41c8c46921c25e5904a817ef8e39e5c9b71225a83269693e0b7e3218fc5e5a1e8412ba16e588b3d6ac536dce39fcdfce81eec79979ea6872793  
  4. e = 3  
  5. c = 0x10652cdfaa6b63f6d7bd1109da08181e500e5643f5b240a9024bfa84d5f2cac9310562978347bb232d63e7289283871efab83d84ff5a7b64a94a79d34cfbd4ef121723ba1f663e514f83f6f01492b4e13e1bb4296d96ea5a353d3bf2edd2f449c03c4a3e995237985a596908adc741f32365  
  6. def de(c, e, n):  
  7.     k = 0  
  8.     while True:  
  9.         m = c + n*k  
  10.         result, flag = gmpy2.iroot(m, e)  
  11.         if True == flag:  
  12.             return result  
  13.         k += 1  
  14. m = de(c,e,n)  
  15. print(long_to_bytes(m)) 

得到flag的值b'flag{25df8caf006ee5db94d48144c33b2c3b}'

6、 低指数广播攻击

如果选取的加密指数较低,并且使用了相同的加密指数给一个接受者的群发送相同的信息,那么可以进行广播攻击得到明文。

CTF中,n、c不同,明文m,e相同,其e比较小。使用中国剩余定理求解。

例题:攻防世界 (xctf.org.cn)

图7 题目描述

这道题在求E2的时候用到了低指数广播攻击。由于题目告知了E2的89次方分别模三个不同的数得到的不同的结果,因而可以用中国剩余定理进行解决。原理也就是先解决同余方程:

找到其中的一个解mx ,那么就一定有 ​​​​​​​,接着按照低指数攻击的方法进行求解。本题中给了三组c和n。

代码如下:

  1. import gmpy2  
  2. import sympy  
  3. from functools import reduce  
  4. def chinese_remainder(n, a):  
  5.     sum = 0  
  6.     prod = reduce(lambda a, b: a * b, n)  
  7.    
  8.     for n_i, a_i in zip(n, a):  
  9.         p = prod // n_i  
  10.         sum += a_i * sympy.invert(p, n_i) * p  
  11.     return int(sum % prod)  
  12. ns=[158632305865006849113563847421234041202136990520180485886503920099275653696854972563446821501899231310095863236405077737069977048608986829463080310203613023342488952332559113483651791537991973417448631349268046039735074156978104409163050923951803822397295508336078475240053911374744978490770975744521153793684635400871728009022108221436870148136313663606525832162691381167854894857724378705288920321197299296078574596210787905111440607100359338873372083010788921638372034120811145101434060138923936079325969213088890589095445846196763807664854931148147538782728818669072102356818776894936716685342517783976586705181171414409846943861935868265282850774438169729355667071768555358571966500244047625600847123531382605174000908351086071499120104791573721610222024262167484160098712200591454206196361827227598683592867392037576827239091277874150265590928139094860646784711837764135754793147258883672633975857603827382047087963755545844624340124815167526660265667736081956374476552249564082149669491851566924361414170474484898074610156978543972858514484165566595938946051262880078274276414777315043055285933126966762694299339210189766171987137572114324027021182126926095038094467019586301662159438723633931793830527351071941957830844946518327563822879593503938377821960427219022565215631856333510782568496016547757945464794632272818101891677705256471714805217606503652132995136255720639088424576003650628211271025648183600635145895528466199068640094470078526413324708028578289949241288828542143203769199399500669311878391255837977932634772778594526940501234736059441483897017015324765266787399950699732518347518591167932031031320265136158304460199654008895095274754918153773566824931440342525688741289235153882699461549523425169846266597156773535163599640189457171272058311480951820887261040891344076039474315985825984444520336790670313179493074014037981261]  
  13. cs=[383309560783086294807909732325487278958657695331767109975208326194961660875923129105056654276498497472279022612039972293710450359074035824990008978450849083037953163275216977794920071856703301857718465817701940490381792002446892371544135540467244300772352575076843089542537612467922571568738238011462810305831217634369390011563826500265762261874466624713211465413542904006931636883993888171655490159303190127299294020048446043619369917550037636845670699856406469382000877890034435774569165287550081044714708871528958135150187601204461199097252157025310667115820767749084924961200295449792776216869988611045535448192415024201211772111560916342582596349777090238942787927556944737561630844311237741015128663169899179220520231684011672122842199072725281170246704436989902382430302211170043724564755215023504041374690885701708854092655670843760692569241352702833352421331633035992391814179499802929442032042965981881756327239687796729940907885853433024734423898654593981426341043317435173845892007893314893943756048019519948316473398391126983941413281789675166364525923852481353401337125221357159437875901723347438932596219095324562813628682905564619079367742311669369156698165093784198921491645525481317769797063816414778789314030409428992204063713908492214256291861339175525948946919629972908439132005643626148678347198381531633907182877152728077958345519083406637446972079387161726967295886447791613166577391233866583354793842121902234644830640050181130381996083089350911224037154798259291124104894554037604500881250119806371348673833105103600782286898276354573884788251542211434143476774391457587885772379990104835187104619922442613860682792470389490804228050671124495925536024571104944112397143299499508504917890140939438891891453283594000764399193028606955089853654071198909973555844004685149713774167524224100487937899126480545681565581673958854]  
  14. res = chinese_remainder(ns,cs)  
  15. print(gmpy2.iroot(res,89))  
  16. 得到E2 = 561236991551738188085

7、 拆解e转化

正常的RSA应该有e与φ(n)互素,但是有的题目并不满足,但通常会给两组关于e与φ(n)的等式。这个时候就需要将e进行质因数分解,构造出新的RSA求解。

例题和6一样,6中求出了E2的值,而E1可以通过爆破求解得出,代码如下:

  1. from gmpy2 import invert,iroot  
  2. from Crypto.Util.number import getPrime, isPrime, bytes_to_long  
  3. def next_prime(num: int) -> int:  
  4.     num = num + 2 if num % 2 else num + 1  
  5.     while not isPrime(num):  
  6.         num += 2  
  7.     return num  
  8. n = 1605247600724752598798254639224215706171506359654961357324428027985787942008103766562745464838961569081446916113769517713344420113584254259000172572811154232107339480903672251992191997458469905064423618888336088652352540882576826988355783159237971043770132628344798937353150930071309347972804118952814447576207066147031238749098842662046825743988208813903138796789940911515825517078554074496474819128789835309636804325132602557092847746454786387067599510769382078521691609970320528531270474091713477040343897269903489441410062592732302402854035415438078656688806905350495825334584533345448091335565792091890185673190424063  
  9.   
  10. e = 65537  
  11. c = 751639057610677013264061431434189083017589908118307247217007533938435229431015858783222167911772848893015518607229280589985711010766459396989232072512314594917029375221335361209036112742388866873824163350886610514973038316512032459352053158417705406031466332440378871927174731975794579894912999936641163063898365134788537389162378185448090279397717831977803284480743612393591614284972981435749362255654561121758163485884075260156288337176713756471879489767416836868661153693157792733142765671887792303181376620864506386820826866340907593080654521498766421056474652652337037121881207188033108746890998208582406826010121861  
  12.   
  13. for i in range(2 ** 16,2**15,-1):  
  14.     print('\r'+str((65536-i)/32768*100)+"%",end='')  
  15.     if isPrime(i):  
  16.         q = next_prime(i * iroot(n // i, 2)[0] + 38219)  
  17.         if n % q == 0:  
  18.             print(q)  
  19.             break  
  20. p = n // q  
  21. phi = (p - 1) * (q - 1)  
  22. d = invert(e, phi)  
  23. E1 = pow(c, d, n)  
  24. print(E1)

得到E1的值E1 = 377312346502536339265

接着通过观察,发现n1和n2有共同的因数P,所以可以辗转相除法求出P。

Python代码如下:

  1. import gmpy2  
  2. n1 = 21655617838358037895534605162358784326495251462447218485102155997156394132443891540203860915433559917314267455046844360743623050975083617915806922096697304603878134295964650430393375225792781804726292460923708890722827436552209016368047420993613497196059326374616217655625810171080545267058266278112647715784756433895809757917070401895613168910166812566545593405362953487807840539425383123369842741821260523005208479361484891762714749721683834754601596796707669718084343845276793153649005628590896279281956588607062999398889314240295073524688108299345609307659091936270255367762936542565961639163236594456862919813549  
  3. n2 = 24623016338698579967431781680200075706241014384066250660360949684385831604822817314457973559632215801205780786144608311361063622813017396858888436529116737754653067203843306015767091585697803364656624926853551997229897087731298797904208292585562517602132663331748784390752958757661484560335406769204491939879324079089140420467301773366050084810282369044622442784113688062220370531522036512803461607049619641336524486507388232280683726065679295742456158606213294533956580462863488082028563360006966912264908424680686577344549034033470952036766850596897062924137344079889301948258438680545785139118107899367307031396309  
  4. p = gmpy2.gcd(n1, n2)  
  5. print('gcd(n1, n2):\n', p)  
  6. q1 = n1// p  
  7. q2 = n2// p  
  8. print('q1 is:\n', q1)  
  9. print('q2 is:\n', q2)  

得到结果:

gcd(n1, n2):

 139221606892711163311861502165720779685040991146236819771077311473266519931947605782571900027963055886773086091452724527664738159398782494677824268515616754695749805253260616352348311702497776259344985568675527862394653437170150947836869132073518219409311180128931469597871185033476336585646820347139844842399

q1 is:

 155547822796260230301163493572328276759754179923840369685187766807125087369928975444183346813644731672051277851645460274588975060909127179689654378234675963719955065971621191295992778117297548246126322013897580863954772277036417493420548297592968260640347856809237210752134250598888189729496548294692404268851

q2 is:

176862032325728733112232812799746628539676281475101885729648695725069625447450093015182103211896449720721008446169371711893103335768209077906398522734998474760674095210567056451011572994691734256964295917711714584736577060817163508416373914379207885134617634676468095190710307036248746843930480925386278062091

接着就是本题的题型了,这道题目中q1-1和q2-1都是5的倍数,p-1是7的倍数,而恰巧e1和e2都是35的倍数,不满足e1,e2和(q1-1)和( p-1),(q2-1)和( p-1)互质,原来的方法失效。所以我们要尝试进行转化,构造一个新的RSA。

我们先假设gcd(e,φ(n))=a ,那么就可以将e写成e=E×a 的形式。再构造d使得dEmodφ(n)=1 。由于RSA的加密算法为 ​​​​​​​ ,解密算法为 ​​​​​​​ 其中demodφn=1

那么变形之后可得到:

​​​​​​​

带入本题,可以知道a=35 ​​​​​​​ ​​​​​​​。其中d1E1modφ(n1)=1d2E2mod(φn2)=1e1=aE1e2=aE2

再根据公式若n=pqwmodn=c wmodp=cmodpwmodq=cmodq

因而代入本题,有 ​​​​​​​

为了方便,这里设 ​​​​​​​ ,那么有 ​​​​​​​,根据中国剩余定理,可以很快求出一个数k,使得 ​​​​​​​,于是一个新的RSA就构造好了。由于在本题中q1-1q2-1 都是5的倍数,而a也是5的倍数,并没有满足互质的前提,因而需要变形一下。由于a=35=5×7 。所以 ​​​​​​​ ,7和q1-1q2-1 是互质的,满足RSA的构造条件,因而可以求出m5 的值,最后开五次方就可以得到答案了。Python代码如下:

  1. from Crypto.Util.number import long_to_bytes  
  2. import gmpy2  
  3. import sympy  
  4. from functools import reduce  
  5. n1 = 21655617838358037895534605162358784326495251462447218485102155997156394132443891540203860915433559917314267455046844360743623050975083617915806922096697304603878134295964650430393375225792781804726292460923708890722827436552209016368047420993613497196059326374616217655625810171080545267058266278112647715784756433895809757917070401895613168910166812566545593405362953487807840539425383123369842741821260523005208479361484891762714749721683834754601596796707669718084343845276793153649005628590896279281956588607062999398889314240295073524688108299345609307659091936270255367762936542565961639163236594456862919813549  
  6. n2 = 24623016338698579967431781680200075706241014384066250660360949684385831604822817314457973559632215801205780786144608311361063622813017396858888436529116737754653067203843306015767091585697803364656624926853551997229897087731298797904208292585562517602132663331748784390752958757661484560335406769204491939879324079089140420467301773366050084810282369044622442784113688062220370531522036512803461607049619641336524486507388232280683726065679295742456158606213294533956580462863488082028563360006966912264908424680686577344549034033470952036766850596897062924137344079889301948258438680545785139118107899367307031396309  
  7. c1 = 2615722342860373905833491925692465899705229373785773622118746270300793647098821993550686581418882518204094299812033719020077509270290007615866572202192731169538843513634106977827187688709725198643481375562114294032637211892276591506759075653224150064709644522873824736707734614347484224826380423111005274801291329132431269949575630918992520949095837680436317128676927389692790957195674310219740918585437793016218702207192925330821165126647260859644876583452851011163136097317885847756944279214149072452930036614703451352331567857453770020626414948005358547089607480508274005888648569717750523094342973767148059329557  
  8. c2 = 6769301750070285366235237940904276375318319174100507184855293529277737253672792851212185236735819718282816927603167670154115730023644681563602020732801002035524276894497009910595468459369997765552682404281557968383413458466181053253824257764740656801662020120125474240770889092605770532420770257017137747744565202144183642972714927894809373657977142884508230107940618969817885214454558667008383628769508472963039551067432579488899853537410634175220583489733111861415444811663313479382343954977022383996370428051605169520337142916079300674356082855978456798812661535740008277913769809112114364617214398154457094899399  
  9. E1 = 377312346502536339265  
  10. E2 = 561236991551738188085  
  11. P = gmpy2.gcd(n1,n2)  
  12. Q2 = n2//P  
  13. Q1 = n1//P  
  14. c = [pow(c1, gmpy2.invert(E1 // 35, (P - 1) * (Q1 - 1)), n1),  
  15.      pow(c2, gmpy2.invert(E2 // 35, (P - 1) * (Q2 - 1)), n2)]  
  16. w2 = c[1] %Q2  
  17. w1 = c[0] %Q1  
  18. def chinese_remainder(n, a):  
  19.     sum = 0  
  20.     prod = reduce(lambda a, b: a * b, n)  
  21.     for n_i, a_i in zip(n, a):  
  22.         p = prod // n_i  
  23.         sum += a_i * sympy.invert(p, n_i) * p  
  24.     return int(sum % prod)  
  25. result = chinese_remainder([Q1,Q2],[w1,w2])  
  26. d = gmpy2.invert(7,(Q1-1)*(Q2-1))   
  27. n = Q1*Q2  
  28. m = pow(result,d,n)  
  29. flag = gmpy2.iroot(m,5)[0]  
  30. print(long_to_bytes(flag))  

得到flag的值flag{27dab675-9e9b-4c1f-99ab-dd9fe49c190a}

8、 多素数分解

这类题目的n并不是两个大素数相乘,往往是多个素数的乘积,但解法是类似的。

例题:攻防世界 (xctf.org.cn)

图8 题目描述

本题的n就是5个大素数的乘积,先将其进行分解。

图9 分解结果图

接着欧拉函数就要相应的进行变化,两个素数的时候,欧拉函数为φ(n)=(p-1)(q-1) ;相应的,多个素数时,欧拉函数就是每个素数减一再乘起来,代码如下:

  1. import gmpy2    
  2. import binascii    
  3. c = 144009221781172353636339988896910912047726260759108847257566019412382083853598735817869933202168  
  4. n = 175797137276517400024170861198192089021253920489351812147043687817076482376379806063372376015921  
  5. E = 0x10001  
  6. data=[9401433281508038261,10252499084912054759,11215197893925590897,11855687732085186571,13716847112310466417]  
  7. phi = 1  
  8. for p in data:  
  9.     phi = phi * (p-1)  
  10. # invert是求乘法逆元    
  11. d = gmpy2.invert(E,phi)   
  12. jiemi = hex(pow(c,d,n))[2:]    
  13. print(binascii.unhexlify(jiemi)) 

得到flag: HSCTF{@Tv0_br3ad5_c1ip_cHe3se_!@}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/388476
推荐阅读
相关标签
  

闽ICP备14008679号