了解RSA之前,想必大家都听说过 对称加密算法 ,也就是说信息的收发方会通过实现商订好的密钥,对数据进行加密和解密
1、对称加密

然而这种加密方式有诸多缺陷,随着网络规模的不断增大,每多一个用户就需要保存许多额外的密钥,密钥的管理也将逐渐成为所有人的负担,更加致命的是,密钥必须通过见面协商,而没有办法直接通过网络进行交换,因为密钥的传输过程需要进行加密,而没有密钥则不能进行加密。
那有没有一种可能性,我们用不同的密钥对数据进行加密和解密,其中对数据加密的密钥是对所有人公开的,而对数据接秘密的密钥却仅为接收者持有呢?

在公钥加密算法中,由于公钥是对所有人公开的信息,我们需要保证数据被"公钥"加密之后,不能够被轻易地反推出来,那什么样的算法单向计算容易,而逆向反推却非常难呢?

2、模运算(Modular arithmetic)
又叫做求余运算,像计算机中的伪随机数
、散列算法(hash)
都是他的经典应用,试想一下下面这个例子:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 3 m o d 7 3^3 mod 7 </math>33mod7
用我们小学二年级学过的知识, <math xmlns="http://www.w3.org/1998/Math/MathML"> 3 3 3^3 </math>33 得到27,并对7取余数得到 6,但已知答案是6的情况下,我们应当如何寻找 x
的值呢?
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 x m o d 7 = 6 3^x mod 7 = 6 </math>3xmod7=6
由于求余算法并不可逆,我们只能一个一个数的带进去试;
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 0 m o d 7 = 1 3^0 mod 7 = 1 </math>30mod7=1
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 1 m o d 7 = 3 3^1 mod 7 = 3 </math>31mod7=3
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 2 m o d 7 = 2 3^2 mod 7 = 2 </math>32mod7=2
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 3 m o d 7 = 6 3^3 mod 7 = 6 </math>33mod7=6
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 4 m o d 7 = 4 3^4 mod 7 = 4 </math>34mod7=4
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 5 m o d 7 = 5 3^5 mod 7 = 5 </math>35mod7=5
但如果出现下面这个很大很大的数,再去一一尝试就很不现实了。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 3 x m o d 8761287461782361827361827361278361823761827312 3^x mod 8761287461782361827361827361278361823761827312 </math>3xmod8761287461782361827361827361278361823761827312
这也就是为什么模运算被称作 单向函数
,因为对于大数来说,对模运算求逆根本上不现实的,而公钥加密正是利用了模运算的这个特性。假设我们将原始数据表示成一个数 m(message),然后我们对 <math xmlns="http://www.w3.org/1998/Math/MathML"> m e m^e </math>me求e次幂 ,这里的e(encrypt)可以看作是我们加密时用的密钥,然后我们将结果除以N并取余数,最后得到密文 c(cipher)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> m e m o d N = c m^e mod N = c </math>memodN=c
并且根据我们之前讲到的,正向计算出这里的密文c 很简单,但反向推出这里的原始数据却很难;
加密 <math xmlns="http://www.w3.org/1998/Math/MathML"> m e m o d N = c m^e mod N = c </math>memodN=c
解密 <math xmlns="http://www.w3.org/1998/Math/MathML"> c d m o d N = m c^d mod N = m </math>cdmodN=m
我们需要对密文c 求 d次幂,这里的d(decrypt)代表另一个用于解密的密钥,最后得到的结果是原始数据m,为了更好的理解,讲两个公式合并为一个更为简洁的形式:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( m e ) d m o d N = m (m^e)^d mod N = m </math>(me)dmodN=m
m的e*d次幂,除以N取余数,将会得到原始数据m,可以发现,如何选取这里的e和d是公钥加密的关键,欧拉定理(Euler's Theorem)
公式:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> m φ ( n ) ≡ 1 ( m o d n ) mφ(n)≡1(mod n) </math>mφ(n)≡1(mod n)
欧拉定理表示,对于任何一个与n互斥的正整数m,取它的 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn,并除以n取余数,结果都永远等于1,这里的 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn是欧拉函数,它代表在小于或等于n的正整数中,有多少个与n互斥的数,举个例子: <math xmlns="http://www.w3.org/1998/Math/MathML"> φ 6 φ^6 </math>φ6 在小于等于6的正整数中,只有1和5互为质数
,也就是说,他们除了1以外,并不存在其他公约数
,所以 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn = 2。
在了解了 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn函数之后,回到欧拉定理,又双叒叕开始变换公式了;
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( m φ ( n ) ) k ≡ 1 k ( m o d n ) (mφ(n))^k≡1^k(mod n) </math>(mφ(n))k≡1k(mod n)
在等式两端同时去k次幂,k代表任意的正整数,接着在两端同时乘以m,
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( ( m φ ( n ) ) k ) ∗ m ≡ 1 k ∗ m ( m o d n ) ((mφ(n))^k)*m≡1^k*m(mod n) </math>((mφ(n))k)∗m≡1k∗m(mod n)
并简化成这样的形式:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( ( m k ) φ ) n ) + 1 m o d n = m ((m^k)^φ)^n)^+1 mod n = m </math>((mk)φ)n)+1modn=m
是不是有点眼熟?对了把它和上面的这个公式对比一下:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( m e ) d m o d N = m (m^e)^d mod N = m </math>(me)dmodN=m
你会发现,公式的指数 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( n ) + 1 = e d kφ(n)+1 = ed </math>kφ(n)+1=ed,变换一下得到:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> d = ( k φ ( n ) + 1 ) / e d = (kφ(n)+1)/e </math>d=(kφ(n)+1)/e
也就是说,我们选取这里的 k,n,e 来计算出解密的密钥d。实际上,要计算 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( n ) kφ(n) </math>kφ(n)的唯一办法就是对数n做质因数分解
,比如 27 = 3 * 3 * 3、11445 = 3 * 5 * 7 * 109 这样,然而对大数的分解是很困难的事情,所以对 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( n ) 的 kφ(n)的 </math>kφ(n)的求解,可以看作是计算上不可行的,但是如果n本身是一个质数,情况就有所不同了,比如对于kφ(7)来说,小于等于7并与7互质的数有1-6,除了7本身,因此 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( 7 ) = 6 kφ(7)=6 </math>kφ(7)=6;同理对于 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( 13 ) kφ(13) </math>kφ(13)来说,与13互质的数,除了13本身,其他的全部都是,因此kφ(13)= 12。
其实对于任何的 <math xmlns="http://www.w3.org/1998/Math/MathML"> k φ ( p ) = p − 1 kφ(p) = p-1 </math>kφ(p)=p−1,除此之外, <math xmlns="http://www.w3.org/1998/Math/MathML"> φ φ </math>φ还有一个重要的特性,对于任意两个互质的整数 p 和 q , <math xmlns="http://www.w3.org/1998/Math/MathML"> φ ( p ) = p − 1 φ(p) = p -1 </math>φ(p)=p−1 可以拆分为 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ ( p ∗ q ) = φ ( p ) ∗ φ ( q ) φ(p*q) = φ(p) * φ(q) </math>φ(p∗q)=φ(p)∗φ(q) ,例如我们可以选取两个质数17和23,由于 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ ( 17 ∗ 23 ) = φ ( 17 ) ∗ φ ( 23 ) φ(17*23) = φ(17) * φ(23) </math>φ(17∗23)=φ(17)∗φ(23) = 16*32 = 352,因此可得: <math xmlns="http://www.w3.org/1998/Math/MathML"> φ ( 17 ∗ 23 ) = φ ( 391 ) = 352 φ(17*23) =φ(391) = 352 </math>φ(17∗23)=φ(391)=352,带入 <math xmlns="http://www.w3.org/1998/Math/MathML"> d = ( k φ ( n ) + 1 ) / e d = (kφ(n)+1)/e </math>d=(kφ(n)+1)/e再得:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> d = ( k φ ( n ) + 1 ) / e = ( 5 ∗ 352 + 1 ) / 3 = 587 d = (kφ(n)+1)/e = (5*352+1)/3 = 587 </math>d=(kφ(n)+1)/e=(5∗352+1)/3=587
于是在k=5
的情况下,求得用于解密的密钥d=587
,在求出了私钥d
以后,算法会将e、n
公布,作为加密时的公钥,而d
将保存下来作为解密时用的私钥,其他人由于不知道p和q这两个关键的质因数,没有办法计算出这里的 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn,因而无从破解这里的私钥 d
,公钥加密正是利用了这个信息的不对等,让加密者能够快速够着出一个 <math xmlns="http://www.w3.org/1998/Math/MathML"> φ n φ^n </math>φn,而其他人却无法在有限的时间内求解它。
3、举个例子
用e = 3,d = 587,n = 391 来模拟一段信息加密解密的过程,我们要加密的字符是"a",它所对应的ascii码是97,于是 <math xmlns="http://www.w3.org/1998/Math/MathML"> 9 7 3 m o d 391 = 79 97^3 mod 391 = 79 </math>973mod391=79,79是我们加密后的密文,为了解密 <math xmlns="http://www.w3.org/1998/Math/MathML"> 7 9 5 87 m o d 391 = 97 79^587 mod 391 = 97 </math>79587mod391=97,因此成功还原了字符"a"。
以上讲到的就是公钥加密算法的全部工作原理,这个算法在首次被发现之后,并被机密作为封了起来,后来又在1977年被三个麻省理工的数学家 Ron R
ivest 、Adi S
hamir 、 Leonard A
dleman 独立发掘,成为当下众所周知的 RSA 加密算法,像数字签名,数字证书,SSH、HTTPS的加密连接,全部都是它的典型应用。
在实际使用中,由于公钥加密的计算量比较大,速度慢,通常会和对称加密算法一同使用,公钥加密算法常被用作最初连接的建立,而真正数据传输的过程,会交由对称加密算法来处理,完结!