中国剩余定理(CRT) 我们设正整数$m_1,m_2,…,m_k$两两互素,得到同余方程组:
有整数解,在模$M=m_1m_2…m_k$下的解唯一,解为:
$Mi=\frac{M}{m_i},M_i^{-1}$是$M_i$模$m_i$的逆元。
$∏$是求积运算符号 ,类似于$Σ$,求多个数的积。
历史背景 “今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”
韩信点兵,士兵站成三人一列,多出来两人;站成五人一列,多出来三人;站成七人一列,多两人。问共有多少人;
满足第一条:2,5,8,11,14,17,20,23,26,29….
满足第二条:8,13,18,23,28……
满足第三条:9,16,23,30……
23同时满足,但是如何去求后面重复的数值?
相当于加上一个数n,n为3,5,7的倍数,在这里,n最小为105,得所有解为:23+105i,i取某个整数就可以得到所有解。
那么,如何让这个结论推广到所有的情况上呢?
当然,几个数求最小公倍数 很好求,那么这个23该怎么处理呢?
基本原理 我们的祖先想出了一首诗用来求解:
三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五使得知。
三人同行七十稀,把除以3所得的余数用70乘。 五树梅花廿一枝,把除以5所得的余数用21乘。 七子团圆正半月,把除以7所得的余数用15乘。 除百零五便得知,把上述三个积加起来,减去105的倍数,所得的差即为所求。
2×70+3×21+2×15=233
233 % 105 =23
在上面的理论中:70是5,7的倍数,21是3,7的倍数,15是3,5的倍数
所找的三个数中,拿70来说,70在作为5,7倍数的同时,还需要满足模3余1 ,同样,3,7的倍数需要模5余1 ,3,5的倍数需要模7余1 。
原理推广 对于两两互质的一组数$a_1,a_2,a_3……a_n$(数组$A$);让一个解$x$对于所有在$[1,n]$的整数同时满足$x\bmod a_i = m_i$($m_i$数组每个元素也为两两互质),这里就可以应用中国剩余定理 。
在这里,A就相当于刚才每列站的3, 5, 7人。
$m_i$就相当于余下的2, 3, 2人。
x就是我们求的总人数。
我们可以设$M$为$A$数组所有元素的乘积,找出一个$B$数组使得$b_i$是 $\frac M{a_i}$ 的倍数,而且$b_i\bmod a_i=1$,n直接求最小公倍数可以求出。
这里的B数组中的每一个数就相当于刚才的70, 21, 15。
怎么求B? 由B的意思,我们可以知道bi为M/ai的倍数,$b_i\bmod a_i=1$,就有:$b_i=\frac{M}{a_i} k$,$\frac{M}{a_i} k ≡ 1(\bmod a_i)$。
转换一下:$\frac{M}{a_i} k + a_i j = 1$
A两两互质,M为A中所有数的乘积,$\frac M{a_i}$和$a_i$互质,我们这里可以使用拓展欧几里得解出。
经过上面的推导:我们就可以找到一个解:$x_0 = m_1b_1 + m_2b_2 + m_3b_3+ ….. + m_nb_n$,也就相当于$233=70×2+21×3+152$
要找到其他的解,就增加或减少$nt$ ,$t$为随意的一个整数。
RSA引入CRT 题目给出三组n和c(这里的nc只出现01234,为五进制):
1 2 3 4 5 6 7 8 N = 331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004 c = 310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243 N = 302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114 c = 112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344 N = 332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323 c = 10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242
根据上面给的三组数,我们可以得到:
$m^e ≡ c_1 (\bmod n_1)$
$m^e ≡ c_2 (\bmod n_2)$
$m^e ≡ c_3 (\bmod n_3)$
求整数的乘积 :$N=n_1n_2n_3$
求除ni以外的整数乘积 :$N_1=\frac N{n_1},N_2=\frac N{n_2},N_3=\frac N{n_3}$
此时,我们可以使用中国剩余定理求解出其中的$m^e$,进而求出$m$。
由于这里模$n$,当$m^e<N$时,才可以用这个方法。因为最终求得的是将同余式转换为了等式,等式两边都不超过$N$:
在模$N$的意义下 ,方程组只有唯一解:
所以可以求得$m^e$,并且对$m$开$e$次方可得到最终的$m$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import gmpy2from Crypto.Util.number import *n1 = int ('331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004' ,5 ) c1 = int ('310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243' ,5 ) n2 = int ('302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114' ,5 ) c2 = int ('112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344' ,5 ) n3 = int ('332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323' ,5 ) c3 = int ('10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242' ,5 ) N=n1*n2*n3 N1=N//n1;N2=N//n2;N3=N//n3 m_e=(c1*N1*gmpy2.invert(N1,n1)+c2*N2*gmpy2.invert(N2,n2)+c3*N3*gmpy2.invert(N3,n3))%N for e in range (1 ,100 ): flag=long_to_bytes(gmpy2.iroot(m_e,e)[0 ]) if flag[-1 ]==125 : print (flag)
long_to_bytes转换的本质还是ASCII码,”}”ASCII为125,可以用这个筛选出符合条件的flag。
实际上,long_to_bytes是在函数内部自行做了先把数字转16进制再将16进制数两两一组转换成ASCII码对应字符。
在libnum库里,有solve_crt
函数帮助我们计算中国剩余定理:以上代码可以简化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import gmpy2from libnum import *from Crypto.Util.number import *n1 = int ('331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004' ,5 ) c1 = int ('310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243' ,5 ) n2 = int ('302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114' ,5 ) c2 = int ('112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344' ,5 ) n3 = int ('332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323' ,5 ) c3 = int ('10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242' ,5 ) m_e=solve_crt([c1,c2,c3],[n1,n2,n3]) for e in range (1 ,100 ): flag=long_to_bytes(gmpy2.iroot(m_e,e)[0 ]) if flag[-1 ]==125 : print (flag)
低加密指数广播攻击 广播 就是发送方将一份明文进行多份加密,每份使用不同的n,但是指数e相同且很小,因此我们只要得到多份密文和对应的n就可以利用中国剩余定理 进行解密。
例题
1 2 3 4 5 6 7 8 9 10 [{"c" : 7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042 , "e" : 10 , "n" : 25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803 }, {"c" : 21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461 , "e" : 10 , "n" : 23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193 }, {"c" : 6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983 , "e" : 10 , "n" : 18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623 }, {"c" : 4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052 , "e" : 10 , "n" : 23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723 }, {"c" : 22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672 , "e" : 10 , "n" : 31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493 }, {"c" : 17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087 , "e" : 10 , "n" : 22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949 }, {"c" : 1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639 , "e" : 10 , "n" : 25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043 }, {"c" : 15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352 , "e" : 10 , "n" : 32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047 }, {"c" : 8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797 , "e" : 10 , "n" : 52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553 }, {"c" : 13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247 , "e" : 10 , "n" : 30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621 }]
题目给出了多组n和c,以及相同的e,我们可以使用中国剩余定理对其进行攻击:
在这里,由于组数过多,如果不用库函数的话不方便像上面那样挨个计算,可以建立数组 遍历进行计算:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import gmpy2from Crypto.Util.number import *e = 10 c = [7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042 , 21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461 ,6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983 ,4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052 ,22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672 ,17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087 ,1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639 ,15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352 ,8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797 ,13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247 ]n = [25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803 , 23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193 ,18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623 ,23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723 ,31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493 ,22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949 ,25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043 ,32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047 ,52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553 ,30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621 ]N=1 m_e=0 for i in range (len (n)): N*=n[i] for i in range (len (n)): m_e=m_e+c[i]*N//n[i]*gmpy2.invert(N//n[i],n[i]) m_e=m_e%N print (long_to_bytes(gmpy2.iroot(m_e,e)[0 ]))
扩展中国剩余定理 在学习CRT中我们了解到构成求解CRT的方程组模数需要两两互质,如果模数是不互质的,可以通过合并相邻两组方程的方式进行逐步求解,这就是扩展中国剩余定理。
扩展中国剩余定理跟中国剩余定理几乎没有关系,扩展CRT是用扩展欧几里得,CRT是用构造的思想。
根据同样的同余方程组,但是模数不互素:
选择前两个式子,转换成等式:
两式子相减得到$k_1m_1-k_2m_2=a_2-a_1$,把$k_1,-k_2$看做$x_k,y_k$,式子就能转化为:
根据裴蜀定理,当$\gcd(m_1,m_2)|(a_2-a_1)$时,就可以使用扩展欧几里得算法求出系数$x_k,y_k$,这里计算得到的式子为:
为了求得$x_k,y_k$,可以对式子两边同时乘$\frac {a_2-a_1}{\gcd(m_1,m_2)}$,得到特解:
我们需要用过特殊解来构造一般解,一般式子为:
特殊解变形为:
代入$x_0m_1+y_0m_2=\gcd(m_1,m_2)$仍成立,此时构造的$x_k,y_k$就是通解。
现在将得到的通解代入到最开始的式子$x=k_1m_1+a_1$:
根据数论的有关知识可以知道$\mathrm{lcm}(m_1,m_2)=\frac{m_1m_2}{\gcd(m_1,m_2)}$,原式可以进一步化为:
化为同余式子:
现在,我们就把两个同余式合并为了一个同余方程:
那么,如果我们不断的合并,进行$n-1$次合并,就能将$n$个同余方程合并为一个同余方程,如果只有一个同余方程,就可以使用扩展欧几里得算法进行计算。
求$d$ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import gmpy2from Crypto.Util.number import *p = getPrime(512 ) q = getPrime(512 ) r = getPrime(512 ) e = getPrime(32 ) print (e)n = p*q*r phi = (p-1 )*(q-1 )*(r-1 ) d = gmpy2.invert(e,phi) dp = d%((q-1 )*(r-1 )) dq = d%((p-1 )*(r-1 )) dr = d%((p-1 )*(q-1 )) flag = 'flag{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}' m = bytes_to_long(flag.encode()) c = pow (m,e,n) print (p)print (q)print (r)print (dp)print (dq)print (dr)print (c)p=12922128058767029848676385650461975663483632970994721128398090402671357430399910236576943902580268365115559040908171487273491136108931171215963673857907721 q=10395910293559541454979782434227114401257890224810826672485874938639616819909368963527556812339196570118998080877100587760101646884011742783881592586607483 r=8104533688439480164488403019957173637520526666352540480766865791142556044817828133446063428255474375204188144310967625626318466189746446739697284656837499 dp=73360412924315743410612858109886169233122608813546859531995431159702281180116580962235297605024326120716590757069707814371806343766956894408106019058184354279568525768909190843389534908163730972765221403797428735591146943727032277163147380538250142612444372315262195455266292156566943804557623319253942627829 dq=40011003982913118920477233564329052389422276107266243287367766124357736739027781899850422097218506350119257015460291153483339485727984512959771805645640899525080850525273304988145509506962755664208407488807873672040970416096459662677968243781070751482234692575943914243633982505045357475070019527351586080273 dr=21504040939112983125383942214187695383459556831904800061168077060846983552476434854825475457749096404504088696171780970907072305495623953811379179449789142049817703543458498244186699984858401903729236362439659600561895931051597248170420055792553353578915848063216831827095100173180270649367917678965552672673 c=220428832901130282093087304800127910055992783874826238869471313726515822196746908777026147887315019800546695346099376727742597231512404648514329911088048902389321230640565683145565701498095660019604419213310866468276943241155853029934366950674139215056682438149221374543291202295130547776549069333898123270448986380025937093195496539532193583979030254746589985556996040224572481200667498253900563663950531345601763949337787268884688982469744380006435119997310653
这个题目中我们并不知道$e,d$,直接进行求解肯定是解不出来的,但是给了$dp,dq,dr$,先观察一下三个式子,尝试使用扩展中国剩余定理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from Crypto.Util.number import *import gmpy2p=12922128058767029848676385650461975663483632970994721128398090402671357430399910236576943902580268365115559040908171487273491136108931171215963673857907721 q=10395910293559541454979782434227114401257890224810826672485874938639616819909368963527556812339196570118998080877100587760101646884011742783881592586607483 r=8104533688439480164488403019957173637520526666352540480766865791142556044817828133446063428255474375204188144310967625626318466189746446739697284656837499 dp=73360412924315743410612858109886169233122608813546859531995431159702281180116580962235297605024326120716590757069707814371806343766956894408106019058184354279568525768909190843389534908163730972765221403797428735591146943727032277163147380538250142612444372315262195455266292156566943804557623319253942627829 dq=40011003982913118920477233564329052389422276107266243287367766124357736739027781899850422097218506350119257015460291153483339485727984512959771805645640899525080850525273304988145509506962755664208407488807873672040970416096459662677968243781070751482234692575943914243633982505045357475070019527351586080273 dr=21504040939112983125383942214187695383459556831904800061168077060846983552476434854825475457749096404504088696171780970907072305495623953811379179449789142049817703543458498244186699984858401903729236362439659600561895931051597248170420055792553353578915848063216831827095100173180270649367917678965552672673 c=220428832901130282093087304800127910055992783874826238869471313726515822196746908777026147887315019800546695346099376727742597231512404648514329911088048902389321230640565683145565701498095660019604419213310866468276943241155853029934366950674139215056682438149221374543291202295130547776549069333898123270448986380025937093195496539532193583979030254746589985556996040224572481200667498253900563663950531345601763949337787268884688982469744380006435119997310653 n = 3 a = [dp,dq,dr] m=[(q-1 )*(r-1 ),(p-1 )*(r-1 ),(p-1 )*(q-1 )] def CRText (): if n == 1 : return a[0 ] for i in range (n): gcd ,x ,y = gmpy2.gcdext(m[0 ], m[i]) lcm = m[i] // gcd x = (a[i] - a[0 ]) // gcd * x % lcm a[0 ] = x * m[0 ] + a[0 ] m[0 ] = m[0 ] * m[i] // gcd a[0 ] = (a[0 ] % m[0 ] + m[0 ]) % m[0 ] return a[0 ] d = CRText() m=pow (c,d,p*q*r) print (long_to_bytes(m))
求$c$ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from Crypto.Util.number import *import randomflag='' table='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' pad=100 -len (flag) for i in range (pad): flag+=random.choice(table).encode() e=343284449 m=bytes_to_long(flag) assert m>(1 <<512 )assert m<(1 <<1024 )p=getPrime(512 ) q=getPrime(512 ) r=getPrime(512 ) print ('p=' ,p)print ('q=' ,q)print ('r=' ,r)n1=p*q n2=q*r c1=pow (m,e,n1) c2=pow (m,e,n2) print ('c1=' ,c1)print ('c2=' ,c2)p= 11820891196647569262137841192985418014377132106496147254821784946481523526822939129065042819464351666077658751406165276121125571355594004514547517855730743 q= 10450390015864176713581330969519712299844487112687677452105216477861582967322473997670559995588440097951786576039009337782247912476227937589298529580432797 r= 9484954066160968219229920429258150817546418633451929876581842443665029377287119340232501682142185708534413073877473741393278935479791561681402673403009771 c1= 69574855207460025252857869494766338442370688922127811393280455950372371842144946699073877876005649281006116543528211809466226185922844601714337317797534664683681334132261584497953105754257846471069875622054326463757746293958069752489458646460121725019594141157667480846709081917530190233900184428943585065316 c2= 66183492015178047844987766781469734325646160179923242098082430373061510938987908656007752256556018402101435698352339429316390909525615464024332856855411414576031970267795270882896721069952171988506477519737923165566896609181813523905810373359029413963666924039857159685161563252396502381297700252749204993228
这个题可以发现$e$是$q$的因子,而且还对flag做了填充处理,直接解密是肯定不行的,思想是通过扩展中国剩余定理求出$n=pr$的对应的密文进行解密:
最后求得的$m^e$可以放在模$pr$域中,进行求解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 from Crypto.Util.number import *import gmpy2p = 11820891196647569262137841192985418014377132106496147254821784946481523526822939129065042819464351666077658751406165276121125571355594004514547517855730743 q = 10450390015864176713581330969519712299844487112687677452105216477861582967322473997670559995588440097951786576039009337782247912476227937589298529580432797 r = 9484954066160968219229920429258150817546418633451929876581842443665029377287119340232501682142185708534413073877473741393278935479791561681402673403009771 e = 343284449 c1 = 69574855207460025252857869494766338442370688922127811393280455950372371842144946699073877876005649281006116543528211809466226185922844601714337317797534664683681334132261584497953105754257846471069875622054326463757746293958069752489458646460121725019594141157667480846709081917530190233900184428943585065316 c2 = 66183492015178047844987766781469734325646160179923242098082430373061510938987908656007752256556018402101435698352339429316390909525615464024332856855411414576031970267795270882896721069952171988506477519737923165566896609181813523905810373359029413963666924039857159685161563252396502381297700252749204993228 n = 2 a = [c1, c2] m = [p * q, q * r] def CRText (): if n == 1 : return a[0 ] for i in range (n): gcd, x, y = gmpy2.gcdext(m[0 ], m[i]) lcm = m[i] // gcd x = (a[i] - a[0 ]) // gcd * x % lcm a[0 ] = x * m[0 ] + a[0 ] m[0 ] = m[0 ] * m[i] // gcd a[0 ] = (a[0 ] % m[0 ] + m[0 ]) % m[0 ] return a[0 ] c = CRText() n = p * r phi = (p - 1 ) * (r - 1 ) d = gmpy2.invert(e, phi) print (long_to_bytes(pow (c, d, n)))
公钥解析和加密协议 SSH和SSL都是加密协议,用于保护网络通信的安全性和完整性。
SSH(Secure Shell)是一种网络协议,用于远程访问和管理服务器 。它提供了加密的连接和认证机制,使得数据传输更加安全。SSH通常用于远程登录、文件传输和远程执行命令 等操作。SSH通常基于TCP/IP,使用公钥加密和私钥解密的方式来保护通信的安全性。
SSL(Secure Sockets Layer)是一种协议,用于在互联网上建立安全的通信通道。它可以在客户端和服务器之间建立加密的连接,保护数据的隐私和完整性。SSL最初是由网景公司开发的,后来被标准化为TLS(Transport Layer Security)。SSL/TLS通常用于保护Web浏览器和Web服务器之间的通信,以及其他类型的网络应用程序。
虽然SSH和SSL/TLS都提供了加密和认证机制,但它们的应用场景和安全需求有所不同。SSH通常用于远程管理和维护服务器,需要保护管理者的身份和服务器的机密信息;而SSL/TLS通常用于保护Web应用程序和电子商务等网络应用,需要保护用户的身份和敏感信息。
PEM(Privacy-Enhanced Mail)是一种常见的文件格式,通常用于存储加密证书、私钥和其他与网络安全相关的敏感信息。
对于SSL的公钥解析,这种题目会提供两个文件,一个key文件,一个enc文件,我们需要利用key文件提取n和e,进而破解enc文件。
用记事本打开key文件,可以得到如下加密信息:
——-BEGIN PUBLIC KEY——- MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMAzLFxkrkcYL2wch21CM2kQVFpY9+7+ /AvKr1rzQczdAgMBAAE= ——-END PUBLIC KEY——-
如何破解这段加密后的文本,一种方式是可以使用公钥解析网站来解析:
SSL在线工具-公钥解析 (hiencode.com)
或者导入Crypto库直接获得n和e(注意函数末尾添加的内容区别决定输出对象):
1 2 3 4 5 6 7 8 9 10 from Crypto.PublicKey import RSAkey = RSA.import_key(open ("pub.key" ).read()).export_key print (key)key = RSA.import_key(open ("pub.key" ).read()).n print (key)key = RSA.import_key(open ("pub.key" ).read()).e print (key)
获得了n和e之后,我们想办法分解模数后,使用rsa库直接解密,用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import gmpy2import rsae=65537 p = 285960468890451637935629440372639283459 q = 304008741604601924494328155975272418463 n=p*q phi = (p-1 )*(q-1 ) d = gmpy2.invert(e,phi) key = rsa.PrivateKey(n,e,d,q,p) with open ("flag.enc" ,"rb+" ) as f: f = f.read() print (rsa.decrypt(f,key))
了解了上面的大致理论之后,下面介绍几种和密钥相关的题目。
私钥泄露问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from Crypto.PublicKey import RSAimport libnumimport gmpy2import uuidflag = "flag{" + str (uuid.uuid4()) + "}" print (flag)m = libnum.s2n(flag) p = libnum.generate_prime(1024 ) q = gmpy2.next_prime(p) n = p * q e = 65537 phi = (p - 1 ) * (q - 1 ) d = gmpy2.invert(e, phi) m = libnum.s2n(flag) c = pow (m, e, n) c1 = libnum.n2s(int (c)) with open ("flag.pem" , "wb" ) as f: f.write(c1) rsa_components = (int (n), int (e), int (d), int (p), int (q)) keypair = RSA.construct(rsa_components) with open ("pubckey.pem" , "wb" ) as f: f.write(keypair.exportKey())
得到两个文件,一个flag.pem,一个pubckey.pem,使用RSA库进行的加密,直接用RSA库的importKey
就可以进行解密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from Crypto.PublicKey import RSAimport libnumwith open ("flag.pem" , 'rb' ) as f: c = int (f.read().hex (),16 ) with open ("pubckey.pem" , 'rb' ) as f: key = f.read() rsakey = RSA.importKey(key) d = rsakey.d n = rsakey.n m = pow (c,d,n) print (libnum.n2s(m))
模数分解问题 实际上题目才不会傻到连私钥都提供给我们,通常是提供模数和$e$,如果针对特定情况生成的$n$,可以进行分解并破解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from Crypto.PublicKey import RSAimport libnumimport gmpy2import uuidflag = "flag{" + str (uuid.uuid4()) + "}" print (flag)m = libnum.s2n(flag) p = libnum.generate_prime(1024 ) q = gmpy2.next_prime(p) n = p * q e = 65537 phi = (p - 1 ) * (q - 1 ) d = gmpy2.invert(e, phi) m = libnum.s2n(flag) c = pow (m, e, n) c1 = libnum.n2s(int (c)) with open ("flag1.pem" , "wb" ) as f: f.write(c1) rsa_components = (int (n), int (e)) keypair = RSA.construct(rsa_components) with open ('pubckey1.pem' , 'wb' ) as f: f.write(keypair.exportKey())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPimport libnum, sympy, gmpy2with open ("flag1.pem" , "rb" ) as f: c = f.read() c = libnum.s2n(c) with open ("pubckey1.pem" , "rb" ) as f: key = f.read() rsakey = RSA.importKey(key) n = rsakey.n e = rsakey.e phi = int (sympy.totient(n)) d = gmpy2.invert(e, phi) m = pow (c, d, n) print (libnum.n2s(int (m)))
OAEP
OAEP(Optimal Asymmetric Encryption Padding)在加密过程中,使用RSA等非对称加密算法加密数据。为了增加安全性,需要对待加密的数据进行填充。OAEP利用随机数和哈希函数的特性来增加加密数据的复杂性和随机性。
使用OAEP填充时,待加密的数据会先经过一个哈希函数,生成一个哈希值(通常用SHA-1或SHA-256等)。然后,将该哈希值与随机生成的填充数据进行异或运算。最后,将结果与原始数据进行拼接,形成一个新的数据块,再使用非对称加密算法进行加密。
在解密过程中,同样使用OAEP填充方案。解密时,首先对密文进行解密得到一个新的数据块,然后对该数据块进行逆操作,还原填充前的数据。最后,从还原后的数据中提取出原始数据。
OAEP填充方案提供了比传统的非对称加密更高的安全性,并且能够防范对抗选择明文攻击等攻击方式。它被广泛应用于各种加密协议和算法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPimport libnumimport gmpy2import uuidflag = "flag{" + str (uuid.uuid4()) + "}" print (flag)flag = flag.encode() p = libnum.generate_prime(1024 ) q = gmpy2.next_prime(p) n = p * q e = 65537 phi = (p - 1 ) * (q - 1 ) d = gmpy2.invert(e, phi) rsa_components = (int (n), int (e), int (d)) keypair = RSA.construct(rsa_components) with open ('prikey2.pem' , 'wb' ) as f: f.write(keypair.exportKey()) rsa_components = (int (n), e) arsa = RSA.construct(rsa_components) rsakey = RSA.importKey(arsa.exportKey()) rsakey = PKCS1_OAEP.new(rsakey) c = rsakey.encrypt(flag) with open ("flag2.pem" , "wb" ) as f: f.write(c)
pycryptodome库提供了进行OAEP加密的操作,当然也提供了解密的操作,需要提供公私钥:
1 2 3 4 5 6 7 8 9 10 11 12 from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPwith open ("flag2.pem" , 'rb' ) as f: ciphertext = f.read() with open ("prikey2.pem" , 'rb' ) as f: key = f.read() rsakey = RSA.importKey(key) cipher = PKCS1_OAEP.new(rsakey) message = cipher.decrypt(ciphertext) print (message)