连分数与其在rsa中的运用
首先先要了解一下连分数的表现形式
也就是把一个数不停细分下去例如x=13/8
可以继续划分为如图所表示的形式
这就是简单连分数,为了方便计算,通常我们会写成[a0,a1,a2,a3],上图我举的例子可以写成[1,1,1,1,2]
我也简单写了个模拟代码,大部分情况应该是适用的(原创代码,可能写的比较差)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def lianfenshu(a,b): list=[] t=a//b list.append(int(t)) h=1/(a/b-t) if h % 1 == 0: list.append(int(h)) while h%1!=0: t=int(h-h%1) list.append(int(t)) h=round(1/(h%1),4) if h%1==0 : list.append(int(h)) return list
简单连分数的概念也要知道,分为有限连分数和无线连分数,也代表着有理数和无理数吧
当然连分数[a0,a1,a2,a3,.......,an]也可以写为(a0*[a1,a2,a3,....,an]+1)/[a1,a2,a3,....,an]最后可以化简为a/b,
连分数的倒数:例如假如这个数为[a0,a1,a2,a3,.......,an],他的倒数就是[0,a0,a1,a2,a3,.......,an]
然后再看渐近分数
渐近分数的定义是称[a0,a1,a2,a3,.......,am]是渐近数[a0,a1,a2,a3,.......,an]第m个渐近分数(0<=m<=n)
然后还存在一个特性
pnqn-1-pn-1 qn=(-1)^(n-1)
可以通过上述可以替换出来
然后又有一个概念完全商,是逆过来的举个例子
[2,3,1,4]
[4]第三个完全商
[1,4]第二个完全商
[3,1,4]第一个完全商
[2,3,1,4]第零个完全商
其定义为称[at,.....,an]为[a0,a1,a2,a3,.......,an]的第t个完全商(0<=t<=n)
渐近分数的单调性
第t个渐近分数xt=pt/qt
性质1:所有偶数编号的渐近分数是严格递增的,奇数编号是相反的
性质2:任何奇数编号的渐近分数大于偶数编号的渐近分数
大概基础就这么多
然后看看连分数在rsa中的应用
作用于RSA维纳攻击
Wiener 表示如果满足:
d < (1 /3) n ^(1/ 4) d以危害 RSA 的安全。此时需要满足:
q<p<2q
回想一下 RSA:
N = pq
φ(n)=(p−1)(q−1)=pq−(p+q)+1=N−(p+q)+1
p, q 非常大, pq≫p+q,φ(n)≈N
ed≡1 mod φ(n),∴ed−1=kφ(n),这个式子两边同除 dφ(n) 可得
可得到e/n-k/d=1/dφ(n)
同样 dφ(n) 是一个很大的数,所以 e /N 略大于 k/ d
因为 e 和 N 是我们是知道的,公钥中给我们的,所以我们计算出 e/ N
后,比它略小的 k/ d怎么出来呢,计算 e /N
的连分数展开,依次算出这个分数每一个渐进分数,由于 e/ N 略大于 k/ d
,wiener 证明了,该攻击能精确的覆盖 k /d .
我们也可以看一下羊城杯 Crypto RRRRRRRSA这道题目
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 36 37 38 39 40 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()
首先发现
1 2 3 4 5 6 7 N1 = P1 * P1 * Q1 N2 = P2 * P2 * Q2 P1 = getPrime(1038) P2 = sympy.nextprime(P1) assert(P2 - P1 < 1000) Q1 = getPrime(512) Q2 = sympy.nextprime(Q1)
p1与 p 2 是相邻的素数,且两者差值小于1000
q1 与 q2 也是相邻的素数
换而言之, p 1 / p 2 ≈ 1
很容易想到维纳攻击
N1/N2=(P1/P2)**2(Q1/Q2)
N1/N2<Q1/Q2
任何有理数都可以写为q/p=[a0;a1,a2,...,an]
计算连分数我们可以使用欧几里得算法
连分数的收敛性
我们定义 c i 为连分数每一次分式展开的收敛,也就是上文的渐近连分数
img
根据这个定理,我们可以通过计算一个数(e/N)的连分数来找到与这个数近似的两个数的比值(k/d),这就是Wiener’s
attack的攻击方法。
img
此题考查这个论文
因为p1和p2过于接近,相比而言取q1/q2更合适
而选择 N 1/ N 2 ≈ Q 1 /Q 2 可以进行维纳攻击的前提条件是:
∣N2/N1−Q2/Q1∣<1/2∗(Q2)**2
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import gmpy2 N1, N2 = ( 28539239760609998188190348006307254423529984523926011298354682217538318221201323233400895681944936240127760319591714405028970789289069319799896668405374649890651532747231344681669678805558659075027847592497103008180667401328194026698749233856463858487096300279373254961880228864461848969277992345170787143090948199697266462389362914238819698112687026213976658417210663710975098053456243238943838516217798558036642447022751111845270483110159293737669560262193958772015914816987850140197853369767380678566336063010710812528919482513791382363881826680659095433918156094107350594201368395060384315773118343026193511099009931177740948978534045707679969732723167077325752299598557383348276880809860413060977442176372544771414690543709674125255716088409107695219200275948083389811120343, 28539239760609998188190348006307254423529984523926011298354682217538318221201323233400895681944936240127760319591714405028970789289069319799896668405377378062335966544017315329665365256524558696688888741558627244653037221467229159144343040629127843297021870442297090214085287305843208151069804261723045390513830069085816369993597001968164660390663983571269250460727348123970070188870297493687465127551913118724304293942732950040939150438510454614095673775735977217966562306548665616925803946575019193754095625773160561193234183507671760318885800972555685452762447998320093072265818485061557955267533908006243431570323359331106169234651310488306412479972526063665874847216797986275140105142694301359006633212114432527436809944525332728559649659936613255629968696993687582732203577) c1, c2 = ( 1432582014696304280729383293185554513436929310033823269133977593539672022744978340029313742941392672688363895524640351487464959860278576282854691764963077939567531721178912737755379413034164798305484717033762726637503348022397339246940965129765378824268519081645805470821347112369377592502109678876165836108257610182421452838639591697308432137885174692492190957254254995673010537260331832973067691597718100899475899017281060822990010249568584370589711942182283002241043038119931455622397903939297537776804134742442672001638774739818585840571993745726530468147630711418520486306194651956014117679528472239294239116641656014852458465706006398065574504399016286485027421474307531748266141136418468990741046806688381193860509615850629805172129297224123462801586090084637746562423808, 15573518512630583133605706431375892476846434992703760807266881477212729790675502562405142453118932977842339803883111403869334521098950030048699583130857582338419182841819307757252097704148569218757559761264396801310961344678392000382263595912787825617009851110457692404940207973548999796553024456145274114257889573707649959860997335143214788897776951837248853483762434899857463503651914305981628033038172123120703537802061315610043298426738218704990852775023413248589434394708618489802771255075164976384643287270994751622452142844176084933641827641239534332334446368745588970480750957569438747829980771324981588625047320914720986351721280038816715323656526802000900688313558979941992015923305782197562859553039256619824373010017972420560224632828808074734952385591551175446599133) e1= 165789626975534012040420057284463500775834911397214992496515507176272849770841998477139944440126985014248815418211585858658342524799286016374109756516450870298232454995876047057825952563581619963387275065218691863272435560584657400761485940130783607258311246708485662913432455714363728035174035069036312370233 e2=165789626975534012040420057284463500775834911397214992496515507176272849770841998477139944440126985014248815418211585858658342524799286016374109756516450870298232454995876047057825952563581619963387275065218691863272435560584657400761485940130783607258311246708485662913432455714363728035174035069036312370859 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.iroot(N2//q2,2)[0] phi1=((p1-1)*p1*p1*p1)*(q1-1) phi2=((p2-1)*p2*p2*p2)*(q2-1) 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))