大数分解
大数分解网页
http://www.factordb.com/index.php
yafu
- 运行yafu-x64.exe,在窗口中输入factor(n),n即为待分解的大数。
- 在factor.log中找到分解结果。
利用z3解方程
可以加快解题速度,此处以一个简单的例子展示如何用z3解方程(首先需要安装z3和z3-solver)。
$\begin{cases}\ x1+x2=3\\ x1-x2=-1\end{cases}$
1 | from z3 import * |
如例题[GWCTF 2019]BabyRSA
已知p,q,e求d
方法一:
1 | p=473398607161 |
方法二(常用,gmpy2库):
1 | # 已知e,p,q |
方法三(sage):
1 | phin = (p-1) * (q-1) |
已知n,dp,e求d
相关例题如:Buuoj RSA2
- 要先根据e,dp求p。首先
$dp\ =\ d\ mod\ (p-1)$
$ed\ \equiv\ 1\ mod\ \phi(n)$
而$\phi(n)\ =\ (p-1)(q-1)$,所以有
$ed\ =\ 1+x(p-1)(q-1)$
$edp\ mod\ (p-1)\ \equiv\ ed\ mod\ (p-1)$
进而:
$edp\ =\ ed+y(p-1)$
$edp\ =\ 1+x(p-1)(q-1)+y(p-1)$
因此可整理为:
$edp\ =\ 1+y(p-1)$
又有$dp\ \lt\ p-1$,所以$e\ \gt\ y$。从1到e遍历即可求得正确的y,进而得到正确的p值。得到p后可有已知的n求得q,进而回到已知$e$和$\phi(n)$求解$d$的问题。得到代码如下,注意求p时是整型除法,否则会在n%p时报溢出错误:
1 | for y in range(1,e): |
小指数明文爆破
相关例题,Buuoj Dangerous RSA
- 题目已知条件有n,e,c其中e是非常小的值,比如3。RSA的加密过程为$c=m^e\ mod\ n$。
如果m很小,n很大,也即可能是以下情况$^{[2]}$:
$m^e\ \lt\ n$
此时,$c=m^e$,开e次根即可得到m。
如果,$m^e \gt\ n$但是并未超过n太多,又由于对c我们可能有$m^e=c+kn$,所以可以得到以下的表达式:
$m=\sqrt[e]{c+kn}$
这样我们可以通过爆破k的大小来求解明文了。 - 基本代码如下:
1 | # 已知n,e,c |
iroot(c+k*n,e)
函数就是在计算$\sqrt[e]{c+kn}$,其返回结果第一个元素为计算结果,第二个元素是表示结果是否精确的布尔值
分数,求导
相关例题:[BJDCTF2020]easyrsa
分数
1 | # Fraction(8, 6) will produce a rational number equivalent to 4/3, Both arguments must be Rational. The numerator defaults to 0 and the denominator defaults to 1 so that Fraction(3) == 3 and Fraction() == 0. |
求导
http://liao.cpython.org/scipy17/
如对$arctan(p)$求导(p为变量)
1 | from sympy import Derivative |
已知e,n且e很大时求d: RSA Wiener Attack 维纳攻击
参考:https://github.com/pablocelayes/rsa-wiener-attack
求d的方法:
1 | from RSAwienerHacker import hack_RSA |
相关例题Buuoj rsa2
openssl
- 首先需要下载安装openssl,下载地址
- 将其bin目录添加到系统变量path中
- 基本用法参考https://www.cnblogs.com/wyzhou/p/9738964.html
- 如利用openssl从文件获取公钥信息(不输出文件):
openssl rsa -pubin -in key.pub -text -noout
利用Crypto.PublicKey的RSA模块从文件中获取公钥信息n,e
这个文件可能是二进制文件,key.pub,pub.key等形式
1 | from Crypto.PublicKey import RSA |
相关例题:Buuoj RSA, 攻防世界 cr4-poor-rsa
已知e,d的值和p,q的位数,求p,q的值
先验知识:
$n=pq$
$\phi(n)=(p-1)(q-1)$
$ed\equiv1\ mod\ \phi(n)$
所以,大概有
如果我们已知p,q的位数,那就大概知道n的位数,$\phi(n)$的位数与n差别不大。同时$ed-1$的位数可以通过其值得到范围,因此我们可以通过$\frac{(ed-1)的位数}{\phi(n)的位数}$大致确定x的位数,随即可以在此范围遍历得到素数p,q的值。
相关例题:[NCTF2019]babyRSA
已知多组n,c的值
中国剩余定理
遍历n,看有无非1的公因数,其值即为p或q的值
RsaCtfTool
- 安装过程中注意mpfr和mpc都应从官网确认最新版本后再下载对应版本并安装。
- 使用方法:
已知n的值,且p,q大小相近,如何求出p和q
- 先对n求平方根,得到一个和p值相近的值,再求其临近的素数,即为p值
- q = n // p
1 | near_p = isqrt(n) |
已知dp,dq,p,q,c求明文
1 | import gmpy2 |
例题
Buuoj RSA
解法一
给了flag.enc和pub.key文件,其中pub.key文件存放了公钥信息,这是个ASCII文本文件可直接用记事本打开。得到以下信息:
1
2
3
4-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMAzLFxkrkcYL2wch21CM2kQVFpY9+7+
/AvKr1rzQczdAgMBAAE=
-----END PUBLIC KEY-----借助RSA密钥解析网站解析密钥指数和模数信息,得以下结果:
1 | key长度:256 |
用Python得到n的十进制形式
1
2n = '0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD'
n = int(n,16)得到n=86934482296048119190666062003494800588905656017203025617216654058378322103517,放到大数分解网站分解。得到:
1 | p=285960468890451637935629440372639283459 |
- 利用gmpy2库求解d,由以上已得数据有以下代码
d = gmpy2.invert(e,(p-1)*(q-1))
,得到:
1 | d=81176168860169991027846870170527607562179635470395365333547868786951080991441 |
注意这个invert函数的用法:invert(x, m) Return y such that x*y == 1 (mod m).
- 最后从flag.enc文件中获取flag
1 | import rsa |
flag{decrypt_256}
或者参考
1 | from Crypto.PublicKey import RSA |
注意这个rsa.PrivateKey所有的参数都要是int
解法二
主要是获取n,e的方法不同:
1 | from Crypto.PublicKey import RSA |
直接输出86934482296048119190666062003494800588905656017203025617216654058378322103517 65537
BJDCTF 2nd rsa0
- 给了node3.buuoj.cn:29594,nc连接,得到
1 | e = 13979291 |
- Python代码如下:
1 | import gmpy2 |
flag{2824f2c0-b958-4d96-9ce7-1b3d40e9333d}
BJDCTF 2nd rsa1
- nc node3.buuoj.cn 28900得到:
1 | e = 10281503 |
- 根据pq的信息解方程即可,$2(p^2 + q^2) - (p-q)^2 = (p+q)^2$,emmm想用Python的cmath开根号或pow时会报溢出,所以整个解题过程在sage中实现。
- sage代码如下:
1 | import binascii |
flag{795faee7-4d4b-432c-9796-4758027c8a58}
RSAROLL
- data.txt中的数据如下:
1 | {920139713,19} |
- 把920139713拿到大数分解网站分解,发现可以分解成18443和49891。所以{920139713,19}应该是{n,e},剩下的行是密文。需要做的是循环求解每行的明文。
- 逻辑比较简单。先由分解得到的p和q,以及已知的e求得d,然后读取data.txt中的内容,循环求解明文。代码如下:
1 | import gmpy2 |
flag{13212je2ue28fy71w8u87y31r78eu1e2}
[HDCTF2019]basic rsa
- 题目attachment.py,具体代码如下:
1 | import gmpy2 |
- 所以基本逻辑很简单,先通过p,q,e求d,上文已经有求解方法和案例。然后利用c,d,n求
int(b2a_hex(flag),16)
再反求flag。解题代码如下:
1 | import gmpy2 |
注意这里m从10进制转到16进制后,前面会有0x的前缀,所以取下标2及以后部分。flag{B4by_Rs4}
[GUET-CTF2019]BabyRSA
- 题目给了一个BabyRsa文件,用winhex打开发现这是一个文本文件,直接用记事本打开即可。有以下信息:
1 | p + q : 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e80cf30141282c97be4400e33307573af6b25e2ea |
- 所以令x=p+q,y=(p+1)(q+1),就有
n=p*q=y-x-1
,这里给的e其实用不到。直接m=pow(enc_flag,d,n)就得到明文数据了,解题代码如下:
1 | from Crypto.Util.number import long_to_bytes |
flag{cc7490e-78ab-11e9-b422-8ba97e5da1fd}
Buuoj RSA2
- 题目信息:
1 | e = 65537 |
- 这是由dp求解p的问题。求解方法已在上文中有具体推导过程,解题代码如下:
1 | import gmpy2 |
flag{wow_leaking_dp_breaks_rsa?_98924743502}
Buuoj Dangerous RSA
- 题目提供的信息:
1 | n: 0x52d483c27cd806550fbe0e37a61af2e7cf5e0efb723dfc81174c918a27627779b21fa3c851e9e94188eaee3d5cd6f752406a43fbecb53e80836ff1e185d3ccd7782ea846c2e91a7b0808986666e0bdadbfb7bdd65670a589a4d2478e9adcafe97c6ee23614bcb2ecc23580f4d2e3cc1ecfec25c50da4bc754dde6c8bfd8d1fc16956c74d8e9196046a01dc9f3024e11461c294f29d7421140732fedacac97b8fe50999117d27943c953f18c4ff4f8c258d839764078d4b6ef6e8591e0ff5563b31a39e6374d0d41c8c46921c25e5904a817ef8e39e5c9b71225a83269693e0b7e3218fc5e5a1e8412ba16e588b3d6ac536dce39fcdfce81eec79979ea6872793L |
- 小指数明文爆破,前文已有原理。具体解题代码如下:
1 | import gmpy2 |
flag{25df8caf006ee5db94d48144c33b2c3b}
[GWCTF 2019]BabyRSA
- 解压缩文件,有encrypt.py和secret,其中secret是文本文件,内容如下:
1 | N=636585149594574746909030160182690866222909256464847291783000651837227921337237899651287943597773270944384034858925295744880727101606841413640006527614873110651410155893776548737823152943797884729130149758279127430044739254000426610922834573094957082589539445610828279428814524313491262061930512829074466232633130599104490893572093943832740301809630847541592548921200288222432789208650949937638303429456468889100192613859073752923812454212239908948930178355331390933536771065791817643978763045030833712326162883810638120029378337092938662174119747687899484603628344079493556601422498405360731958162719296160584042671057160241284852522913676264596201906163 |
encrypt.py如下:
1 | import hashlib |
- 由以上代码可以得到以下表达式:
$c1=F1+F2$
$c2=F1^{3}+F2^{3}$
$c1=m1^{d}\ mod\ N$
$c2=m2^{d}\ mod\ N$
d可由e,p,q求得。而p,q可通过yafu对N进行分解得到。所以拿到d后就可以求出c1和c2,然后解方程即可得到F1和F2,最后拼出flag。 - 解题代码如下:
1 | from Crypto.Util.number import long_to_bytes |
GWHT{f709e0e2cfe7e530ca8972959a1033b2}
[HDCTF2019]bbbbbbrsa
- 题目给了enc和encode.py,内容如下:
1 | p = 177077389675257695042507998165006460849 |
1 | from base64 import b64encode as b32encode |
- 所以思路是:先求c,这个c值不看代码,直接从enc文本中就可以看出是逆序的base64结果,所以先逆序过来再base64解密即可;其次,由e爆破得到d;最后因为有$c=int(b2a_hex(flag),16)^{e}\ mod\ n$,所以有$int(b2a_hex(flag),16)=c^{d}\ mod\ n$,可整理得到flag,代码如下:
1 | from gmpy2 import invert,gcd |
flag{rs4_1s_s1mpl3!#}
[BJDCTF2020]easyrsa
- 题目给了rsa_task.py,具体如下:
1 | from Crypto.Util.number import getPrime,bytes_to_long |
所以基本思路是由z求出p和q,再有p,q,e得到d,由c,d,n求m即可得到最终的flag
由z求p,q。首先$z=\frac{1}{arctan’(p)}\ -\ \frac{1}{arth’(q)}$,其中$arctan’(p)=\frac{1}{1+p^{2}}$,$arth’(q)=\frac{1}{1-q^{2}}$,因此有$z=p^{2}+q^{2}$。同时我们已知有$n=pq$,z和n的值已知,利用z3库联立解方程即可。代码如下:
1 | from z3 import * |
最终输出可得:
1 | p = 144564833334456076455156647979862690498796694770100520405218930055633597500009574663803955456004439398699669751249623406199542605271188909145969364476344963078599240058180033000440459281558347909876143313940657252737586803051935392596519226965519859474501391969755712097119163926672753588797180811711004203301 |
- 由p,q,e,c,n求m,并得到flag
1 | from Crypto.Util.number import * |
BJD{Advanced_mathematics_is_too_hard!!!}
Buuoj rsa2
- 题目是一个py文件,具体如下:
1 | N = 101991809777553253470276751399264740131157682329252673501792154507006158434432009141995367241962525705950046253400188884658262496534706438791515071885860897552736656899566915731297225817250639873643376310103992170646906557242832893914902053581087502512787303322747780420210884852166586717636559058152544979471 |
通过RSA Wiener Attack(维纳攻击)求得
d=8920758995414587152829426558580025657357328745839747693739591820283538307445当在Python3环境下求解flag时报错,提示要先编码。但是我尝试用utf-8和latin1编码再求md5后,得到的flag提交还是不对,有点坑,最后还是用的Python2,flag的那行代码不需要修改。最终结果为:
flag{47bf28da384590448e0b0d23909a25a4}
[BJDCTF2020]RSA
题目代码
1 | from Crypto.Util.number import getPrime,bytes_to_long |
分析
- 前半部分可以得到(c,n,x已知):
$c=m^{e}\ mod\ n$
对第二个print出来的值如果设为x,有:
$x=294^{e}\ mod\ n$ 后半部分有(c2,m2,n2已知):
$c2=m2^{e}\ mod\ n2$解题首要目标自然是e,由于1中第二个表达式数值较小,本打算用sage求离散对数得到e但是跑不出来,所以用Python进行0,100000的遍历找这个e的值
1 | n = 13508774104460209743306714034546704137247627344981133461801953479736017021401725818808462898375994767375627749494839671944543822403059978073813122441407612530658168942987820256786583006947001711749230193542370570950705530167921702835627122401475251039000775017381633900222474727396823708695063136246115652622259769634591309421761269548260984426148824641285010730983215377509255011298737827621611158032976420011662547854515610597955628898073569684158225678333474543920326532893446849808112837476684390030976472053905069855522297850688026960701186543428139843783907624317274796926248829543413464754127208843070331063037 |
得到e=52361
- 然后希望求得p,q的值以求d。但是想直接分解n的值太困难了。这里n和n2已知,且它们有最大公因数q,可直接求得,所以解题代码如下:
1 | from Crypto.Util.number import * |
BJD{p_is_common_divisor}
[NCTF2019]babyRSA
题目代码
1 | from Crypto.Util.number import * |
解题过程
- e,d已知,先确定$ed-1$的位数。
1 | import gmpy2 |
结果为:2063.2545176257354
- p的位数为1024,q在p的附近所以大致也是1024位。$\phi(n)$的位数约为2048,而$ed-1$大概是2063~2064位,所以$ed-1=1+x\phi(n)$中的x的位数为15~16。
- 在$2^{15}$~$2^{16}$减遍历x,找到可以被x整除的$ed-1$。那么有$\phi(n)=\frac{ed-1}{x}$
- 找到这个$\phi(n)$,因此p和q大小相近,可以取$\phi(n)$平方根,在其附近的素数取为p,得到p值就很容易找到q,只要它们都是素数,将它们相乘得到n,随即得到明文。
- 解题代码:
1 | from Crypto.Util.number import * |
NCTF{70u2_nn47h_14_v3ry_gOO0000000d}
Reference
[1] https://baike.baidu.com/item/%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95/2029414?fr=aladdin
[2] FlappyPig.CTF特训营
[3] https://www.freebuf.com/articles/database/170814.html?replytocom=249214