栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

RSA加密算法简单介绍以及python实现

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

RSA加密算法简单介绍以及python实现

RSA加密算法简单介绍

注:本篇文章只是本人在学完RSA密码之后的个人总结,若有不正确的地方,欢迎指正OVO

RSA是一种公钥加密算法,它具有公钥和私钥两种密钥:公钥用来加密,并且是公开的,私钥是用来解密的,是不公开的,也不需要和数据一起传送,这样就能防止密钥在网络传输时泄露。

RSA算法设计的原理是依靠着模幂运算,例如加密、解密以及密钥的产生。

1.密钥设计

首先,我们需要了解密钥设计的思想:
①加密计算:c = m^e mod n;
②解密计算:m = c^d mod n;
其中m为明文, c为密文,e为公钥,d为私钥,n为一个我们要产生的大数。

所以,根据以上两个式子有:
dk( ek(m) ) = m
= (m^e mod n) ^d mod n        # 这里也就是先加密再解密
= m^(ed) mod n
那么要实现解密生成的数据和明文一样,**m^(e
d) mod n一定要等于m。①**

m^φ(n) mod n = 1 → m ^(tφ(n)) mod n = 1 → m ^(tφ(n)+1) mod n = m ②
∴① ②中两个式子相对应,即有:ed = (t*φ(n)+1) → ed = 1 mod φ(n)。
不难看出,公钥e和私钥d是关于φ(n)互逆的。

到这里,可能会有疑问,为什么别人不能根据公钥e和 φ(n)来直接求得私钥呢?,这就是接下来要讲的:如何生成n使别人难以计算φ(n)。

2.大数n的生成

首先,我们需要知道一个定理:若n = p*q, 且p,q为素数,那么φ(n) =φ(p) * φ(q) = (p-1) * (q-1)
而且我们知道,想要分解一个大的数是非常困难的,所以我们需要找两个大数p,q,来使生成的n难以被分解计算,而且我们需要p,q都是素数,才能满足上述定理,所以我们问题就变成了如何产生大素数p,q。

3.产生大素数p,q

我们思路可以是这样:要产生大素数,我们可以先用随机数产生一个大数,然后再判断其是否为素数就行。
产生大数简单,random库可以实现,那么如何验证其是否为素数呢?这里我们不能使用简单的素数判别法:如遍历比它小的所有数,并且对其取余,看是否为0。因为这样只适用于小数,对于大数来说,计算时间太长了,根本行不通。所以这里我们需要采用一种素数检测法:Miller-Rabin算法

Miller-Rabin算法思想:
首先,由费马小定理:a^p-1 = 1 mod p (p为素数),我们可以将p-1写成2 ^k*m形式,其中,a我们可随机生成,但需满足1<=a<=n-1。
那么a ^p-1 = ((a ^m) ^2) ^2 … ,所以我们可以先验算a ^m mod p的结果是否为±1,
若是,那么a ^p-1 = ((a ^m) ^2) ^2 … 一定为1,那么可以判断出p为素数;
若不是,令b=a^ m mod p的结果,然后依次计算b, b^ 2,b^ 4,…,b^ 2^(k-1) mod n,若发现有一个为±1,则p是素数,否则,p为合数。

但是,这种算法并不是100%正确,有时候也会将合数当成素数输出,所以一般情况下,我们可以产生伪随机数来进行素数检测,而不是使用随机数来检测。

Miller-Rabin算法具体代码如下:

#判断是否为素数(Miller-Rabbin),RoundTime表示循环测试的次数,提高准确率
def IsPrime(BigNum, RoundTime):
    temp = BigNum - 1
    k = 0
    while (temp & 0x1)==0 and temp:
        temp = temp >>1
        k = k+1
    m = temp

    while RoundTime:
        a = random.randint(1, BigNum- 2)
        b =  repeatMod(a, m, BigNum)
        if b == 1 or b==BigNum-1:
            return True

        for i in range(1,k):
            b = repeatMod(b, 2, BigNum) #若b^2^(k-1) mod n ==+-1,则是一个素数
            if b == 1 or b==BigNum-1:
                return True

        RoundTime = RoundTime -1
    return False
