# RSA 的证明 - [RSA 的证明](#rsa-的证明) - [1. 修订说明](#1-修订说明) - [1.1. 第一次修订](#11-第一次修订) - [1.2. 第二次修订](#12-第二次修订) - [2. 前言](#2-前言) - [3. 基础知识](#3-基础知识) - [4. 加密/解密过程](#4-加密解密过程) - [5. RSA 的证明](#5-rsa-的证明) - [5.1. c 与 n 互质](#51-c-与-n-互质) - [5.2. c 与 n 不互质](#52-c-与-n-不互质) - [5.3. 关于 n 的选取和明文的分割](#53-关于-n-的选取和明文的分割) - [6. RSA 的安全性](#6-rsa-的安全性) - [7. 注释](#7-注释) - [8. 外部参考资料](#8-外部参考资料) ## 1. 修订说明 ### 1.1. 第一次修订 感谢朋友提醒,对(3)及推论进行了修正。 最初写这篇《RSA 的证明》是看到了一篇好文——《“不给力啊,老湿!”:RSA加密与破解 》,但是这篇文章在网络上大部分的分享中,公式大多不完整。而且各处的推演使用的数学语言与程序员习惯的表示方法差异太大了。于是出了此文,对《RSA 加密与破解》进行了总结,并将数学部分换成程序员易于理解的方式。但是大部分内容还是来源于《RSA 加密与破解》,少量的借鉴使用了《RSA 算法基础详解》进行补充说明。 但是,回过头来看这篇文章,虽然当初反复修改,但仍有很多地方表述不明确、不严谨、也不够简洁。例如公式(3)可以得到更多化简,这就导致推导证明 RSA 时可以更加简单高效;在证明 RSA 时本末倒置,没有把证明的根本目标说清楚。 因此,对此文再次进行了修改,希望能够与国内大部分胡乱转载的 RSA 资料有明显的区别,能够起到给网友从另一个角度看问题的启示作用。并尽量将问题说得详细,逻辑顺畅、严谨。 ### 1.2. 第二次修订 RSA 的证明需要区分明文 c 与 n 是否互质的两种情况分别讨论,其最终证明结果都为: ```cpp (c^(d*e))%n=c%n // c%n 为解密结果 ``` 但 c%n 不一定能够还原成 c。参考资料显示,实际的 RSA 算法会将明文分割为多个小块得到许多 c',每个 c' 都小于 n,这就保证了 c'%n=c',进而能还原出 c。 当年我简单的以为此时应等同于 c 与 n 互质的情况,因此 c 与 n 不互质的情况没有进行讨论。但实际上两种情况并不相同,举个简单的例子就可以看出,比如 20%100=20,但 20 与 100 并不互质。 因此,c 与 n 不互质情况下的证明需要补充,以免误导大家。 **再次感谢朋友们在评论区的指正!** 其实当时看了评论是想修正的,但 RSA 的证明是个细致活,尤其是许多资料用的符号各不相同,交叉对比分析困难重重,于是一拖再拖。终于在看到朋友的点赞后,决定挤出时间对这里补正。由于本人对 RSA 的学习仅限于应用,理论上的粗浅分析也是为了工程应用服务(这也是算法部分坚持使用 C 语言风格描写的原因),因此难免仍有错别之处。尤其是 c 与 n 不互质的证明部分,原来参考 **阮一峰** 的文章进行证明,后又参考了 [RSA —— 经典的非对称加密算法](https://zhuanlan.zhihu.com/p/450180396) 的相关部分,并按照自己的理解进行了书写。这部分是否足够严谨仍有待考察。 欢迎理性文明的批评和建议。 ## 2. 前言 RSA 是一种非对称加密算法,能够将大家都能看懂的明文加密成旁人无法读懂的密文。相比之下,最早的加密,如凯撒移位加密,其加密和解密用的是相同的钥匙(密钥),被称作对称加密算法。这种算法,一旦知道了一个密钥,便可以获取所有加密通讯的明文。 但是,如果加密用一把钥匙,而解密只能用另一把钥匙,那么,即便窃听消息的人获得了加密密钥,也无法还原出明文。这样便极大的提高了加密通讯的安全性。这种加密与解密密钥不同的方式被称作非对称加密。 1977年,罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)三人共同提出了著名的非对称加密算法——RSA,是目前安全性最高的加密算法之一。 ## 3. 基础知识 要想清晰的了解这个算法,首先要掌握几个数学概念、定理或公理,其中最核心的要算欧拉定理。17世纪的费马首先给出该定理的一个特殊形式,即费马小定理: **p 是一个正的质数,a 是任意一个不能被 p 整除的整数。那么,a^(p−1)−1 能被 p 整除。** 也就是 ```cpp (a^(p−1))%p=1 ``` 费马有个习惯,就是在书边写注释,由于书边空白一般太小,导致他提出了著名的“费马猜想”却没有地方写证明,于是在书边空白处留下一句“我发现了一个美妙的证明,但由于空白太小而没有写下来”。导致相当长的一段时间内,这个猜想让无数后来人想破脑瓜也不得证。可见,在书边写注释也不是一个好习惯。同样的,”费马小定理“的证明,也是很久以后的事儿了。 一百年后,出了个大牛叫欧拉,话说欧拉一生写了70多本数学专著,几乎把当时所有数学领域都征服了一遍,这么一个具有征服癖的人,自然没有放过费马,于是欧拉狂虐费马小定理,将其扩展到一个更广的适用范围,用数学语言描述如下: ```cpp // 如果 n 是一个正整数,a 是任意一个非 0 整数,且 n 和 a 互质,那么: (1). (a^ϕ(n))%n=1 ``` 其中,ϕ(n) 是欧拉函数,ϕ(n) 等于从 1 到 n-1 中所有与 n 互质的整数的个数。互质,说白了就是公约数只有 1。那么,比如说 5,则 1,2,3,4 都与 5 互质,因此 ϕ(5)=4。 对于质数 p,它和 1,2,3,…,p-1 都互质,所以 ϕ(p\)=p-1。比如 ϕ(11)=10。 由于质数 p 有 ϕ(p\)=p−1。因此,从欧拉定理可以推出费马小定理。在欧拉虐了费马之后,我们可以忘记费马小定理了(话说这里只是调侃哈,费马还是超级牛的)。用一个例子简单的检验欧拉定理:如果 n 是 6,那么 ϕ(6)=2,让 a 为 11,此时 a 和 6 互质,有 11^2-1=120,确实可以被 6 整除,符合欧拉定理。 关于欧拉函数,还有一个推论: ```cpp // m 和 n 是互质的正整数。那么 (2). ϕ(mn)=ϕ(m)*ϕ(n) ``` 除了上面的 (1) 和 (2),还需要提前说明一点: ```bash (3). (a*b)%n=((a%n)*(b%n))%n=((a%n)*b)%n ``` 简单的证明如下: ```md 1. 假设 a 和 b 除以 n 的余数为 c1,c2,则 a 和 b 可以写成 a=n*t1+c1,b=n*t2+c2。 2. 那么,a*b=n^2*t1*t2+n*t1*c2+n*t2*c1+c1*c2。 3. 因此,a*b 除以 n 的余数为 (c1*c2)%n,即 (a*b)%n=((a%n)*(b%n))%n。 4. 最后,((a%n)*b)%n=(c1*(n*t2+c2))%n=(c1*c2)%n ``` 根据此可以 **推论** ```cpp (推论). (a^m)%n=((a%n)^m)%n ``` 以上其实是令人枯燥乏味的数论方面的东西,这些东西本来在古代没太多实际意义,没想到现代计算机和通讯技术的发展,为这些理论开辟出广大的应用空间。RSA 加密,便应用了以上理论。 ## 4. 加密/解密过程 在证明 RSA 算法前,我们先来了解下这个算法和加密解密过程: ```md 1. 先选择两个质数 p 和 q,让 n=p*q,且 n>c; 2. 而 k=ϕ(n)=(p−1)*(q−1); 3. 选择任意 d,条件是 1c,所以 c%n=c,也就是说: ```cpp (c^(d*e))%n=c ``` 此时得证。 ### 5.2. c 与 n 不互质 此时,由于 n 等于质数 p 和 q 的乘积,所以必然有: ```cpp c=h*p // 或 c=h*q ``` 但 c 不可能同时是 p、q 的倍数,否则 c=j*p*q 且 j>=1,这与 n>c 的要求相矛盾(若 c=j*p*q,则有 (c^e)%n=0,导致无法加密)。以 ```cpp c=h*p ``` 为例,此时 c 与 q 必然互质,则根据欧拉定理 (1) 可得: ```cpp (c^ϕ(q))%q=1 // 因为 1 的任意次幂余 q 还是 1,因此对 (c^ϕ(q))%q 求 (t*ϕ(p)) 次幂再余 q,结果也是 1: => ((c^ϕ(q)%q)^(t*ϕ(p)))%q=1 // 反向应用推论可得: => (c^(t*ϕ(p)*ϕ(q)))%q=1 // 设 i 为比例常数,则 => c^(t*ϕ(p)*ϕ(q))=i*q+1 ``` 将 [5. RSA 的证明](#5-rsa-的证明) 中的式子继续化简: ```cpp (c^(k*t+1))%n // k=ϕ(n)=ϕ(p)*ϕ(q),提出 c 的 1 次幂 = (c^(t*ϕ(p)*ϕ(q))*c)%n // 前面证明了 c^(t*ϕ(p)*ϕ(q))=i*q+1,因此: = ((i*q+1)*c)*%n // 由于 (q*c)%n=(q*p*h)%n=(n*h)%n=0,所以 (i*q*c)%n=0,得 = c%n ``` 因为 n>c,所以 c%n=c,也就是说: ```cpp (c^(d*e))%n=c ``` 此时得证。 当 ```cpp c=h*q ``` 时,证法相同。 ### 5.3. 关于 n 的选取和明文的分割 需要注意的是,无论 c 与 n 是否互质,都要求 c%n=c,所以务必保证 n>c。但实际明文是不定长度,若要保证这一点,可以将 c 分割成小块的 c',使得每个 c' 都小于 n。这一点,在工程应用时,需特别注意。 ## 6. RSA 的安全性 为了对 n 求余的时候,不会把数字弄混了,RSA 算法要求所有被加密的数 c 要小于 n。 但 n 大更重要的原因是要保护 p 和 q。想破解,必须找到 d。回顾 RSA 工作过程(注意 n 是公开的),可以这样破解: ```md 1. 先找到隐藏的 p 和 q; 2. 知道了 p 和 q,可以算出 k; 2. d*e=k*t+1,即找到一个 e,可以让 d*e-1 被 k 整除。d 就找到了。 ``` 上面的整个破解过程中,最困难的是第一步——找到两个隐藏的 p 和 q。如果 p 和 q 都选得非常大,比如说 200 位,会导致 n 也非常大,有 400 位。寻找一个 400 位数字的质数分解,对现在的计算机而言并不容易,这需要做除法运算大约 sqrt(10^400)/2 次。相当于 10^199 次除法运算!以超级计算机天河 2 号为例,其浮点运算能力是每秒 10^16 级别。那么,用天河 2 号找到 p 和 q 大约需要 10^174 年。这个活,要请上帝出手了。不过,假如 10^174 年后,天河 2 号得到明文如下(如果天河 2 号还在的话): ```md “10^174年减1天后,此信息作废。” ``` 那么,估计上帝也要哭笑不得了。 ## 7. 注释 1. 符号 % 和函数 mod() 均表示取模运算,可以理解为求余,如 5%3=2; 2. 符号 ^ 表示乘方运算,如 5^2=25; 3. 关于 n 的选取这里只给出的一个简单的方法。一个反例是 p、q 与 c 不互质,例如 p=5,q=7,c=70,很明显 n=35,与 c 不互质; ## 8. 外部参考资料 1. [“不给力啊,老湿!”:RSA加密与破解](https://www.cnblogs.com/vamei/p/3480994.html#!comments) 2. [RSA算法基础详解](https://www.cnblogs.com/hykun/p/RSA.html) 3. [RSA算法原理(一)](http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html) 4. [RSA算法原理(二)](https://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html) 5. [RSA —— 经典的非对称加密算法](https://zhuanlan.zhihu.com/p/450180396):以及网友评论。