RSA算法
RSA是一种非对称加密算法,假如甲要和乙通讯,甲使用公钥 A 加密,将密文传递给乙,乙使用私钥 B 解密得到明文,其中公钥是在网络上进行传递的,私钥只有乙自己拥有,不在网络上传递,这样即使知道了公钥 A 也无法解密传输的信息
RSA算法原理和python代码实现
1.生成公私钥
1.1给定两个质数P,Q
这里的P,Q越大,该算法就会越安全,为了方便描述,这里给定P=67,Q=71,那么他们的乘积n=4757
1.2计算n的欧拉函数φ(n)
根据欧拉函数的定义,φ(n)等于所有小于等于n的正整数中与n互质的个数,又因为P*Q=n,且PQ均为素数,所以φ(n) =(P-1)(Q-1)= 66 * 70 = 4620
1.3随机选择一个整数e(1<e<m) and e与m互质
这里随机选取e=101,注意,当e=m时会导致公私钥相同
1.4给定整数d,使得(e*d)%m=1
因为 (e*d)%m=1
所以 e*d-m*y=1(y为整数),由上述可知 e = 101,m = 4620
所以 101d-4620y=1
根据相关定理(d,y)=1=101d-4620y
根据扩展欧几里得算法:
4620=101x4+75
101=75x1+26
75=26x2+23
23=3x7+1
3=2x1+1
---->
101x1601-35x4620
得到d等于1601
计算完成后,得到公钥 (n,e)=(4757,101) ,私钥 (n,d)=(4757,1601),根据RSA算法的效果,除了接收方自己,没有人知到私钥,那么通过公钥能否得到私钥呢
已知(e*d)%m=1,已知n,e,那么要求d只需要求出n
而我们知道m是n的欧拉函数φ(n),想要知道m就必须将n分解成两个质数的乘积
这里由于数比较小,我们很容易分解出PQ的值,而随着n的增大,分解会变得异常困难
2.加密生成密文
假设需要加密的数字时a
那么将a转化成int就是97
计算过程如下:
97^101%4757=3589
3.解密密文
根据公式
a^d % n = b
就可以得出明文
python代码实现
由于C语言不支持大数,所以使用C语言实现异常麻烦这里采用python代码
# -*- coding: cp936 -*-
def isPrime(number):
import math
i = 2
sqrtnum = (int)(math.sqrt(number))
for i in range(2, sqrtnum + 1):
if number % i == 0:
return False
i = i + 1
return True
def is_ET_Prime(ee, tt):
while tt != 0:
a = ee
ee = tt
tt = a % tt
if ee == 1:
return True
else:
return False
def get_publickey(k, t):
d = 0
while ((d * k) % t != 1):
d += 1
return d
def encryption(plain, d, n):
re = (plain ** d) % n
return re
if __name__ == "__main__":
print
"~" * 70
Flag = False
while True:
p = int(input("please input a prime p:"))
q = int(input("please input a prime q:"))
if (isPrime(p) and isPrime(q)):
break
else:
print
"p or q is not prime!"
continue
print
"p=", p, "q=", q
n = q * p
t = (q - 1) * (p - 1)
print("n=", n, "t=", t)
print("~" * 70)
Flag == False
while Flag == False:
e = int(input("please input a private key:"))
Flag = is_ET_Prime(e, t)
if Flag == False:
print("e is not prime with the t!")
print("the private key e=", e)
d = get_publickey(e, t)
print("the public key d=", d)
plain = int(ord(input("please input the plain you want to entrypted:")))
encry = encryption(plain, d, n)
print("plain", plain, "is encrypted as", encry)
#print(encry)
plain1 = encryption(encry, e, n)
print("encrypt", encry, "is decrypted as", plain1)
RSA共模攻击
假设有一条信息m,由两个不同的用户使用公钥进行加密(两个用户的e一般不同,模数n一般相同)
c1 = m^e1 mod n
c2 = m^e2 mod n
得到了两个不同的密文c1,c2
共模攻击这得到了这两个密文c1,c2,因为公钥是公开的(e1,e2,n)已知
那么攻击者一共知道如下信息
gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n
那么根据上述就可以直接求出明文m,由于gcd(e1,e2)
那么存在整数s1,s2使得e1*s1+e2*s2=1
,又因为
c1=m^e1 mod n
c2=m^e2 mod n
所以:
c1^s1 mod n=m^(e1*s1) mod n
c2^s2 mod n=m^(e2*s2) mod n
c1^s1*c2^s2 mod n=m^(e1*s1+e2*s2) mod n
又因为e1*s1+e2*s2=1
所以
c1^s1*c2^s2 =m mod n
再由扩展欧几里得算法和e1*s1+e2*s2=1,即可求出s1,s2
代码模板:
from libnum import n2s,s2n
from gmpy2 import invert
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def main():
n = int(input("请输入一个十六进制数n"),16)
c1 = int(input("请输入一个十六进制数c1"),16)
c2 = int(input("请输入一个十六进制数c2"),16)
e1 = int(input("请输入一个十六进制数e1"),16)
e2 = int(input("请输入一个十六进制数e2"),16)
s = egcd(e1, e2)
s1 = s[1]
s2 = s[2]
# 求模反元素
if s1<0:
s1 = - s1
c1 = invert(c1, n)
elif s2<0:
s2 = - s2
c2 = invert(c2, n)
m = pow(c1,s1,n)*pow(c2,s2,n) % n
print n2s(m)
if __name__ == '__main__':
main()