RSA算法
RSA算法可以说是使用最为广泛的非对称加密算法。在1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的,并取三人名字的首字母命名。其中的数学原理大致如下:
加密过程
RSA加密过程简单描述如下:
- 选两个大质数 p , q p, q p,q,计算 n = p ⋅ q n=p\cdot q n=p⋅q;
- 选一个大于1的整数 e e e,满足 e e e和 ( p − 1 ) ( q − 1 ) (p-1)(q-1) (p−1)(q−1) 互质, e e e要小于后者;
- 数据 x x x加密后为 y y y,那么加密后的数据 y = x e m o d    n y=x^e\mod n y=xemodn;
这里 ( n , e ) (n,e) (n,e)就作为公钥。其中 ( p − 1 ) ( q − 1 ) (p-1)(q-1) (p−1)(q−1)是 n n n的欧拉函数 ϕ ( n ) \phi(n) ϕ(n)。
解密过程
- 找到一个数字 d d d,满足 d e ≡ 1 m o d    ( p − 1 ) ( q − 1 ) de\equiv1\mod(p-1)(q-1) de≡1mod(p−1)(q−1);
- 数据 y y y解密还原为 x x x ,那么 x = y d m o d    n x=y^d\mod n x=ydmodn;
这里 ( n , d ) (n,d) (n,d)就作为私钥。其中 d d d是 e e e对 ϕ ( n ) \phi(n) ϕ(n)的模反元素。
举例
- 取 p = 11 , q = 17 p=11, q=17 p=11,q=17,那么 n = 11 ⋅ 17 = 187 n=11\cdot17=187 n=11⋅17=187;
- 取 e = 3 e=3 e=3, 与 ( 11 − 1 ) ( 17 − 1 ) = 160 (11-1)(17-1)=160 (11−1)(17−1)=160互质,公钥 ( n , e ) (n,e) (n,e);
- 取 d = 107 d=107 d=107, 满足 d ⋅ e ≡ 1 m o d    160 d\cdot e\equiv1 \mod160 d⋅e≡1mod160,私钥 ( n , d ) (n,d) (n,d);
- 加密数字 x = 20 x=20 x=20,那么 y = x e m o d    n = 2 0 3 m o d    187 = 146 y=x^e\mod n=20^3\mod187=146 y=xemodn=203mod187=146;
- 解密数据 y = 146 y=146 y=146, 那么 x = y d m o d    n = 14 6 107 m o d    187 = 20 x=y^d\mod n=146^{107}\mod 187=20 x=ydmodn=146107mod187=20;
使用python内置的pow函数, pow(x,y[,z])
就是x的y次方对z取模。
>>> x = 20
>>> y = pow(x, 3, 187) # 公钥(187, 3), 加密x
>>> y
146
>>> pow(y, 107, 187) # 私钥(187, 107), 解密y
20
应用场景
通过前面RSA的数学过程可以看出,公钥私钥在加解密上是对称的,即公钥加密私钥解密,私钥加密公钥也可以解密。那么结合公钥私钥的公开与保密特点,可以看出有如下经典实用场景:
- 数据加密:公钥广而告之,公钥所有者都可加密数据,只有私钥所有者可以解密数据;
- 数字签名:私钥私密拥有,只有私钥所有者可以制作数字签名,任何有公钥的人可验证签名;
这里再详细说一下数字签名。数字签名通常还需要结合摘要算法。完整的数据报文通过摘要算法hash出一个固定长度的字符串,比如Git使用的SHA1算法,文件MD5算法等。然后对摘要内容使用私钥加密生成数字签名。对方验证数字签名的时候,也是先用同样的摘要算法算出摘要,然后使用公钥解密签名还原摘要,对比两者是否相同。
理论证明
RSA算法用到的数论知识有:欧拉定理、费马小定理、扩展欧几里得算法(生成一组公私钥)。理解这些数论原理的证明是有一定难度,但是通过这些数论原理来理解RSA的如何加密解密就相对简单了,致敬那些伟大的数学家。
在知乎上如何用通俗易懂的话来解释非对称加密,有个回答很形象:
让对方任意想一个3位数,并把这个数和91相乘,然后告诉我积的最后三位数,我就可以猜出对方想的是什么数字啦!
比如对方想的是123,那么对方就计算出123 * 91等于11193,并把结果的末三位193告诉我。看起来,这么做似乎损失了不少信息,让我没法反推出原来的数。不过,我仍然有办法:只需要把对方告诉我的结果再乘以11,乘积的末三位就是对方刚开始想的数了。可以验证一下,193 * 11 = 2123,末三位正是对方所想的秘密数字!
其实道理很简单,91乘以11等于1001,而任何一个三位数乘以1001后,末三位显然都不变(例如123乘以1001就等于123123)。