2020年羊城杯Crypto的RRRRRRRSA
本来是在复现第七届“湖湘杯” Crypto 的signin
,但是查的资料都说和 2020 年羊城杯 Crypto 的 RRRRRRRSA
的原理是一样的,所以也顺便把这道题看了。
打开附件,代码如下:
import hashlib
import sympy
from Crypto.Util.number import *
flag = 'GWHT{************}'
flag1 = flag[:19].encode()
flag2 = flag[19:].encode()
assert(len(flag) == 38)
P1 = getPrime(1038)
P2 = sympy.nextprime(P1)
assert(P2 - P1 < 1000)
Q1 = getPrime(512)
Q2 = sympy.nextprime(Q1)
N1 = P1 * P1 * Q1
N2 = P2 * P2 * Q2
E1 = getPrime(1024)
E2 = sympy.nextprime(E1)
m1 = bytes_to_long(flag1)
m2 = bytes_to_long(flag2)
c1 = pow(m1, E1, N1)
c2 = pow(m2, E2, N2)
output = open('secret', 'w')
output.write('N1=' + str(N1) + '\n')
output.write('c1=' + str(c1) + '\n')
output.write('E1=' + str(E1) + '\n')
output.write('N2=' + str(N2) + '\n')
output.write('c2=' + str(c2) + '\n')
output.write('E2=' + str(E2) + '\n')
output.close()
由于涉及了 RSA
的连分数低解密指数
攻击,我并没有这方面的知识储备,所以下面话语中大部分参考自师傅 前方是否可导?
和mortal15
> 对应的参考博客地址:
> https://blog.csdn.net/weixin_44110537/article/details/108560055
> https://blog.csdn.net/a5555678744/article/details/117701126
先放上以前的RSA
图来回顾一下基本流程:
.
.
wiener attack原理阐述:
在 RSA 中我们根据ed =1 mod ψ(n)有如下推导:
ed =1 mod ψ(n) ⇒ ed =1 mod phi ⇒ ed -1 =kphi ⇒ e/phi - k/d =1/(dphi)
可以发现当 p,q 很大时,phi 和 n 是接近的,即phi(N)≈N,且phi(N)非常大。1/(d*phi) 很小,说明 e/phi 和 k/d 很接近,于是就有 e/n
和 k/d
很接近。
当 e 很大时,由于 e 和 N 都是已知
的,通过对 e/n 进行连分数展开
,然后对每一项求其渐进分数,通过遍历渐进分数 k/d 很有可能就被 e/n 的众多项渐进分数中的一项所覆盖
,只要检验
一下 ed mod phi(N) 看它是不是1就知道对不对了。
假设覆盖它的是 k1/d1,那么 k1=k
; d1=d
,得到两个数之后就可以用常规的 RSA
解题流程解题了。
wiener attack
就是这样一个依靠连分数进行的攻击方式,适用于非常接近某一值(比如1)时,求一个比例关系
,通过该比例关系再来反推关键信息就简单很多,这种攻击对于解密指数 d
很小,即 e
和 N
很相近,位数将近一样时有很好的效果。
特别的:wiener attack并不是针对于
解密指数的攻击方式,实际上,在低解密指数的情况下,任何比例
非常接近另外一个
已知比例的情况下都可以尝试用这个方法得到RSA中重要解密信息,不一定是 d
,也有可能是 p
或者 q
。
.
.
补充1:
这里可能会有疑问,如果 gcd(k,d)!=1
那么对于最简的 k1/d1 来说是否应该存在t使得 tk1=k td1=d 呢? 但其实这里 gcd(k,d) 一定为 1 即 k,d 一定互质.证明也很简单.前面我们可以得到: ed-kphi=1 对于这么一个式子,在扩展欧几里得里有如果gcd(d,k)!=1 那么该该方程无解
.(不互质可以提出一个不为1公因子,除过去左边全是整数而右边却是真分数显然不可能)
.
.
补充2:什么是连分数
连分数(continued fraction)是特殊繁分数。如果a0,a1,a2,…an,…都是整数,则将分别称为无限连分数和有限连分数。可简记为a0 ,a1,a2,…,an,…和a0,a1,a2,…,an。一般一个有限连分数表示一个有理数,一个无限连分数表示一个无理数。如果a0,a1,a2,…,an,…都是实数,可将上述形式连分数分别叫无限连分数和有限连分数 。近代数学的计算需要,还可将连分数中的a0,a1 ,a2,…,an,…取成以x为变元的多项式。在近代计算数学中它常与某些微分方程式差分方程有关,与某些递推关系有关的函数构造的应用相联系。
举例如:
127/52 = 2 + 1/2+ 1/3+ 1/1+ 1/5
那连分数项目就是[2,2,3,1,5]
.
.
.
.
.
.
现在我们回过头来看回题目,题目先是把 flag
分成两部分(其实两部分加密方式是一样的),然后生成两个非常接近
的大素数P1,P2
,然后生成了两个相邻的较小
的大素数Q1、Q2
,用P1的平方和Q1相乘得到N1,N2则是用P2的平方和Q2相乘,再用两个相近
巨大的加密指数E加密。
但是和普通的wiener attack 不同
的是,e与N并没有相近
到相除约为1
的地步,相差还是很大的,也就是说解密指数 d
也许还是很大的。
有意思的是 e
和 N
的关系不符合
利用条件,但是N1
和N2
的关系却适合,由于(P1/P2)**2
接近于1
,所以 N1/N2
的比例
很相近于Q1/Q2
。
.
.
仿照 e/n 来展开:
通过:N1/N2=(P1/P2)**2 * (Q1/Q2)显然我们可以知道的是N1/N2 <Q1/Q2
所以在Q1/Q2
在区间(N1/N2,1)之间 (这是关键,不用P1/P2是因为平方不好求)
尝试对N1/N2
进行连分数展开
并求其各项渐进分数,其中某个连分数的分子
可能就是Q1(这个可以依靠N1%Q1==0
来验证)
.
.
代码如下:
import gmpy2
N1=60143104944034567859993561862949071559877219267755259679749062284763163484947626697494729046430386559610613113754453726683312513915610558734802079868190554644983911078936369464590301246394586190666760362763580192139772729890492729488892169933099057105842090125200369295070365451134781912223048179092058016446222199742919885472867511334714233086339832790286482634562102936600597781342756061479024744312357407750731307860842457299116947352106025529309727703385914891200109853084742321655388368371397596144557614128458065859276522963419738435137978069417053712567764148183279165963454266011754149684758060746773409666706463583389316772088889398359242197165140562147489286818190852679930372669254697353483887004105934649944725189954685412228899457155711301864163839538810653626724347
c1=55094296873556883585060020895253176070835143350249581136609315815308788255684072804968957510292559743192424646169207794748893753882418256401223641287546922358162629295622258913168323493447075410872354874300793298956869374606043622559405978242734950156459436487837698668489891733875650048466360950142617732135781244969524095348835624828008115829566644654403962285001724209210887446203934276651265377137788183939798543755386888532680013170540716736656670269251318800501517579803401154996881233025210176293554542024052540093890387437964747460765498713092018160196637928204190194154199389276666685436565665236397481709703644555328705818892269499380797044554054118656321389474821224725533693520856047736578402581854165941599254178019515615183102894716647680969742744705218868455450832
E1=125932919717342481428108392434488550259190856475011752106073050593074410065655587870702051419898088541590032209854048032649625269856337901048406066968337289491951404384300466543616578679539808215698754491076340386697518948419895268049696498272031094236309803803729823608854215226233796069683774155739820423103
N2=60143104944034567859993561862949071559877219267755259679749062284763163484947626697494729046430386559610613113754453726683312513915610558734802079868195633647431732875392121458684331843306730889424418620069322578265236351407591029338519809538995249896905137642342435659572917714183543305243715664380787797562011006398730320980994747939791561885622949912698246701769321430325902912003041678774440704056597862093530981040696872522868921139041247362592257285423948870944137019745161211585845927019259709501237550818918272189606436413992759328318871765171844153527424347985462767028135376552302463861324408178183842139330244906606776359050482977256728910278687996106152971028878653123533559760167711270265171441623056873903669918694259043580017081671349232051870716493557434517579121
c2=39328446140156257571484184713861319722905864197556720730852773059147902283123252767651430278357950872626778348596897711320942449693270603776870301102881405303651558719085454281142395652056217241751656631812580544180434349840236919765433122389116860827593711593732385562328255759509355298662361508611531972386995239908513273236239858854586845849686865360780290350287139092143587037396801704351692736985955152935601987758859759421886670907735120137698039900161327397951758852875291442188850946273771733011504922325622240838288097946309825051094566685479503461938502373520983684296658971700922069426788236476575236189040102848418547634290214175167767431475003216056701094275899211419979340802711684989710130215926526387138538819531199810841475218142606691152928236362534181622201347
E2=125932919717342481428108392434488550259190856475011752106073050593074410065655587870702051419898088541590032209854048032649625269856337901048406066968337289491951404384300466543616578679539808215698754491076340386697518948419895268049696498272031094236309803803729823608854215226233796069683774155739820425393
def continuedFra(x, y): #不断生成连分数的项,如127/52 = 2 + 1/2+ 1/3+ 1/1+ 1/5,生成[2,2,3,1,5]
cF = []
while y:
cF += [x // y]
x, y = y, x % y #这里是连分数生成项的算法
return cF
def Simplify(ctnf): #对前面生成的连分数项化简
numerator = 1
denominator = 0
for x in ctnf[::-1]: #注意这里是倒叙遍历,从后面把连分数项合成总和。
numerator, denominator = x * numerator + denominator, numerator
return (numerator, denominator) #把连分数分成和算出来的分母以元组的形式导出来,如Simplify(continuedFra(127,52))生成(127, 52)
def getit(c):
cf=[]
for i in range(1,len(c)):
cf.append(Simplify(c[:i])) #各个阶段的连分数的分子和分母
return cf #得到一串连分数,如:[(2, 1), (5, 2), (17, 7), (22, 9)]
def wienerAttack(e, n): #低解密指数攻击,自己修改要碰撞的分子或分母
cf=continuedFra(e,n)
for (Q1,Q2) in getit(cf): #遍历得到的连分数,令分子分母分别是Q1,Q2,因为前面我们说了N1/N2=(p1/p2)**2 (q1/q2)
if Q1 == 0:
continue
if N1%Q1==0 and Q1!=1: #满足这个条件就找到Q1了,其实这里的Q2也是对的。
return (Q1,Q2)
print('没找到能覆盖的分子/分母')
Q1,Q2=wienerAttack(N1,N2) #找出一个Q1,其实这里也可以找出Q2的,但处于p2=sympy.nextprime(p1)的限制,只能用p1求出p2,不能用p2求出p1
from Crypto.Util.number import *
P1=gmpy2.iroot(N1//Q1,2)[0]
P2=gmpy2.next_prime(P1) #p1对了,p2也会对
phi1=P1*(P1-1)*(Q1-1) #求出phi1,也就是ψ(n1)
phi2=P2*(P2-1)*(Q2-1) #求出phi2,也就是ψ(n2)
d1=gmpy2.invert(E1,phi1) #逆模求d
d2=gmpy2.invert(E2,phi2) #逆模求d
m1=long_to_bytes(gmpy2.powmod(c1,d1,N1)) #普通解密算法,但是要用将long型数转为字节型数据
m2=long_to_bytes(gmpy2.powmod(c2,d2,N2)) #普通解密算法,但是要用将long型数转为字节型数据
print((m1+m2)) #拼接flag字符。
结果:
.
.
.
解毕!敬礼!