RSA基础原理

数论:

复制代码
互质:两个正整数只有一个公因数1时,则称其为互质。比如:6和7互质,而4和6不互质。

欧拉函数 φ(N) :小于或等于 N 的正整数中与 N 互质的数的数目。例如:N = 6 那么此数目为2,φ(6) = 2*3=(2-1)*(3-1)=2 这里为什么不是1*6呢?因为2和3是两个素数。
若 p 为素数,则 φ(p) = p-1 (因为每一个小于p的数(这里指与p互质的小于p的那些数)都与p互质)
又有若 N = p * q,则 φ(N) = φ(p) * φ(q),这里涉及到欧拉函数性质和计算方式,我们不在此深究,感兴趣的可以从N中有哪些和N不互质的数来进行推导本公式。
由此在RSA中,有φ(N) = (p-1) * (q-1)

乘法逆元:

在加法中,我们有a+(−a)=0,我们称其互为相反数。
在乘法中,我们有a⋅(1/a)=1,我们称其互为倒数。
在矩阵中,我们有M⋅M−1=E,我们称其为逆矩阵。

其实我们可以用一个统一的称呼:逆元,即某种运算下的逆元素,我们会发现,元素和其逆元素进行运算之后总是一个定值,实际上在代数中,他们构成了一个群(不用深究),我们只需要了解是在模意义下的乘法逆元即可。

在模 p 意义下,指的是后续的所有运算都是在模 p 的条件下满足,例如 3⋅4≠1
但 (3⋅4) mod 11=(1) mod 11,对于这种式子我们称其为同余式,并且有专门的同余符号进行表示:
                  3⋅4 ≡ 1(mod11)
所以参考上面乘法中的逆元运算规则,在模意义下则有:
                  a⋅a−1 ≡ 1(mod p)
我们称 a 和 a−1 互为在模 p 意义下的乘法逆元。例如上述中的 3 与 4 互为在模 11 下的乘法逆元。
复制代码

 



一、RSA原理

非对称加密

RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥。

非对称加密算法有两种密钥:

公开密钥Pk(Public key):又称公钥,可以公开给所有人进行存储。
私有密钥Sk(Secret key):又称私钥,只能是发送者自己保存。
 
加密原理

 

 

1、乙方生成一对密钥(公钥和私钥)并将公钥向其它方公开。

2、得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。

3、乙方再用自己未公开的私钥对加密后的信息进行解密。乙方只能用其专用密钥(私钥)解密由对应的公钥加密后的信息。

在传输过程中,即使攻击者截获了传输的密文,并得到了乙的公钥,也无法破解密文,因为只有乙的私钥才能解密密文。

同样,如果乙要回复加密信息给甲,那么需要甲先公布甲的公钥给乙用于加密,甲自己保存甲的私钥用于解密。


RSA

那怎么从0开始,进行一个RAS的加密呢?

首先按照加密方式,发送消息的一方,先

生成公私钥:

1、首先选取两个不同的大素数 p和q,然后计算 N = p * q

2、求欧拉函数值 φ(N) = φ(p) * φ(q) = (p-1) * (q-1)

3、选择一个小于 φ(N) 的整数 e,并且满足 e 和 φ(N) 互质,求得 e 在模 φ(N) 意义下的乘法逆元 d,有 e * d ≡ 1 (mod φ(N))

4、销毁 p 和 q

那么 (N,e)是公钥,(N,d)是私钥

加密

RSA算法本质上都是基于数学运算,在加密时我们需要先将消息转化为一个数字 m(例如消息ASCII码的二进制排列转为数字),然后有

c ≡ me(mod N)

此时得到的 c 便是我们的密文。

解密

加密时我们只用到了公钥 (N,e),同理解密时我们也只需用到私钥 (N,d)。有:m ≡ cd(mod N)
此时得到的 m 便是我们的明文消息。

证明:
复制代码
m ​≡ cd ≡ (me)d ≡ med(mod N)    (在模相同情况下,同余式是可以如此转换的)
又有 ed ≡ 1(mod φ(N)),即ed = 1 + kφ(N)。

