rsa加密初探
RSA加密算法初探
RSA加密算法是早期的非对称加密,公钥和私钥分离,公开公钥,通过确保私钥的安全来保证加密内容的安全。由麻省理工学院的罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的,所以算法由他们三人的姓名首字母来命名。
有关RSA加密算法原理以及应用的文章在网上有很多,CTF中,RSA在密码学,misc以及逆向中考察得也很频繁(有些题目中好像也会出现RSA的魔改版本~Orz)。这里是我个人在学习RSA加密算法中的一点梳理和总结,主要从数学原理、加密原理以及RSA加密算法攻击层面的常见手段出发,剖析RSA加密。
一、数学原理
从数学层面理解RSA加密算法的核心,在于对于欧拉函数和模反运算的理解。
1、欧拉函数
对于一个正整数n,我们要计算小于n的正整数中,有多少和n互质(即和n只有一个公约数1),我们通过欧拉函数来计算。
(1)当n=1时,则 φ(1) = 1;
(2)当n是一个质数时,φ(n)=n-1,因为质数本身只有1和它本身两个约数,所以质数和小于它的任何正整数都互质;
(3)当n是一个质数的k次方时,即n=p^k(p为质数,k为大于等于1的整数),则φ(n)=p^k-p^(k-1),可以看到,k=1的时候,第2种情况就是第3种的特殊情况;
(4)欧拉函数是一个积性函数,即如果n可以分解成两个互质的整数之积,即n = p1 × p2,这时候φ(n) = φ(p1p2) = φ(p1)φ(p2);
(5)n可以写成一系列质数的积的形式,φ(n)=n(1-1/p1)(1-1/p2)…(1-1/pr),p1,p2…pr分别表示n可以被分解的最小质数。这个公式是欧拉函数的通用计算公式。
2、欧拉定理
欧拉定理是费马小定理的一般化,费马小定理有如下描述。
假如a是一个整数,p是一个质数,那么a^p-a是p的倍数,可以表示为:
a^p-a=kp(k为整数),即可表示为:
a^p≡a (mod p),当a是p的倍数时,a^p≡a(mod p)=0。当a不是p的倍数时,可写作a^(p-1)≡1(mod p)。
欧拉给予费马小定理以一般化(膜真神):欧拉定理表明,两个正整数a,n,在a和n互质的情况下(即gcd(a,n)=1),a^φ(n)≡1 (mod φ(n))。
3、模反运算
举个例子,对于ed≡1 (mod φ(n)),要求出d的值。上式等价于:ed-1=kφ(n),k为整数。这时候,模反运算就可以等价为一个二元一次方程。求解二元一次方程的过程,这里也分析一下。
要求出d,需要用到拓展欧几里得算法。在了解拓展欧几里得算法之前,首先要看一下贝祖定理。
贝祖定理:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 (x,y) ,使得 gcd(a,b)=ax+by。
拓展欧几里得算法,我们可以通过一个例子来看一下。求解不定方程:17x+3120y=1。
观察可得,17和3120互质,这个方程满足贝祖等式,我们这里通过辗转相除法计算:
(1)3120=18317+9
(2)17=9+8
(3)9=8+1
求得1为最大公约数,然后移项
(1)9=3120+183(-17)
(2)8=17+9(-1)
(3)1=9+8(-1)
接着用(2)式中的8=17+9(-1)替换掉三式中的”8”,依次类推:
(1)1=9+[17+9(-1)](-1)
(2)1=92+17(-1)
(3)1=[3120+183(-17)]2+17(-1)
(4)1=31202+17(-367)
那么最后求得的x=-367,y=2。
对于互质的整数a,b而言,贝祖等式可以写为a^x+b^y=1。二元一次方程是一个不定方程,所以需要找到一组解(x0,y0),然后用(x0,y0)去表示一组解的通解。
二、RSA加密原理
1、公钥私钥产生和分配
(1)进行加密之前,首先找出2个不同的大质数p和q;
(2)计算n=p*q,这里在选取p和q的时候,应该注意几点:p和q不能选取的太近,我们一般取同一数量级之中,差比较大的两个数;
(3)根据欧拉函数,求得φ(n)=φ(p)φ(q)=(p-1)(q-1);
(4)找出一个公钥e,e要满足:1<e<φ(n)的整数,且使e和φ(n)互质;
(5)根据e*d除以φ(n)余数为1,找到私钥d,这里求d,就是求一个模反运算,可以通过拓展欧几里得算法来计算;
(6)公钥就是(n,e),私钥就是(n,d)
2、加解密
m为密文,c为明文,这里的密文和明文都是数字的形式,对于字符串来说,可以取ascll码和unicode码。
RSA加密:m^e ≡ c (mod n)
RSA解密:c^d ≡ m (mod n)
RSA算法的安全性在于:已知公钥e和质数乘积n,要通过模反运算计算出私钥,需要计算出φ(n),由上文提到的欧拉函数计算的第三条可以得到φ(n)
=(q-1)(p-1),计算φ(n)需要得到质数q和p。你可以通过质数q和p来计算出n,但是要将n进行因数分解是非常困难的。所以,在选取的n足够大的情况下,要进行因数分解是一件非常困难的方法。未来要进行高于1024个二进制位私钥的破解,可能只有两种思路:足够强大的计算力,数学领域能够在因数分解方面提出全新的方法。所以截止目前为止,对于RSA加密算法来说,没有足够有效的方法进行破解。
RSA目前人类分解的最大整数是232个十进制位,768个二进制位。所以,一般在加密过程中使用1024个二进制位的密钥,在对安全性要求很高的情况下,使用2048个二进制位的密钥,我们认为这是绝对安全的。
CTF中的RSA
CTF中对于RSA的考察相当地频繁,水平有限,这里以我个人学习经历,总结几种比较常见的攻击手段。
模数分解
工业界常用到的RSA加密是1024或者2048个二进制位的密钥。但是在题目中,常常给出256位的密钥。这时候,我们可以利用一些工具直接对n进行分解,得到p,q,然后通过题目中给出的(n,e),密文m,利用拓展欧几里得算法来计算出私钥d,求出明文。这也是最基础的考察方式。
低加密指数攻击
m^e≡c(mod φ(n)),当e==2或e==3,且明文较小时,m^3=nk+c,这时候可以爆破一下k的值,然后对nk+c求解立方根。这种题目,很多时候需要多线程跑一下,也可以用现成的一些工具,前段时间CYBRICS CTF就有这样一道题目。
模不互素
模不互素攻击,需要满足以下条件:
1、有两个或者以上的模数,且模数之间不互素,即存在最大公约数;
2、对两段明文进行加密时,选取了相同的e来求解d;
模不互素,通过辗转相除法求解两个模数的公约数,这时候就可以成功分解两个质数q和p,这时候再要对密文进行求解,就非常简单了。
RSA共模攻击
共模攻击的条件:题目给出两对公钥(n,e1),(n,e2),且n1,n2互质,给出分别由两对秘钥加密的两组密文m1,m2。
这时候我们已知的条件是:e1,e2,m1,m2,n。
由于e1,e2互质,由贝祖定理可得:e1s1+e2s2=1。s1和s2可以由拓展欧几里得算法得知。这时候明文m满足条件:m=(c1^s1)*(c2^s2)%n。由此可以解得明文。
RoarCTF:EZRSA
from Crypto.Util.number import *
from gmpy2 import *
from secret import *
assert(flag.startwith('flag{')) and (flag.endwith('}'))
assert(is_prime(beta) and len(bin(beta)[2:]) == 512)
assert(len(bin(x)[2:]) == len(bin(y)[2:]))
# This is tip!!!
assert(tip == 2*x*y*beta + x + y)
p = 2*x*beta + 1
q = 2*y*beta + 1
assert(is_prime(p) and is_prime(q))
n = p*q
e = 65537
m = bytes_to_long(flag)
enc = powmod(m,e,n)
给出了算法和提示,公钥和密文也给出来了,tip可以用一下表达式来求解:
tip=(n-1)/(2*beta)
如果能够求解出x和y的话,也就可以算出p和q,算出p和q的话,就可以求出N=(p-1)*(q-1)的值。然后通过拓展欧几里得算法就可以求出私钥(n,d),然后通过d实现对密文的解密。