揭秘公钥加密算法 RSA

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

1、对称加密

然而这种加密方式有诸多缺陷,随着网络规模的不断增大,每多一个用户就需要保存许多额外的密钥,密钥的管理也将逐渐成为所有人的负担,更加致命的是,密钥必须通过见面协商,而没有办法直接通过网络进行交换,因为密钥的传输过程需要进行加密,而没有密钥则不能进行加密。

那有没有一种可能性,我们用不同的密钥对数据进行加密和解密,其中对数据加密的密钥是对所有人公开的,而对数据接秘密的密钥却仅为接收者持有呢?

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

2、模运算(Modular arithmetic)

又叫做求余运算,像计算机中的伪随机数散列算法(hash)都是他的经典应用,试想一下下面这个例子:
3 3 m o d 7 3^3 mod 7 33mod7

用我们小学二年级学过的知识, 3 3 3^3 33 得到27,并对7取余数得到 6,但已知答案是6的情况下,我们应当如何寻找 x 的值呢?
3 x m o d 7 = 6 3^x mod 7 = 6 3xmod7=6

由于求余算法并不可逆,我们只能一个一个数的带进去试;
3 0 m o d 7 = 1 3^0 mod 7 = 1 30mod7=1
3 1 m o d 7 = 3 3^1 mod 7 = 3 31mod7=3
3 2 m o d 7 = 2 3^2 mod 7 = 2 32mod7=2
3 3 m o d 7 = 6 3^3 mod 7 = 6 33mod7=6
3 4 m o d 7 = 4 3^4 mod 7 = 4 34mod7=4
3 5 m o d 7 = 5 3^5 mod 7 = 5 35mod7=5

但如果出现下面这个很大很大的数,再去一一尝试就很不现实了。
3 x m o d 8761287461782361827361827361278361823761827312 3^x mod 8761287461782361827361827361278361823761827312 3xmod8761287461782361827361827361278361823761827312

这也就是为什么模运算被称作 单向函数,因为对于大数来说,对模运算求逆根本上不现实的,而公钥加密正是利用了模运算的这个特性。假设我们将原始数据表示成一个数 m(message),然后我们对 m e m^e me求e次幂 ,这里的e(encrypt)可以看作是我们加密时用的密钥,然后我们将结果除以N并取余数,最后得到密文 c(cipher)
m e m o d N = c m^e mod N = c memodN=c

并且根据我们之前讲到的,正向计算出这里的密文c 很简单,但反向推出这里的原始数据却很难;

加密 m e m o d N = c m^e mod N = c memodN=c


解密 c d m o d N = m c^d mod N = m cdmodN=m

我们需要对密文c 求 d次幂,这里的d(decrypt)代表另一个用于解密的密钥,最后得到的结果是原始数据m,为了更好的理解,讲两个公式合并为一个更为简洁的形式:
( m e ) d m o d N = m (m^e)^d mod N = m (me)dmodN=m

m的e*d次幂,除以N取余数,将会得到原始数据m,可以发现,如何选取这里的e和d是公钥加密的关键,欧拉定理(Euler's Theorem)公式:
m φ ( n ) ≡ 1 ( m o d n ) mφ(n)≡1(mod n) mφ(n)≡1(mod n)

欧拉定理表示,对于任何一个与n互斥的正整数m,取它的 φ n φ^n φn,并除以n取余数,结果都永远等于1,这里的 φ n φ^n φn是欧拉函数,它代表在小于或等于n的正整数中,有多少个与n互斥的数,举个例子: φ 6 φ^6 φ6 在小于等于6的正整数中,只有1和5互为质数,也就是说,他们除了1以外,并不存在其他公约数,所以 φ n φ^n φn = 2。

在了解了 φ n φ^n φn函数之后,回到欧拉定理,又双叒叕开始变换公式了;
( m φ ( n ) ) k ≡ 1 k ( m o d n ) (mφ(n))^k≡1^k(mod n) (mφ(n))k≡1k(mod n)

在等式两端同时去k次幂,k代表任意的正整数,接着在两端同时乘以m,
( ( m φ ( n ) ) k ) ∗ m ≡ 1 k ∗ m ( m o d n ) ((mφ(n))^k)*m≡1^k*m(mod n) ((mφ(n))k)∗m≡1k∗m(mod n)

并简化成这样的形式:
( ( m k ) φ ) n ) + 1 m o d n = m ((m^k)^φ)^n)^+1 mod n = m ((mk)φ)n)+1modn=m

是不是有点眼熟?对了把它和上面的这个公式对比一下:
( m e ) d m o d N = m (m^e)^d mod N = m (me)dmodN=m

你会发现,公式的指数 k φ ( n ) + 1 = e d kφ(n)+1 = ed kφ(n)+1=ed,变换一下得到:
d = ( k φ ( n ) + 1 ) / e d = (kφ(n)+1)/e d=(kφ(n)+1)/e

