密码加密解密(六)——RSA公钥密码设计

RSA算法描述如下:
1.公钥
选择两个互异的大素数p和q,n是二者的乘积,即n = pq,使Ф(n)=(p-1)(q-1),Ф(n)为欧拉函数。随机选取正整数e,使其满足gcd(e,Ф(n))=1,即e和Ф(n)互质,则将(n,e)作为公钥。
2.私钥
求出正数d,使其满足e×d=l mod Ф(n),则将(n,d)作为私钥。
3.加密算法
对于明文M,由C=Me mod n,得到密文C。
4.解密算法
对于密文C,由M=Cd mod n,得到明文M。
如果窃密者获得了n、e和密文C,为了破解密文必须计算出私钥d,为此需要先分解n。为了提高破解难度,达到更高的安全性,一般商业应用要求n的长度不小于1024位,更重要的场合不小于2048位

python源代码:

'''
   args = {
        name:RSA加解密
        author:Lsy
        date:2020-11-30
   }
'''

import random
import math


def pow_mod(a, q, n):
    '''
    args={
        幂模运算,快速计算(a^q) mod (n)
        a:底数
        q:指数
        n:模数
        返回结果d
    }
    '''
    d = 1
    while q:
        if q & 1:  # 如果q & 1=1,那么其二进制形式的最后一位等于1
            d = (d * a) % n
        q >>= 1  # 每一轮右移一位,就能得出其二进制每位是0还是1
        a = (a * a) % n
    return d


# 素数检测算法
def MillerRabin(n, a):
    '''
    判断一个数是否是素数,使用Miller-Rabin概率检测法
    n:待检验的数
    a:小于n的数
    如果n暂时测试为素数,则返回true
    '''
    binstr = bin(n - 1)[2:]
    d = 1
    for i in binstr:
        x = d
        d = d * d % n
        if d == 1 and x != 1 and x != n - 1:
            return False
        if i == '1':
            d = d * a % n
    if d != 1:
        return False
    return True


# 获取大素数
def GetBigPrime(num):  # num代表位数
    '''
    args={
        获取大素数
        num:输入十进制的位数
        返回大素数p
    }
    '''
    while 1:
        p = random.randrange(10 ** (num - 1) + 1, 10 ** num, 2)
        for i in range(50):
            for j in range(8):  # 进行8轮Miller-Rabin概率检测法,就能够大概率判断此数为素数
                a = random.randint(2, p)
                if MillerRabin(p, a) == False:
                    break
                elif j == 7:
                    return p
            p = p + 2  # 如果生成的数不是素数,则向后加2依次判断,直至50次后重新生成另一个数
            if p > 10 ** num:
                break


def gcd(a, b):
    '''
    args = {
        欧几里得算法求最大公约数
        返回最大公约数
    }
    '''
    while a != 0:
        a, b = b % a, a
    return b


# 求逆元函数
def GetInverse(a, b):
    '''
    args = {
        求某个数的逆元
        a:需要求逆元的密钥
        a与b大者为模数,另一个为密钥
        y2:返回该秘钥的逆元
    }
    '''
    if a < b:
        a, b = b, a
    x1 = 1
    x2 = 0
    x3 = a
    y1 = 0
    y2 = 1
    y3 = b
    while 1:
        q = x3 // y3
        temp1 = y1
        temp2 = y2
        temp3 = y3
        y1 = x1 - q * temp1
        y2 = x2 - q * temp2
        y3 = x3 - q * temp3
        x1 = temp1
        x2 = temp2
        x3 = temp3
        if y3 == 1:
            break
    if y2 < 0:
        y2 = (y2 + a) % a
    return y2


def GetKey(num):
    '''
    args = {
        生成密钥
        num:生成素数的位数,十进制位数
        返回值:
        p:第一个大素数
        q:第二个大素数
        n:p*q
        -n:欧拉函数值
        e:公钥
        d:私钥
    }
    '''
    p = GetBigPrime(num)
    while 1:
        q = GetBigPrime(num)
        if p != q:
            break
    n = p * q
    _n = (p - 1) * (q - 1)
    while 1:
        e = random.randint(2, _n)  # e的值随机生成
        if gcd(e, _n) == 1:
            break
    # e = 65537
    d = GetInverse(_n, e)
    return p, q, n, _n, e, d


def Encrypt(m, e, n):
    '''
    args = {
        加密函数
        m:需要加密的数字字符串
        e:公钥
        n:公钥
        返回密文,列表形式
    }
    '''
    c = []
    l = math.floor(math.log(n, 10))
    # l = 8
    print("分组长度:" + str(l))
    for i in range(math.ceil(len(m) / l)):
        c.append(str(pow_mod(int(m[i * l:l * (i + 1)].ljust(l, '0')), e, n)))
    return c


def Decrypt(c, d, n):
    '''
    args = {
        解密函数
        c:需要解密的密文,列表形式
        d:私钥
        n:私钥
        返回解密后的数字字符串
    }
    '''
    m = ''
    l = math.floor(math.log(n, 10))
    for cc in c:
        x = str(pow_mod(int(cc), d, n)).zfill(l)
        m += x
    return m


def Change(plaintext):
    '''
    args = {
        将字符串转换成数字字符串
        plaintext:需要转换的字符串
        返回数字字符串
        其中:" ":"00","a":"01","b":"02","c":"03"......"z":"26"
    }
    '''
    m = ''
    plaintext = plaintext.lower()
    for i in plaintext:
        if i == " ":
            m += "00"
        else:
            m += str(ord(i) - 96).zfill(2)
    return m


def InverseChange(m):
    '''
    args = {
        逆置换,将数字字符串转换成字符串
        m:数字字符串
        返回转换后的字符串
    }
    '''
    plaintext = ''
    for i in range(len(m) // 2):
        if m[i * 2:(i + 1) * 2] == "00":
            # plaintext+=" "
            continue
        else:
            plaintext += chr(int(m[i * 2:(i + 1) * 2]) + 96)
    return plaintext


if __name__ == "__main__":
    num = int(input("请输入产生素数的长度:"))
    p, q, n, _n, e, d = GetKey(num)
    print("产生的第一个素数p为:" + str(p))
    print("产生的第二个素数q为:" + str(q))
    print("n=" + str(n))
    print("_n=" + str(_n))
    print("公钥为:(" + str(e) + "," + str(n) + ")")
    print("私钥为:(" + str(d) + "," + str(n) + ")")
    plaintext = input("请输入需要加密的明文:")
    ciphertext = Encrypt(Change(plaintext), e, n)
    print("加密后的密文:" + str(ciphertext))
    cipher = []
    cipher.append(input("请输入需要解密的密文:"))
    plaintext = Decrypt(cipher, d, n)
    print("解密后的明文" + InverseChange(plaintext))
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值