密码学 · 2020年12月24日 0

RSA非对称加密算法demo

一、基础知识:

密钥生成

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 ("谢谢朋友们!")