在打0CTF时看到了RSA的那题,但是不会做,于是先学习一波RSA吧,算做入门,自己也喜欢数学,正好积累下,RSA是非对称加密,相对于DES对称加密而言的,下面进去正题。
一、欧拉定理: 如果两个正整数a和n互质,则n的欧拉函数 φ(n) 可以让下面的等式成立:
这是个很重要的公式,先来理解下,首先n = pq(q和p互为质数),欧拉函数 φ(p) = p-1(表示与p互质的数的个数为p-1个,下同), φ(q) = q-1,所以 得到
推理1:φ(n) = φ(p)φ(q) = (p-1) (q-1) 上式可以转成
a^φ(n)%n = 1,也就是说a的φ(n)次幂对n求余为1,设φ(n)=k=(p-1)*(q-1), 也就是a^k%n=1,那么可以知道a^kt%n=1也成立~
二、密钥的计算获取过程 密钥的计算过程为:首先选择两个质数p和q,令n=p*q。
令k=ϕ(n)=(p−1)(q−1),上面讲过了,这里再给一个推理:
推理2:ab%n=a%n b%n(乘积的余数等于余数的乘积) 证明:假设a和b除以n的余数为c1,c2。a和b可以写成a=nt1+c1,b=nt2+c2。那么,ab=n2t1t2+nt1c2+nt2c1+c1c2=n(nt1t2+t1c2+t2c1)+c1c2=nt3+c1c2。因此ab除以n的余数为c1c2。即ab%n=a%n b%n
选择任意整数d,保证其与k互质,
取整数e,使得de%k=1。也就是说de=kt+1,t为某一整数,这样私钥d和公钥e就生成了,这里d就是e相对于k的逆元,(这里知道了e就可以求d,或者知道了d就可以求e),那么逆元怎么求呢?有很多方法,这里推荐个最好用的方法:
接着看一下一个重要的推理:
z为小于n的任意一个数,z^(de)%n=z^(kt+1)%n=(z^(kt)z)%n=((z^kt)%n*z%n)%n= z%n=z (z%n<n,所以再求一次余还是z) ,解释下,因为(z^k)%n = 1,所以(z^kt)%n=1,得到
推理3:z^(de)%n=z%n=z 三、加密与解密过程 A发送信息m给B,利用公钥e加密成密文c,B利用私钥d解密出明文信息m
1、加密 设明文为m,密文为c,首先把用户A发送的信息字符m转成整数,找到一个与m互为质数的n,
随机地选择一个正整数e,1<e<ф(n)且gcd(e,ф(n))=1,将e公开,根据ed=1 mod ф(n),求出d,并对d保密。
即可生成公钥对(n,e)和私钥对(n,d),加密公式:m^e%n = c,加密结束。
2、解密 解密公式:c^d%n=m,解密结束。
3、证明解密过程的正确性: 推理4:(m^e%n)^d=m^ed%n=m%n 证明:设[m^e/n]表示求余,[m^e/n]^d = [m^ed/n^d],可以看成[[m^ed/n]/n]…/n],这里有d个n,因为算出第一个余数x,一定有x<n,后面恒有[x/n]=x,所以可以知道,(m^e%n)^d=m^ed%n(余数的幂等于被除数的幂的余数)
因为m^e%n = c,
所以c^d%n = (m^e%n)^d%n = (m^ed%n)%n =m%n=m(m<n)
得证合理性! 四、做一波题目巩固下 1、模数分解型:
给了c、n和e,要求m,最简单的题型,把n写入我们的pcat.txt,这里直接先雅虎分解n:
1 ./yafu-x64.exe "factor(@)" -batchfile pcat.txt
得到了p和q就好办了,直接求逆元得到d,最后解密即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from gmpy2 import *import libnumfrom Crypto.Util.number import *n=3161262255255421133292506694323988711204792818702640666084331634444148712428915950639954540974469931426618702044672318134908678730641981414037034058320359158246813987154679178159391832232990193738454116371045928434239936027006539348488316754611586659587677659791620481200732564068367148541242426533823626586574915275209508300120574819113851895932912208783915652764568319771482309338434364094681579135086703127977870534715039005822312878739611630155714313119545610939253355808742646891815442758660278514976431521933763272615653261044607041876212998883732724662410197038419721773290601109065965674129599626151139566369 e=65537 c=631583911592660652215412683088688785438938386403323323131247534561958531288570612134139288090533619548876156447498627938626419617968918299212863936839701943643735437264304062828205809984533592547599060829451668240569384130130080928292082888526567902695707215660020201392640388518379063244487204881439591813398495285025704285781072987024698133147354238702861803146548057736756003294248791827782280722670457157385205787259979804892966529536902959813675537028879407802365439024711942091123058305460856676910458268097798532901040050506906141547909766093323197363034959926900440420805768716029052885452560625308314284406 p = 56225103425920179745019828423382255030086226600783237398582720244250840205090747144995470046432814267877822949968612053620215667790366338413979256357713975498764498045710766375614107934719809398451422359883451257033337168560937824719275885709824193760523306327217910106187213556299122895037021898556005848927 q = 56225103425920179745019828423382255030086226600783237398582720244250840205090747144995470046432814267877822949968612053620215667790366338413979256357713975498764498045710766375614107934719809398451422359883451257033337168560937824719275885709824193760523306327217910106187213556299122895037021898556005848447 d = invert(e,(p-1 )*(q-1 )) m = pow(c,d,n) print long_to_bytes(m)
*公约数模数分解,c1,e1,n1和c2,e2,n2,这里先测试下gcd(n1,n2)!=1,那么我们就可以尝试分解n1和n2,就可以得到想要的q和p值。
2、共模攻击型:
由原理部分我们可以知道,e的范围是1<e<ϕ(n),也就是说e是可以随机选取的,这时候,就可以使用不同的e对相同的m加密,得到2个不同的密文,而共模体现在使用的模数n不变,画个图:
演示共模攻击,重点是找到r和s,因为n比较难分解,如果满足下面的条件:
1 2 1 = gcd(e1,e2)r*e1 + s*e2 = 1
这里计算r和s要用到扩展欧几里得算法:
1 2 3 a = gcdext(e1,e2) s = a[1 ] r = a[2 ]
这里可以知道m>n:
通过变换可以知道:
讲完了原理,下面开始做题:
这里给出了2组的信息,n,e1,e2,c1,c2,这题直接yafu是跑不出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 gmpy2 import *import libnumfrom Crypto.Util.number import *n = 21660190931013270559487983141966347279666044468572000325628282578595119101840917794617733535995976710097702806131277006786522442555607842485975616689297559583352413160087163656851019769465637856967511819803473940154712516380580146620018921406354668604523723340895843009899397618067679200188650754096242296166060735958270930743173912010852467114047301529983496669250671342730804149428700280401481421735184899965468191802844285699985370238528163505674350380528600143880619512293622576854525700785474101747293316814980311297382429844950643977825771268757304088259531258222093667847468898823367251824316888563269155865061 e1 = 65537 c1 = 11623242520063564721509699039034210329314238234068836130756457335142671659158578379060500554276831657322012285562047706736377103534543565179660863796496071187533860896148153856845638989384429658963134915230898572173720454271369543435708994457280819363318783413033774014447450648051500214508699056865320506104733203716242071136228269326451412159760818676814129428252523248822316633339393821052614033884661649376604245744651142959498917235138077366818109892738298251161767344501687113868331134288984466294415889635863660753717476594011236542159800099371872396181448655448842148998667568104710807411358117939831241620315 e2 = 70001 c2 = 8180690717251057689732022736872836938270075717486355807317876695012318283159440935866297644561407238807004565510263413544530421072353735781284166685919420305808123063907272925594909852212249704923889776430284878600408776341129645414000647100303326242514023325498519509077311907161849407990649396330146146728447312754091670139159346316264091798623764434932753276554781692238428057951593104821823029665203821775755835076337570281155689527215367647821372680421305939449511621244288104229290161484649056505784641486376741409443450331991557221540050574024894427139331416236263783977068315294198184169154352536388685040531 a = gcdext(e1,e2) if a[1 ]<0 : s = -a[1 ] r = a[2 ] c1 = invert(c1, n) if a[2 ]<0 : s = a[1 ] r = -a[2 ] c2 = invert(c2, n) m = (pow(c1,s,n)*pow(c2,r,n))%n print long_to_bytes(m)
3、小指数明文爆破攻击
这里如果使用的e太小的话,比如e=3,而且m也比较小的情况下,就有这种可能:
那么我们可以通过爆破的方式直接开3次根,解得m值,来一道题看看:
小指数的e,所以我们直接尝试着使用小指数明文爆破的方式去做这题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from gmpy2 import *import libnumfrom Crypto.Util.number import *n = 47966708183289639962501363163761864399454241691014467172805658518368423135168025285144721028476297179341434450931955275325060173656301959484440112740411109153032840150659 e = 3 c = 10968126341413081941567552025256642365567988931403833266852196599058668508079150528128483441934584299102782386592369069626088211004467782012298322278772376088171342152839 i = 0 while 1 : m = iroot(c+i*n,3 ) if m[1 ]==1 : print long_to_bytes(m[0 ]) break i += 1
4、选择密文攻击 这里相当于给了一个orancle,攻击者拥有了加密和解密的服务,但是无法直接获得想要的n和e,我们只知道c,这时如果我们选择了一个r,满足r<n,可以知道:
1 2 3 4 5 6 7 8 9 10 11 若x = r^e mod n 则r = x^d mod n 得到y = x*c mod n 选择t = r^(-1 ) mod n 选择u = y^d mod n 那么我们有: t*u mod n = ((r^(-1 ) mod n)*(y^d mod n)) mod n =(r^(-1 )*(x^d)*(c^d)) mod n =(r^(-1 )*r*c^d) mod n =c^d mod n =m
由此通过选择密文攻击的方式,我们可以解密出明文。
5、广播攻击 广播攻击是低指数攻击的一种,通常情况下,是利用相同的e对不同的n进行加密,这样我们就可以得到很多组同余的方程式:
1 2 3 4 5 6 7 c1≡m^e mod n1 c2≡m^e mod n2 c3≡m^e mod n3 对上述等式运用中国剩余定理,可以得到: cx≡m^e mod n1n2n3 这里的e一般是小指数,比如3 或者9 可以知道m^e = cx mod n1n2n3
已经知道d、e和n的情况下,分解p和q:
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 import random def gcd (a, b) : if a < b: a, b = b, a while b != 0 : temp = a % b a = b b = temp return a def getpq(n,e,d): p = 1 q = 1 while p==1 and q==1 : k = d * e - 1 g = random .randint ( 0 , n ) while p==1 and q==1 and k % 2 == 0 : k /= 2 y = pow (g,k,n) if y!=1 and gcd(y-1 ,n)>1 : p = gcd(y-1 ,n) q = n/p return p,q n=0x96ed2727e4446e26c84552a9a19640c7d720c9b6e661cfcfec03463e92a9d0b228ddc9847c0daa137a19db67294626c535fe71c388f6ea3eb8cb5dbf09a84374eb021c9297a29394cf77da157c1b8be77b09a4fcbe54bf3dc93d33539e842766ad8e38369093ddc034ac32583a48e299a4d8b31b606b1729298ee136664b8b77 e=0x10001 d=0x7d12e57b1aa157038ebe5c45b56256270671e6984b0dcdf10a2ea07ce480143240c9a3e1c60870e499306a717073f157476aa88e99a7bdf1e2a4adf8ce21025cc6c05035c4a1d7e3b6f061464872e65118384999f0154f3c1761fa68d4685126b7fc98f4c2cdc41c98aa4e099a868a89099dd2170664647efca2c8d8e06a2e49 # phi = 0x96ed2727e4446e26c84552a9a19640c7d720c9b6e661cfcfec03463e92a9d0b228ddc9847c0daa137a19db67294626c535fe71c388f6ea3eb8cb5dbf09a84373552f3ae326ed80690d123ce71b3059d75095dcf839cdd0dc79ff6077ae979b1fe2267a0f698dd27cbc1adc82cba32a8289faf953279fdb3651f0a66d0cdbe478 p,q=getpq(n,e,d) print ("p=" ,p)print ("q=" ,q)print (p*q==n)print hex((p-1 )*(q-1 ))