也就是说,我们选取这里的 k,n,e 来计算出解密的密钥d。实际上,要计算 k φ ( n ) kφ(n) kφ(n)的唯一办法就是对数n做质因数分解,比如 27 = 3 * 3 * 3、11445 = 3 * 5 * 7 * 109 这样,然而对大数的分解是很困难的事情,所以对 k φ ( n ) 的 kφ(n)的 kφ(n)的求解,可以看作是计算上不可行的,但是如果n本身是一个质数,情况就有所不同了,比如对于kφ(7)来说,小于等于7并与7互质的数有1-6,除了7本身,因此 k φ ( 7 ) = 6 kφ(7)=6 kφ(7)=6;同理对于 k φ ( 13 ) kφ(13) kφ(13)来说,与13互质的数,除了13本身,其他的全部都是,因此kφ(13)= 12。

其实对于任何的 k φ ( p ) = p − 1 kφ(p) = p-1 kφ(p)=p−1,除此之外, φ φ φ还有一个重要的特性,对于任意两个互质的整数 p 和 q , φ ( p ) = p − 1 φ(p) = p -1 φ(p)=p−1 可以拆分为 φ ( p ∗ q ) = φ ( p ) ∗ φ ( q ) φ(p*q) = φ(p) * φ(q) φ(p∗q)=φ(p)∗φ(q) ,例如我们可以选取两个质数17和23,由于 φ ( 17 ∗ 23 ) = φ ( 17 ) ∗ φ ( 23 ) φ(17*23) = φ(17) * φ(23) φ(17∗23)=φ(17)∗φ(23) = 16*32 = 352,因此可得: φ ( 17 ∗ 23 ) = φ ( 391 ) = 352 φ(17*23) =φ(391) = 352 φ(17∗23)=φ(391)=352,带入 d = ( k φ ( n ) + 1 ) / e d = (kφ(n)+1)/e d=(kφ(n)+1)/e再得:
d = ( k φ ( n ) + 1 ) / e = ( 5 ∗ 352 + 1 ) / 3 = 587 d = (kφ(n)+1)/e = (5*352+1)/3 = 587 d=(kφ(n)+1)/e=(5∗352+1)/3=587

于是在k=5的情况下,求得用于解密的密钥d=587,在求出了私钥d以后,算法会将e、n公布,作为加密时的公钥,而d将保存下来作为解密时用的私钥,其他人由于不知道p和q这两个关键的质因数,没有办法计算出这里的 φ n φ^n φn,因而无从破解这里的私钥 d,公钥加密正是利用了这个信息的不对等,让加密者能够快速够着出一个 φ n φ^n φn,而其他人却无法在有限的时间内求解它。

3、举个例子

用e = 3,d = 587,n = 391 来模拟一段信息加密解密的过程,我们要加密的字符是"a",它所对应的ascii码是97,于是 9 7 3 m o d 391 = 79 97^3 mod 391 = 79 973mod391=79,79是我们加密后的密文,为了解密 7 9 5 87 m o d 391 = 97 79^587 mod 391 = 97 79587mod391=97,因此成功还原了字符"a"。

以上讲到的就是公钥加密算法的全部工作原理,这个算法在首次被发现之后,并被机密作为封了起来,后来又在1977年被三个麻省理工的数学家 Ron Rivest 、Adi Shamir 、 Leonard Adleman 独立发掘,成为当下众所周知的 RSA 加密算法,像数字签名,数字证书,SSH、HTTPS的加密连接,全部都是它的典型应用。

在实际使用中,由于公钥加密的计算量比较大,速度慢,通常会和对称加密算法一同使用,公钥加密算法常被用作最初连接的建立,而真正数据传输的过程,会交由对称加密算法来处理,完结!

相关推荐
Navigator_Z2 小时前
LeetCode //C - 1089. Duplicate Zeros
c语言·算法·leetcode
上海云盾-小余4 小时前
BGP 高防 IP 与 CDN 混合部署:攻防场景选型实战指南
网络·网络协议·tcp/ip
云泽8084 小时前
C++ 可调用对象通关指南:深度解析 Lambda 表达式、function 包装器与 bind 绑定器
开发语言·c++·算法
wlsh155 小时前
Go 迭代器
算法
语戚5 小时前
力扣 3161. 块放置查询:线段树解法(Java 实现)
java·算法·leetcode·面试·线段树·力扣·
CS创新实验室6 小时前
从顺序表到动态数组:数据结构的永恒基石与现代语言的优雅封装
数据结构·算法
Black蜡笔小新6 小时前
自动化AI算法训练服务器DLTM训推一体化平台助力农业生产管理实现安全智能化
人工智能·算法·自动化
8Qi87 小时前
LeetCode 23. 合并 K 个升序链表 —— 小顶堆(PriorityQueue)
数据结构·算法·leetcode·链表·
QiLinkOS8 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
松间听晚8 小时前
Agentic RL 环境和代码学习:以HGPO为例
算法