1、若gcd(m,N) = 1,则med ≡ med−1⋅m ≡ mkφ(N)⋅m ≡ m (mod N)。原始得证。(中间涉及到欧拉定理 aφ(n)≡1(mod n))

2、若gcd(m,N) ≠ 1,则 m 为 p 或 q 的整数,设 m = hp,有

med​ ≡ med−1 ≡ mk(p−1)(q−1)⋅m ≡ (1+xq)⋅m ≡ m + xq⋅hp ≡ m (mod N)

其中

mk(p−1)(q−1) = (mk(p−1))q−1 = 1 + xq​
复制代码

 

二、算法

python请使用3.8以上的版本,我自己用的是3.9.5版本

pycryptodome库

pip3 install pycryptodome
#
python3 -m pip install pycryptodome

路径报错

pip install --target=路径(这里的路径不用担心,报错的时候系统会给出你路径的,只需要复制过来即可) pycryptodome

更新使用

pip install --upgrade --target=上面一样的路径 模块名

 

 

1.生成两个素数

from Crypto.Util.number import *
p = getPrime(512)
q = getPrime(512)
print(p)
print(q)

q和p是两个512位素数,这两个数可以返回一个n位的素数。

 

2. n = p * q,φ (n) = (p - 1) * (q - 1)

n = p * q
phi = (p - 1) * (q - 1)

3. ed ≡ 1(mod φ(n)) , e与phi互素

互素判断,e的乘法逆元

e = 65537
assert GCD(e, phi) == 1 #最大公因数,结果为1时,互素
d = inverse(e, phi)

 

求解d的过程中,我们使用了inverse函数,该函数有两个参数(a,p),作用便是求解a在模p意义下的乘法逆元,那么这里我们便是求解e在模phi下面的乘法逆元,结果为d。之前我们提到了逆元是互为逆元
1
inverse(d, phi) == e

 

以上,(n,e)是公钥,(n,d)是私钥

 

加密:

m 明文:需要加密的消息

m = b‘Nineday’

这里密文是一个bytes类型的字符串,每个字符8位二进制储存,是字符串最原始的存储形式。

直接定义 m = "Nineday" ,这是一个Unicode的字符串,需要转换成bytes类型才能进行后续加密。

 

将字符串转换为数字,将密文转换为数字:

1
m = bytes_to_long(m)

 

加密

1
2
c = pow(m, e, n)
print(c)

 => c = me  % n

注意在代码中,不可以使用 直接的算式运算,pow函数可以快速得出结果,但是直接使用算式运算,会产生大量的运算。

此时,c就是密文:加密后的消息

 

解码:

1
msg = pow (c, d, n)

 完整代码:

比较

复制代码
from Crypto.Util.number import *
p = getPrime(512)
q = getPrime(512)

n = p*q
phi = (p-1)*(q-1)
e = 65537
assert GCD(e, phi) == 1, "判断互素"
d = inverse(e, phi)

print(f'公钥:({e}, {n})')
print(f'私钥:({d}, {n})')

message = b'Nineday'
m = bytes_to_long(message)
print('消息:', m)

c = pow(m, e, n)
print('密文:', c)

msg = pow(c, d, n)
print('明文:', msg)

assert msg == m, "是否一样"
复制代码

 

基础解码代码:
复制代码
import gmpy2
from Crypto.Util.number import *

e = 65537
p = 12567387145159119014524309071236701639759988903138784984758783651292440613056150667165602473478042486784826835732833001151645545259394365039352263846276073
q = 12716692565364681652614824033831497167911028027478195947187437474380470205859949692107216740030921664273595734808349540612759651241456765149114895216695451
c = 108691165922055382844520116328228845767222921196922506468663428855093343772017986225285637996980678749662049989519029385165514816621011058462841314243727826941569954125384522233795629521155389745713798246071907492365062512521474965012924607857440577856404307124237116387085337087671914959900909379028727767057

n = p*q
phi = (p-1) * (q-1)   

d = gmpy2.invert(e,phi)  # d ≡ e-1 % n 逆元

m = pow(c,d,n)           # m ≡ cd % n
print(long_to_bytes(m))
复制代码

 


 

 
posted @   Nineday_九日之景  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示