buuctf rsa小总结(第一页)
前言:
记录一下自己的学习过程
感谢博主:
有借鉴CTFer菜菜的文章,他的数学原理推导过程很有帮助
学习前置:
需要库(自行下载):gmpy2,rsa还有一些进制转文本的库
基础知识:c密文,m明文,e公钥(随机),q,p是随机的两个素数,n=p*q
私钥d与公钥e的关系:(de)%(p-1)(q-1)=1
m=c^d%n,n=qp,(de)%(p-1)*(q-1)=1(用以求逆元)
备注:进阶知识有补充,最后需要转文字
1.RSA
在一次RSA密钥对生成中,假设p=473398607161,q=4511491,e=17 求解出d作为flga提交,
求逆元:gmpy2.invert(e,(p-1)*(q-1)) 会返回d的值
上代码
import gmpy2 p = 473398607161 q = 4511491 e = 17 d = int(gmpy2.invert(e,(p-1)*(q-1))) print(d)
2.rsasa
题目
p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483 q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407 e = 65537 c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034
根据公式:m=c^d%n可得思路:先求d,再求m
上代码:
import gmpy2 p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483 q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407 e = 65537 c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034 n = p*q d = int(gmpy2.invert(e,(p-1)*(q-1)))# 数学意义:(d*e)%(p-1)*(q-1)=1 ==> d=(k*(p-1)*(q-1)+1)/e,求逆元原理 m = pow(c,d,n) #pow函数用法简单:c^d%n的意思(求幂取模) print(m)
3.RSA1
题目:
p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229 q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469 dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929 dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041 c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852
这里首先要知道dpdq是什么,下面式子有说明:
这里首先要知道什么是同余(≡)比如a≡b(modn)就表示:两个整数a、b,如果他们同时除以一个自然数n,所得的余数相同,则称a、b对于模m同余,记作a≡b(modn
公式:dp≡d mod (p-1) ,dq≡d mod (q-1) ,m≡c^dmodn
m≡c^dmodn这个公式解释一下:因为m=c^d%n,所以m<n,这样m%n=m,c^d%n=m,同余
m≡c^dmodn就是m=k*n+c^d(k为整数,m小于c^d,这里肯定是负数了)(方程好理解)
就是m=c^d+kpq
对上面的式子同时取余(可以理解为对m=c^d%n两次取余)
得到mp=c^d%p;mq=c^d%q
这里对mp式子进行转换(方便代入):c^d=k*p+mp,再将mq代入
mq≡(k*p+mp)%q,再将两边同时减去mp(数学基本思维:未知数放在等式同一边)
(mq-mp)≡k*p%q
根据rsa基本原理:p,q为素数所以gcd(p,q)=1,敏感的人就发现了,可以对p求逆元:
(mq-mp)*p(-1)≡k%q再根据同余的原理得到:
k≡(mq-mp)p(-1)%q再与上面推导的式子c^d=kp+mp联立
得出:c^d=((mq-mp)p^(-1)%q)p+mp代入公式m≡c^d%n(由从c^d≡m%n而来)
得到m≡(((mq-mp)p^(-1)%q)p+m1)%n(到这里不知道怎么推导的了求佬解决)
推导为m = (((mq-mp)I)%q)p+mp(I为p,q的逆元)
最后仅仅几行代码
import gmpy2 I = gmpy2.invert(p,q) mp = pow(c,dp,p) mq = pow(c,dq,q) m = (((mq-mp)*I)%q)*p+mp #求明文公式 print(print(hex(m)[2:])) # 转为十六进制
4.RSA2
给了e,n,dp,c
这里给公式:dp≡d mod (p-1);d*e≡1%(p-1)(q-1)
还是数学原理:
公式:m=c^d%n也就是求d
而d的求法也只有一个:逆元:d=gmpy2.invert(e,(p-1),(q-1))
现在知道求了p就可以求出q也就能求d
缩小范围遍历求出p,现在推导p的范围
dpe=ed%(p-1)(由dp≡d mod (p-1)推出)
ed=k(p-1)+dp*e(k为整数)
ed=a(p-1)(q-1)+1(a为整数)(由de≡1%(p-1)(q-1)推出)
联立:
a(p-1)(q-1)+1=k(p-1)+dpe
整理得:(p-1)(a(q-1)-k)+1=dp*e
令x=(a(p-1)-k)
所以dpe=(p-1)x+1
又因为dp<p-1
可以推出x的范围1<x<e
由x=(a(q-1)-k)推出p=(dp*e-1)/x+1
代码实现:
import gmpy2 for i in range(1, e): # 在范围(1,e)之间进行遍历 if (dp * e - 1) % i == 0: if n % (((dp * e - 1) // i) + 1) == 0: # 存在p,使得n能被p整除 p = ((dp * e - 1) // i) + 1 q = n // (((dp * e - 1) // i) + 1) phi = (q - 1) * (p - 1) # 欧拉定理 d = gmpy2.invert(e, phi) # 求模逆 m = pow(c, d, n)# 快速求幂取模运算 print(print(hex(m)[2:]))
5.RSA3
涉及数学知识,扩展欧几里得算法,费马小定理
由数学原理,欧几里得算法可得:e1 * s1 + e2 * s2 = 1
这里s1,s2与e1,e2关系为逆元即
s1=gmpy2.invert(e1,e2) s2=gmpy2.invert(e2,e1)
m=m%n(明文肯定比n小,相当于m=m)
m = m^(e1s1+e2s2) % n
m = (m^(e1*s1) % n * m^(e2*s1) % n) % n
m = (c1^s1 % n * c2^s2 % n) % n
涉及到gmpy2的函数;gcdext(即扩展欧几里得算法)
上代码:
import gmpy2 r,s1,s2=gmpy2.gcdext(e1,e2) m=(pow(c1,s1,n)*pow(c2,s2,n))%n print(print(hex(m)[2:]))
6.RSA
需要网站公钥解析(没网的时候用kali的rsa工具,以后补充)
得到文件
无法打开,添加后缀.txt
打开后得到公钥,公钥解析后拿到e,n
n比较小,直接用网站分解整数n
这时候可以直接用脚本:
d = gmpy2.invert(e, phi)
也可以用工具,RSA Tool2 by Te!
最后用脚本
import rsa#要导入rsa库 key = rsa.PrivateKey(n,e,d,q,p) with open("解压flagenc的地址","rb") as f: #rb指以二进制读模式,读取密文 f = f.read() print(rsa.decrypt(f,key))
7.RSAROLL
两个文件
看见括号一般是(n,e)
n很小,用分解网站分解(这里一样可以用kali的工具,以后补充)
得到p,q
再求d = gmpy2.invert(e, phi)
接下来密文盲猜是下面的一长串数字,但是需要一行一行来,很麻烦,直接利用文件读取及strip函数去除\n
,但是注意,这里的每一行数字对应一明文的一个字符,不能合在一起当一个大数字用
上代码:
import gmpy2 n=920139713 e=19 p=18443 q=49891 d=gmpy2.invert(e,(p-1)*(q-1)) flag='' with open("D:\\火狐\\704796792.txt",'r')as f:#这里要修改为自己的地址 for i in f.readlines(): i=i.strip('\n') flag+=(chr(pow(int(i),d,n))) print(flag)
buuctf第一页的RSA解密完毕