一、基础知识:
密钥生成:
1、随机选择两个不相等的质数p和q
比如我们选择了61和53。(实际应用中,这两个质数越大,就越难破解。)
2、计算p和q的乘积n
n = 61×53 = 3233
n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12位。实际应用中,RSA密钥一般是1024位,重要场合则为2048位。
3、计算n的欧拉函数φ(n)
φ(n) = (p-1)(q-1)
所以φ(3233)等于60×52,即3120。
4、随机选择整数e,条件是1<e<φ(n),且e与φ(n)互质
所以我们随便在1到3120之间选择了17。(实际常常选择65537)
5、计算e对于φ(n)的模反元素d
所谓”模反元素”就是指有一个整数d,可以使得ed被φ(n)除的余数为1。
ed ≡ 1 (mod φ(n))
这个式子等价于
ed – 1 = kφ(n) (k∈Z)
于是,找到模反元素d,实质上就是对下面这个二元一次方程求解。
ex + φ(n)y = 1
已知 e=17, φ(n)=3120,17x + 3120y = 1
这个方程可以用”扩展欧几里得算法”求解。算出一组整数解为
(x,y)=(2753,-15),即 d=2753。
至此所有计算完成。
6、将n和e封装成公钥,n和d封装成私钥。
n=3233,e=17,d=2753,所以公钥就是 (3233,17),私钥就是(3233, 2753)。
7、总结一下
pq的作用用于求n==pq,再用 (p-1)(q-1)求φ(n),在φ(n)范围内随机选择即为e,d==e对于φ(n)的模反元素
二、python实现
生成密钥module:
'''公钥私钥生成模块'''
## by EotStxTaB
## 20.11.20
import random
# 辗转相除法求最大公因数
def gcd(a, b):
if a > b:
a, b = b, a
while b != 0:
a, b = b, a%b
return a
# 判断一个数是否为素数
def isPrime(n):
if n <= 1:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
def fast_mod(b, n, m):
ret = 1
tmp = b
while n:
if n & 0x1:
ret = ret * tmp % m
tmp = tmp * tmp % m
n >>= 1
return ret
# 随机生成素数
def random_prime(half_len):
while True:
n = random.randint(0, 1 << half_len)#求2^half_len之间的大数
if n % 2 != 0:
found = True
# 随机性测试
for i in range(0, 5): #安全阈值为5的时候错误率小于千分之一
if prime_test(n) == False:
found = False
break
if found == True:
return n
# Miller-Rabin素性检测算法
def prime_test(n):
q = n - 1
k = 0
# 寻找k,q 是否满足2^k*q =n - 1
while q % 2 == 0:
k += 1
q = q // 2
a = random.randint(2, n - 2)
# 如果 a^q mod n= 1, n 可能是一个素数
if fast_mod(a, q, n) == 1:
return True
# 如果存在j满足 a ^ ((2 ^ j) * q) mod n == n-1, n 可能是一个素数
for j in range(0, k):
if fast_mod(a, (2 ** j) * q, n) == n - 1:
return True
# n 不是素数
return False
def create_k(key_len): # key_len要比消息长度大
p = random_prime(key_len // 2)
q = random_prime(key_len // 2)
n = p * q
phi_n = (p - 1)*(q - 1) # 计算n的欧拉函数
print("欧拉后的phi_N:"+str(phi_n))
# 事先设定好公钥 E<phi且互素
E = 65537
D = create_D(phi_n, E)
return (n,E,D)
# 迭代实现扩展欧几里得算法
def ext_gcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_gcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
# 生成私钥D
def create_D(phi_n, E):
(x, y, r) = ext_gcd(phi_n, E)
# y有可能是负数
if y < 0:
# return y % phi_n
return y + phi_n
return y
加密与解密(可以分离,我就是随便演示一下)
'''加密'''
## by EotStxTaB
## 20.11.20
import Create_Key as ck
import math
import random
if __name__ == '__main__':
M = input("输入明文M:")
M_int = int(M)
mess_num_length = len(M)
(n, e, d) = ck.create_k(mess_num_length*15)
print ("欧拉前的N:"+str(n))
print ("公钥E为:"+str(e))
print ("私钥D为:"+str(d))
cipher = ck.fast_mod(M_int,e,n) #生成密文C a^b%c=n
print ("加密后的密文cipher:"+str(cipher))
print ("-----------------------------------------------------------------")
New_M = ck.fast_mod(cipher, d, n)
print ("解密后的明文:"+str(New_M))
print ("-----------------------------------------------------------------")
print ("谢谢朋友们!")