引文
之前简单讲了一下RSA算法的原理以及计算方法大家有没有学会呢?今天给大家带来的是RSA算法的进阶,进阶内容不止拘泥于RSA的一般算法,也是我在平常经常遇见的类型,多了一些限制性的条件。下面我先带大家回顾一下基础知识吧。
基础知识
先看一下RSA算法涉及的参数:
N:整数N,模数。
p 和 q :N的两个因子(素数)。
e 和 d:互为模反数的两个指数。
c 和 m:密文和明文,求解d时用到函数(d=gmpy2.invert(e,n的欧拉函数)。
加密算法
密文等于m的e次方对N求余。
解密算法
明文是对代表密文的数字 c 的 d 次方对 N 求余。
图解
进阶
维纳攻击
当e过大时适用,e/n的连分数展开会逐渐趋向于k/d。由于连分数逼近原理可以得到两者之间的比值所以(p+q)是可以得到相对接近的值。
例子
GITHUB有个专门的RSA解密脚本:
from RSAwienerHacker import hack_RSA
e=354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619
n=460657813884289609896372056585544172485318117026246263899744329237492701820627219556007788200590119136173895989001382151536006853823326382892363143604314518686388786002989248800814861248595075326277099645338694977097459168530898776007293695728101976069423971696524237755227187061418202849911479124793990722597
d=hack_RSA(e,n)
c=38230991316229399651823567590692301060044620412191737764632384680546256228451518238842965221394711848337832459443844446889468362154188214840736744657885858943810177675871991111466653158257191139605699916347308294995664530280816850482740530602254559123759121106338359220242637775919026933563326069449424391192
m=pow(c ,d ,n)
print hex(m)
dp泄露攻击
也是一个非常经典的题目,dp:d对(p-1)取模,当dp泄露时,n可分解成的素数种类大大降低,变得可以判断。
dp≡dmod(p−1)
我们可以根据DP值求出P然后就可以按基础公式来求解了:
for i in range(1,65538):if (dp*e-1)%i == 0:if n%(((dp*e-1)/i)+1)==0:p=((dp*e-1)/i)+1q=n/(((dp*e-1)/i)+1)phi = (p-1)*(q-1)d = gmpy2.invert(e,phi)%phi
低加密指数攻击
适用于e的值比较小的时候,原理如下:
m^e≡c(modn)
m^e=k×n+c(k为特定数值)
e非常小的时候k推断也会非常小,通过蛮力法得到m,然后就可以推导出e。
例子
import gmpy2
import binascii
enf = open('flag.enc', 'rb')
c = int(binascii.b2a_hex(enf.read()), 16)
print c
e = 3
n = 0x00b0bee5e3e9e5a7e8d00b493355c618fc8c7d7d03b82e409951c182f398dee3104580e7ba70d383ae5311475656e8a964d380cb157f48c951adfa65db0b122ca40e42fa709189b719a4f0d746e2f6069baf11cebd650f14b93c977352fd13b1eea6d6e1da775502abff89d3a8b3615fd0db49b88a976bc20568489284e181f6f11e270891c8ef80017bad238e363039a458470f1749101bc29949d3a4f4038d463938851579c7525a69984f15b5667f34209b70eb261136947fa123e549dfff00601883afd936fe411e006e4e93d1a00b0fea541bbfc8c5186cb6220503a94b2413110d640c77ea54ba3220fc8f4cc6ce77151e29b3e06578c478bd1bebe04589ef9a197f6f806db8b3ecd826cad24f5324ccdec6e8fead2c2150068602c8dcdc59402ccac9424b790048ccdd9327068095efa010b7f196c74ba8c37b128f9e1411751633f78b7b9e56f71f77a1b4daad3fc54b5e7ef935d9a72fb176759765522b4bbc02e314d5c06b64d5054b7b096c601236e6ccf45b5e611c805d335dbab0c35d226cc208d8ce4736ba39a0354426fae006c7fe52d5267dcfb9c3884f51fddfdf4a9794bcfe0e1557113749e6c8ef421dba263aff68739ce00ed80fd0022ef92d3488f76deb62bdef7bea6026f22a1d25aa2a92d124414a8021fe0c174b9803e6bb5fad75e186a946a17280770f1243f4387446ccceb2222a965cc30b3929L
k = 99999999
while True:k += 1if k % 1000000 == 0:print kres, isInt = gmpy2.iroot(c + k * n, e)if isInt:print k, resbreak
共模攻击
数次加密,e不同,n相同,m相同。就可以在不分解n和求d的前提下,解出明文m。
推导过程如下:
实现公式因为太长这里就不具体贴了,贴一个最终运算的代码:
m=(pow(c1,s1,n)*pow(c2,s2,n)) % n
P&Q相差过大或者过小
根据基础知识我们知道:
N=P*Q
如果他们相差过大或者过小,根据经验来说更容易从N中分解出来,这里介绍一个分解N的工具YAFU。
WINDOWS版本:
linux版本
使用方法:
factor(*)
dp,dq泄露
dp:d对(p-1)取模
dq:d对(q-1)取模
根据公式推导,我们可以通过dp,dq来算出M,进而求解。
设存在m1,m2:
c^d≡m1(modp)(m1为特定数值,使该式成立)
c^d≡m2(modq)(m2为特定数值,使该式成立)
进行一系列的推导,得到以下公式:
cd=((m2−m1)×p(−1)modq)×p+m1
m1≡c^(dp)modp
m2≡c^(dq)modq
合并运算可以求出m,脚本如下:
InvQ=gmpy2.invert(q,p)
mp=pow(c,dp,p)
mq=pow(c,dq,q)
m=(((mp-mq)*InvQ)%p)*q+mq
print '{:x}'.format(m).decode('hex')
低加密指数广播攻击
选取的加密指数较低,并且使用了相同的加密指数给一个接受者的群发送相同的信息,那么可以进行广播攻击得到明文。原理如下:
n1,n2…为不同加密所使用的模数,c1,c2…为不同加密的密文。
根据条件:
me≡c1(modn1) …等,可以推断出m^e,然后我们就可以发送相同的信息爆破得到e。
例子
('n=', '0x683fe30746a91545a45225e063e8dc64d26dbf98c75658a38a7c9dfd16dd38236c7aae7de5cbbf67056c9c57817fd3da79dc4955217f43caefde3b56a46acf5dL', 'e=', '0x7', 'c=', '0x673c72ace143441c07cba491074163c003f1a550eab56b1255e5ea9fa2bbd68fd6a9ccb48db9fd66d5dfc6a55c79cad3d9de53f700a1e3c2a29731dc56ba43cdL')
('n=', '0xa39292e6ad271bb6a2d1345940dfab8001a53d28bc7468f285d2873d784004c2653549c589dae91c6d8238977ff1c4bea4f17d424a0fc4d5587661cc7dde3a77L', 'e=', '0x7', 'c=', '0x6111357d180d966a495f38566ebe4ea51fa0d54159b22bbd443cde9387687d87c08638483b39221883453a5ad09f6a0e3726b214e8e333037d178a3d0f125343L')
('n=', '0x52c32366d84d34564a5fdc1650fc401c41ad2a63a2d6ef57c32c7887bb25da9d42c0acfb887c6334c938839c9a43aca93b2c7468915d1846576f92c342046d1fL', 'e=', '0x7', 'c=', '0x26cd2225c0229b6a3f1d1d685e53d114aa3d792737d040fbc14189336ac12fb780872792b0c0b259847badffd1427897ede0d60247aa5e79633f27ccb43e7cc2L')
给了我们三组数据,符合低加密指数广播攻击,于是我们找一个脚本:
import binascii,gmpy2
n =[0x683fe30746a91545a45225e063e8dc64d26dbf98c75658a38a7c9dfd16dd38236c7aae7de5cbbf67056c9c57817fd3da79dc4955217f43caefde3b56a46acf5d,0xa39292e6ad271bb6a2d1345940dfab8001a53d28bc7468f285d2873d784004c2653549c589dae91c6d8238977ff1c4bea4f17d424a0fc4d5587661cc7dde3a77,0x52c32366d84d34564a5fdc1650fc401c41ad2a63a2d6ef57c32c7887bb25da9d42c0acfb887c6334c938839c9a43aca93b2c7468915d1846576f92c342046d1f]
c =[0x673c72ace143441c07cba491074163c003f1a550eab56b1255e5ea9fa2bbd68fd6a9ccb48db9fd66d5dfc6a55c79cad3d9de53f700a1e3c2a29731dc56ba43cd,0x6111357d180d966a495f38566ebe4ea51fa0d54159b22bbd443cde9387687d87c08638483b39221883453a5ad09f6a0e3726b214e8e333037d178a3d0f125343,0x26cd2225c0229b6a3f1d1d685e53d114aa3d792737d040fbc14189336ac12fb780872792b0c0b259847badffd1427897ede0d60247aa5e79633f27ccb43e7cc2]
def CRT(mi, ai):assert(reduce(gmpy2.gcd,mi)==1)assert (isinstance(mi, list) and isinstance(ai, list))M = reduce(lambda x, y: x * y, mi)ai_ti_Mi = [a * (M / m) * gmpy2.invert(M / m, m) for (m, a) in zip(mi, ai)]return reduce(lambda x, y: x + y, ai_ti_Mi) % M
e=0x7
m=gmpy2.iroot(CRT(n, c), e)[0]
print(binascii.unhexlify(hex(m)[2:].strip("L")))
工具介绍
看了这么多RSA的解密方式是不是有点晕了,在遇到这些问题时一步一步做还是挺麻烦的,接下来给大家讲解一款专门用来解决RSA算法问题的工具:RsaCtfTool
文件结构如下:
git clone https://github.com/ius/rsatool.git
cd rsatool//进入这个目录
python setup.py install
基本用法:
已知公钥(自动求私钥) –publickey,密文 —-uncipherfile。
python RsaCtfTool.py --publickey 公钥文件 --uncipherfile 加密的文件
已知公钥求私钥
python RsaCtfTool.py --publickey 公钥文件 --private
openssl
openssl可以实现:秘钥证书管理、对称加密和非对称加密 。
生成PKCS#1私钥
openssl genrsa -out rsa_prikey.pem 1024-out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密1024 生成密钥的长度(生成私钥为PKCS#1)
根据私钥生成公钥
openssl rsa -in rsa_prikey.pem -pubout -out pubkey.pem-in 指定输入的密钥文件-out 指定提取生成公钥的文件(PEM公钥格式)
公钥加密文件
openssl rsautl -encrypt -in input.file -inkey pubkey.pem -pubin -out output.file-in 指定被加密的文件-inkey 指定加密公钥文件-pubin 表面是用纯公钥文件加密-out 指定加密后的文件
私钥解密文件
openssl rsautl -decrypt -in input.file -inkey key.pem -out output.file-in 指定需要解密的文件-inkey 指定私钥文件-out 指定解密后的文件
RSA用法
openssl rsa [-inform PEM|NET|DER] [-outform PEM|NET|DER] [-in filename] [-passin arg] [-out filename] [-passout arg] [-sgckey] [-des] [-des3] [-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout] [-engine id]</pre>
常用选项:
-in filename:指明私钥文件
-out filename:指明将提取出的公钥保存至指定文件中
-pubin:根据公钥提取出私钥
-pubout:根据私钥提取出公钥
结语
今天比较详细的总结了个人在遇到RSA题目时的一些经验,可能有一些确实不太好理解,这里也提供了工具去解决,喜欢的小伙伴不妨一键三连支持一下。