CTFCrypto练习之RSA算法
2017-01-15 16:38
246 查看
简介
RSA属于非对称加密算法,因为RSA使用了两个不同的密钥分别用于加密和解密,这两个密钥称之为公私钥对,其中公钥用于加密,且公钥是公开的,而私钥用于解密,私钥是私有的。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK(对于简答的加密的处理的话还是可以破解的)。
RSA加密过程
找到两个大素数p和q,计算出n=p×q
得到φ=(p−1)×(q−1),然后选择一个e(1<e<φ),且gcd(φ,e)=1,gcd为最大公约数,即e和φ互质(互为质数)
计算出d,计算方法:(e×d)%φ=1
得到了公私钥对,其中{e,n}为公钥,{d,n}为私钥。
针对明文M,进行加密:C=Me%n,得到的C即为密文
针对密文C,进行解密,M=Cd%n,得到的M即为明文
通过上面的加密方式和解密方式可以知道,明文是以数字的方式进行加密和解密,一般都是针对单个字符的ASCII码进行加密,也可能两个…,这里的操作对象为位数小于n的位数的数据,比如说一串数据变为二进制为111011101101,而n的位数为5那么你要处理的数据可能是1位二进制,2位二进制,3位二进制和4位二进制
图如下:
接下来的详细分析要进行一些知识讲解
欧几里得算法和扩展欧几里得算法(当然其中素数和质数之类的知识百度一下就知道了),在本人的博客中有写,这是地址:数学基础讲解
简单的破解RSA算法
之前也说了,RSA的公钥是公开的,即对于知道{e,n}的数据,如果n比较小的话我们是可以暴力出结果的,这就是所谓的数学暴力攻击
攻击方法一般是:给定RSA的公钥{e,n},根据RSA的定义,如果能够将n分解为两个素数的乘积,即n=p×q,那么就可以计算出d了,也就是得到私钥{d,n}
所以这种方法只能针对n的值非常小的情况下,基本最大就是108大小的,这应该就是n可以暴力的极限了,二进制位数为32位。
举个例子
已知n,e,我们可以暴力查找质数,从而得到φ=(p−1)×(q−1),然后针对(e×d)%φ=1求出d来。
这里就可以用扩展欧几里得算法来求解,基本求解方法本人博客中也提到了,这里简单提醒一下
令d为x
(1)(e×x)%φ=1
(2)e×x=φ×y+1
(3)e×x−φ×y=1
(4)e×x+φ×y=1
所以就是求解x的值,如果求出的x为负数,就需要不断的调整将它变为正数,这些知识点在本人讲扩展欧几里的算法的时候都已经详细介绍了,这里稍微提一下:
如果x<0,那么将式子变为e×(x+φ)+φ×(y+e)=1
然后令x=x+k×φ,y=y+e×k,原式变为e×x+φ×y=1,变回了原来的式子,这就是变为正数的方法,其实就是在一条直线上面来回移动x轴上的点将它变为正整数就可以了
所以这里可以简化,但我们求出的值为一个负数的时候我们只需要将x变为正数不需要管y的值,所以x=x+k×φ,所以我们写个循环判断加φ直到x为正数
简单破解例题讲解
已知公钥为{49,851}以及RSA密文数据[617,673,319,695,16,252,299,319,657,346,767,299,346,88],请还原对应的明文
通过上述说的步骤我们可以得到如下数据:
n=37∗23=851
φ=36∗22=792
e=49
其中n=p×q,p=37,q=23的求解方式为for循环暴力:
c++代码算出d的值
这里用了一个c++求解扩展欧几里的算法结果的模板,solve()和exgcd()这两个函数,给出这个函数运用地址:http://blog.csdn.net/qwb492859377/article/details/47679225
接下来是python代码,这个代码就是用上面是说的怎么让x为正数
得到d=97,然后我们写破解代码
c++破解代码
python代码
c++执行代码结果
python执行代码结果
RSA属于非对称加密算法,因为RSA使用了两个不同的密钥分别用于加密和解密,这两个密钥称之为公私钥对,其中公钥用于加密,且公钥是公开的,而私钥用于解密,私钥是私有的。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK(对于简答的加密的处理的话还是可以破解的)。
RSA加密过程
找到两个大素数p和q,计算出n=p×q
得到φ=(p−1)×(q−1),然后选择一个e(1<e<φ),且gcd(φ,e)=1,gcd为最大公约数,即e和φ互质(互为质数)
计算出d,计算方法:(e×d)%φ=1
得到了公私钥对,其中{e,n}为公钥,{d,n}为私钥。
针对明文M,进行加密:C=Me%n,得到的C即为密文
针对密文C,进行解密,M=Cd%n,得到的M即为明文
通过上面的加密方式和解密方式可以知道,明文是以数字的方式进行加密和解密,一般都是针对单个字符的ASCII码进行加密,也可能两个…,这里的操作对象为位数小于n的位数的数据,比如说一串数据变为二进制为111011101101,而n的位数为5那么你要处理的数据可能是1位二进制,2位二进制,3位二进制和4位二进制
图如下:
接下来的详细分析要进行一些知识讲解
欧几里得算法和扩展欧几里得算法(当然其中素数和质数之类的知识百度一下就知道了),在本人的博客中有写,这是地址:数学基础讲解
简单的破解RSA算法
之前也说了,RSA的公钥是公开的,即对于知道{e,n}的数据,如果n比较小的话我们是可以暴力出结果的,这就是所谓的数学暴力攻击
攻击方法一般是:给定RSA的公钥{e,n},根据RSA的定义,如果能够将n分解为两个素数的乘积,即n=p×q,那么就可以计算出d了,也就是得到私钥{d,n}
所以这种方法只能针对n的值非常小的情况下,基本最大就是108大小的,这应该就是n可以暴力的极限了,二进制位数为32位。
举个例子
已知n,e,我们可以暴力查找质数,从而得到φ=(p−1)×(q−1),然后针对(e×d)%φ=1求出d来。
这里就可以用扩展欧几里得算法来求解,基本求解方法本人博客中也提到了,这里简单提醒一下
令d为x
(1)(e×x)%φ=1
(2)e×x=φ×y+1
(3)e×x−φ×y=1
(4)e×x+φ×y=1
所以就是求解x的值,如果求出的x为负数,就需要不断的调整将它变为正数,这些知识点在本人讲扩展欧几里的算法的时候都已经详细介绍了,这里稍微提一下:
如果x<0,那么将式子变为e×(x+φ)+φ×(y+e)=1
然后令x=x+k×φ,y=y+e×k,原式变为e×x+φ×y=1,变回了原来的式子,这就是变为正数的方法,其实就是在一条直线上面来回移动x轴上的点将它变为正整数就可以了
所以这里可以简化,但我们求出的值为一个负数的时候我们只需要将x变为正数不需要管y的值,所以x=x+k×φ,所以我们写个循环判断加φ直到x为正数
while(x < 0){ x += φ }
简单破解例题讲解
已知公钥为{49,851}以及RSA密文数据[617,673,319,695,16,252,299,319,657,346,767,299,346,88],请还原对应的明文
通过上述说的步骤我们可以得到如下数据:
n=37∗23=851
φ=36∗22=792
e=49
其中n=p×q,p=37,q=23的求解方式为for循环暴力:
//其中prime是一个素数的表,isprime也是一个素数的表用于判断是否为素数 for(int i = 1;i < len;i ++){ if(n % prime[i] == 0 && isprime[n/prime[i]]){ //输出prime[i]和n/prime[i] break; } }
c++代码算出d的值
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; LL exgcd(LL a, LL b, LL &x, LL &y) { if(b == 0) { x = 1; y = 0; return a; } LL r = exgcd(b, a % b, x, y); LL t = y; y = x - a / b * y; x = t; return r; } /*可以得到x>=bound时的x和y,返回true表示有解*/ bool solve(LL a, LL b, LL c, LL bound, LL &x, LL &y) { LL xx, yy, d = exgcd(a, b, xx, yy); if(c % d) return false; xx = xx * c / d; yy = yy * c / d; LL t = (bound - xx) * d / b; x = xx + b / d * t; if(x < bound) { t++; x = xx + b / d * t; } y = yy - a / d * t; return true; } int main(){ LL k = 792, e = 49; LL x, y; solve(e, k, 1, 0, x, y); printf("%lld\n", x); return 0; }
这里用了一个c++求解扩展欧几里的算法结果的模板,solve()和exgcd()这两个函数,给出这个函数运用地址:http://blog.csdn.net/qwb492859377/article/details/47679225
接下来是python代码,这个代码就是用上面是说的怎么让x为正数
#! /usr/bin/env python # -*- coding=utf-8 -*- import math #扩展欧几里得算法求解 def exgcd(a, b): if a < b: return exgcd(b, a) if b == 0: return a , 1, 0 gcd , x, y = exgcd(b, a % b) return gcd, y, x - a / b * y #求解d的值 def getd(): k = 792 e = 49 gcd, y, x = exgcd(k, e) while x < 0: x += k return x if __name__ == '__main__': print getd()
得到d=97,然后我们写破解代码
c++破解代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; //快速幂,知识点数学基础博客中有 /*x^n%mod*/ LL pow_LL(LL x, LL n, LL mod){ LL ret = 1; while(n > 0){ if(n & 1) ret = ret * x % mod; x = x * x % mod; n >>= 1; } return ret; } int main(){ LL d = 97, n = 851; LL arr[] = {617,673,319,695,16,252,299,319,657,346,767,299,346,88}; for(int i = 0;i < 14;i ++){ printf("%c", pow_LL(arr[i], d, n)); } return 0; }
python代码
#! /usr/bin/env python # -*- coding=utf-8 -*- import math def pow_LL(x, n, mod): ret = 1 while n > 0: if (n & 1) > 0: ret = (ret * x) % mod x = (x * x) % mod n >>= 1 return ret def test(): d = 97 n = 851 arr = [617,673,319,695,16,252,299,319,657,346,767,299,346,88] new_arr = [] for i in arr: new_arr.append(chr(pow_LL(i, d, n))) print "".join(new_arr) if __name__ == '__main__': test()
c++执行代码结果
python执行代码结果
相关文章推荐
- BugKuCTF(CTF-练习平台)——Crypto-一段Base64
- BugKuCTF(CTF-练习平台)——Crypto-.!?
- BugKuCTF(CTF-练习平台)——Crypto-+[]-
- BugKuCTF(CTF-练习平台)——Crypto-奇怪的密码
- BugKuCTF(CTF-练习平台)——Crypto-托马斯.杰斐逊
- BugKuCTF(CTF-练习平台)——Crypto-来自宇宙的信号
- BugKuCTF(CTF-练习平台)——Crypto-滴答~滴
- BugKuCTF(CTF-练习平台)——Crypto-聪明的小羊
- BugKuCTF(CTF-练习平台)——Crypto-ok
- BugKuCTF(CTF-练习平台)——Crypto-简单加密
- BugKuCTF(CTF-练习平台)——WEB-web基础$_GET
- CTF安卓逆向练习第五弹
- CTF/CTF练习平台-本地包含【eval函数闭合及代码段的理解】
- NJCTF-easy_crypto writeup
- CTF杂项之隐写术、Crypto
- CTF/CTF练习平台-phpcmsV9【phpcms 9.6 漏洞利用】
- Crypto知识相关——RSA算法原理与python实现
- bugku CTF练习平台writeup
- CTF中(Crypto)常见的加密解密网站
- BugKuCTF(CTF-练习平台)——WEB-web基础$_POST