4.密钥生成

我们生成两个大素数p,q后,我们就可以直接得到φ(n)。对于公钥e,我们可以随机生成,但需要满足gcd(e,φ(n))=1(可以使用欧几里得除法来判断余数是否为1)。

然后对于私钥d,因为ed = 1 mod φ(n)所以我们只需要求逆元就能得到d,然而求逆元可以根据欧几里得除法逆过程来求得。欧几里得除法求逆代码如下:

 #求x,y为两个所求逆元,其中y为私钥
def get_(a, b):
	if b == 0:
		return 1, 0
	else:
		k = a // b		
		x1, y1 = get_(b, a % b)
		x, y = y1, (x1 - k * y1)
	return x,y
5.加解密

加解密过程我们只需根据:
①加密计算:c = m^e mod n;
②解密计算:m = c^d mod n; 来计算就行。

但是,对于大数的计算,我们不能直接使用高级语言所给定的计算来求,这样也会导致时间太长,我们在这需要使用平方-乘算法来求。该算法具体代码如下:

#平方乘算法求余数 base^n mod mod
def repeatMod(base, n, mod):
    a = 1
    while n:
        if n&1:
            a = (a*base)%mod
        base = (base*base)%mod
        n = n>>1
    return a
全部代码
#coding=gbk
import math
import random

#平方乘算法求余数 base^n mod mod
def repeatMod(base, n, mod):
    a = 1
    while n:
        if n&1:
            a = (a*base)%mod
        base = (base*base)%mod
        n = n>>1
    return a

#判断是否为素数(Miller-Rabbin)
def IsPrime(BigNum, RoundTime):
    temp = BigNum - 1
    k = 0
    while (temp & 0x1)==0 and temp:
        temp = temp >>1
        k = k+1

    m = temp

    while RoundTime:
        a = random.randint(1, BigNum- 2)
        b =  repeatMod(a, m, BigNum)

        if b == 1 or b==BigNum-1:
            return True

        for i in range(1,k):
            b = repeatMod(b, 2, BigNum) #若b^2^(k-1) mod n ==+-1,则是一个素数
            if b == 1 or b==BigNum-1:
                return True

        RoundTime = RoundTime -1

    return False

#生成大素数
def BuildBigPrime():
    flag = False
    while not flag:
        BigNum = random.randint(2**512,2**513)
        if BigNum % 2 !=0 :
            flag = IsPrime(BigNum, 10)

    return BigNum

#辗转相除求最大公约数
def MaxCommDivisor(m,n):
    if n == 1:
        return True
    if m % n == 0:
      return False
    else:
        flag = MaxCommDivisor(n, m%n)
    return flag
 
 #求 b mod a b的逆元 
def get_(a, b):
	if b == 0:
		return 1, 0
	else:
		k = a // b		
		x1, y1 = get_(b, a % b)
		x, y = y1, (x1 - k * y1)
	return x,y

if __name__ == '__main__':
    print("正在生成大素数------")
    p = BuildBigPrime()
    q = BuildBigPrime()
    while p==q:
        q = BuildBigPrime()

    print("大素数p:",p,"n大素数q:",q)
    n = p*q
    fn = (p-1)*(q-1)

    while True:
        key1 = random.randint(2**64,2**65)
        if  MaxCommDivisor(fn, key1):
            break
    
    print("密钥1为:",key1)
    k, key2 = get_(fn,key1)
    #生成的私钥key2可能为负数,我们需要mod fn来保证其为正数
    if key2<0: 
        key2 = key2 % fn

    print("密钥2为:",key2)

    m = input("请输入明文:")
    m = int(m.encode('utf-8').hex(),16)

    print('n------加密中----')
    c = repeatMod(m,key1,n)
    print("明文为:",m,"n密文为:",c)

    print('n------解密中----')
    m = repeatMod(c,key2,n)
    print("密文为:",c,"n明文为:",m)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/308335.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号