#python#rsa文本加密


前言

  RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成。

  RSA原理:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥


一、具体算法描述

  具体的算法较为简单,且百度百科描述得很清楚,就不赘述了,直接上链接RSA算法

二、关键实现过程

1.公钥&密钥生成

(1)用筛选法生成素数表

  在学习python的时候老师让我们实现过验证歌德巴赫的猜想,感觉筛选法求素数表是最快的,就把之前写过的代码修改一下搬进来了。
  大概思路就是先假设全是素数,从2到 n \sqrt{n} n 顺序数下去,第一次遇到的数x就是素数,x的倍数都不是素数从素数表里剔除,一直数到比 n \sqrt{n} n 大的最小整数就结束了。

def getprimelist(self, n):
        """生成小于n的素数表"""
        primelist = n * [1]  # 全1矩阵
        primelist[:2] = [0, 0]  # 0和1不是素数
        for i in range(2, int(sqrt(n))):  # 只需要筛选到最大数的平方根即可,比最大数小的合数必然存在比最大数的平方根小的数
            if primelist[i] == 1:  # 确认除数是素数
                for j in range(i * 2, n, i):
                    primelist[j] = 0  # 倍数肯定不是素数
        for i in range(n):
            if primelist[i] == 1:
                self.numList.append(i)

(2)利用素数表生成公钥和密钥

  获得了素数表之后,就可以按步骤生成需要的公钥和密钥了,不过 e e e d d d的生成还需要后面的求模拟元来完成。
具体步骤

  • 1.用随机数生成 p p p q q q
  • 2. n = p q n=pq n=pq
  • 3. ϕ ( n ) = ( p − 1 ) ( q − 1 ) \phi(n)=(p-1)(q-1) ϕ(n)=(p1)(q1)
  • 随机生成 e e e,求 e e e的模拟元 d d d
def create():
        numList = []#生成一个素数表
        n = 100  
        getprimelist(n)#获取n以内的素数
        num1 = len(numList) / 2 - 1#定中位素数位置
        self.n = 0
        while self.n <= 255:
            p = numList[randint(0, int(num1))]
            q = numList[randint(0, int(num1)) + int(len(numList) / 2)]
            n = p * q
        fn = (p - 1) * (q - 1)#欧拉方法计算
        e, d = returnED(fn)

2.模幂算法

  蒙哥马利模乘减少了取模的次数(在大数的条件下)以及简化了除法的复杂度(在2的k次幂的进制下除法仅需要进行左移操作)

  它是RSA 的核心算法,最直接地决定了RSA 算法的性能。

m e ( m o d n ) m^{e}(modn) me(modn)
步骤:

  • (1)把e赋值给u,m赋值给v,w赋值为1;
  • (2)如果u=0,则w的值为的结果;
  • (3)如果u可以被2整除,则 u = u 2 u=\frac{u}{2} u=2u v = v 2 ( m o d n ) v=v^{2}(modn) v=v2(modn)
  • (4) u = u − 1 u = u-1 u=u1 w = w ⋅ v ( m o d n ) w=w·v(modn) w=wv(modn),转(2).

流程图如下

Created with Raphaël 2.2.0 开始 e=u,v=m,w=1 u=0? 输出w 结束 u/2为整数? u=u/2,v=v·v(modn) u=u-1,w=w·v(modn) yes no yes no

模幂算法具体例子如下

1 1 7 11^{7} 117:
7 = 1 + 6 = 1 + 2 ⋅ 3 = 1 + 2 ( 1 + 2 ) = 1 + 2 + 2 2 7=1+6=1+2·3=1+2(1+2)=1+2+2^{2} 7=1+6=1+23=1+2(1+2)=1+2+22
1 1 7 = 11 ⋅ 1 1 6 = 11 ⋅ 1 1 2 ⋅ ( 1 1 2 ) 2 = 11 ⋅ 4 ⋅ 4 2 = 11 ⋅ 4 ⋅ 3 = 2 ( m o d 13 ) 11^{7}=11·11^{6}=11·11^{2}·(11^{2})^{2}=11·4·4^{2}=11·4·3=2(mod13) 117=11116=11112(112)2=11442=1143=2(mod13)

实现源码

#模幂算法
    def powmod(v, u, c):
        """v:底数
        u:指数
        c:模
        """
        w = 1
        while u != 0:
            if u % 2 == 0:
                u = u / 2
                v = (v * v) % c
            u = u - 1
            w = (w * v) % c
        return w

3.求模逆元

    def Euler(e, fn):
        '''
        e为d的系数,fn为k的系数ed=1(modfn)
        '''
        if fn == 0:
            return 1, 0, e
        else:
            x, y, q = Euler(fn, e % fn)
            x, y = y, (x - (e // fn) * y)
        return x, y, q

三、完整源码及运行结果

1.源码

from random import randint
from math import sqrt


class rsa():
    def __init__(self):
        self.create()

    def change(self, p, q, e):
        try:
            assert p * q > 255 and self.isprime(p) and self.isprime(q)  # n应该大于255
            #注:因为一个字符串使转二进制时得到的01串共16位,
            # 一个字符串分割成两个8位的01串,所以m应小于2^8
            self.p = p
            self.q = q
            self.n = p * q
            self.fn = (p - 1) * (q - 1)  # 欧拉函数
            self.e = e
            self.d,tem,tem= self.Euler(e, self.fn)
            return True
        except Exception as e:
            print(e)
            return False

    def create(self):
        self.numList = []
        n = 100  # 100内选素数
        self.getprimelist(n)
        num1 = len(self.numList) / 2 - 1
        self.n = 0
        while self.n <= 255:
            self.p = self.numList[randint(0, int(num1))]
            self.q = self.numList[randint(0, int(num1)) + int(len(self.numList) / 2)]
            self.n = self.p * self.q
        self.fn = (self.p - 1) * (self.q - 1)#欧拉函数
        self.e, self.d = self.returnED(self.fn)
    # 明文字符串转二进制
    def isprime(self,num):
        if  num > 1:
            for i in range(2, int(sqrt(num))+1):
                if num % i == 0:
                    return False
            return True
        else:
            print('变量有误,请输入大于1的整数。')
    def get_p_bin(self, Texts):
        """字符串转二进制
        Text:字符串
        return 字符串对应的二进制的编码
        """
        Text_bin = ''
        for text in Texts:
            s = ord(text)
            s_bin = '{:016b}'.format(s)
            Text_bin = Text_bin + s_bin
        return Text_bin

    # 密文字符串转二进制
    def get_c_bin(self, Texts):
        """字符串转二进制
        Text:字符串
        return 字符串对应的二进制的编码
        """
        Text_bin = ''
        for text in Texts:
            s = ord(text)
            s_bin = '{:08b}'.format(s)
            Text_bin = Text_bin + s_bin
        return Text_bin

    # 二进制转字符函数
    def bin_str(self, s):
        '''获取16位的01串,返回对应的汉字'''
        try:
            return chr(int(s, 2))
        except:
            return -1
    #求最大公约数
    def gcd(self, a, b):
        """求最大公约数"""
        c = a % b
        while c != 0:  # 辗转相除法
            a = b
            b = c
            c = a % b
        # 当余数为0时,循环结束
        return b
    #展示
    def disp(self):
        return self.n, self.e, self.p, self.q, self.d, self.fn
    #获取素数表
    def getprimelist(self, n):
        """生成小于n的素数表"""
        primelist = n * [1]  # 全1矩阵
        primelist[:2] = [0, 0]  # 0和1不是素数
        for i in range(2, int(sqrt(n))):  # 只需要筛选到最大数的平方根即可,比最大数小的合数必然存在比最大数的平方根小的数
            if primelist[i] == 1:  # 确认除数是素数
                for j in range(i * 2, n, i):
                    primelist[j] = 0  # 倍数肯定不是素数
        for i in range(n):
            if primelist[i] == 1:
                self.numList.append(i)
    #欧拉法求模逆元
    def Euler(self, e, fn):
        '''
        e为d的系数,fn为k的系数ed=1(modfn)
        '''
        if fn == 0:
            return 1, 0, e
        else:
            x, y, q = self.Euler(fn, e % fn)
            x, y = y, (x - (e // fn) * y)
        return x, y, q
    #返回公钥e和密钥d
    def returnED(self, fn):
        e = randint(10, fn - 1)
        while self.gcd(e, self.fn) != 1:
            e = randint(10, fn - 1)
        d, x, y = self.Euler(e, fn)
        while d < 0:
            d = d + fn
        # print(f'e,d={e},{d}')
        return e, d
    #模幂算法
    def powmod(self,v, u, c):
        """v:底数
        u:指数
        c:模
        """
        w = 1
        while u != 0:
            if u % 2 == 0:
                u = u / 2
                v = (v * v) % c
            u = u - 1
            w = (w * v) % c
        return w

    #二进制字符串分割函数
    def distribute(self, m):
        """"给二进制字符串分组"""
        mL = []
        mlen = len(m)
        i = 0
        while 8 * (i + 1) <= mlen:
            # print(f'm[{i*8}:{(i+1)*8}]:',m[i*8:(i+1)*8])
            mL.append(int(m[i * 8:(i + 1) * 8], 2))
            i += 1
        return mL
    #加密函数
    def encryption(self, text):
        m = self.get_p_bin(text)  # 明文
        mL = self.distribute(m)#8位为一组
        self.__plaintext = mL
        c = ''
        for m in mL:
            c = c + str(self.powmod(m, self.e, self.n)) + ' '  # 密文,m的e次方幂
        #print("已完成c运算, c=", c)
        self.__ciphertext = c
        return self.__ciphertext
    #解密函数
    def dencryption(self, texts, flag):
        '''flag=0字符串
            flag=2二进制
            flag=10十进制
            flag=16十六进制
        '''
        cL = []
        if flag == 0:
            for text in texts:
                cL.append(int(self.get_c_bin(text),2))
        elif flag == 2:
            texts = list(texts.split(' ')[:-1])
            for text in texts:
                cL.append(int(text, 2))
        elif flag == 10:
            cL = texts.split(' ')[:-1]
        elif flag == 16:
            texts = list(texts.split(' ')[:-1])
            for text in texts:
                cL.append(int(text, 16))
        m = []
        for c in cL:
            m.append(str(self.powmod(int(c), self.d, self.n)))
        #print("已完成m运算, m=", m)
        self.__plaintext = m
        return self.__plaintext

    # 以数字形式展示
    def showc_in_num(self, n):
        ''''n代表进制,目前仅支持2进制和16进制'''
        cstr = ''
        s_hex = ''
        s_bin = ''
        c = self.__ciphertext
        if n == 2:
            for i in c.split(' ')[:-1]:
                s_bin = s_bin + '{:b}'.format(int(i)) + ' '
            return s_bin
        elif n == 16:
            s_hex = ''
            for i in c.split(' ')[:-1]:
                s_hex = s_hex + '{:x}'.format(int(i)) + ' '
            return s_hex
        elif n == 10:
            return c
        else:
            return '请期待后续版本,感谢您的信赖'

    # 明文以文字形式展示
    def show_mtext(self):
        '''明文'''
        M = self.__plaintext
        m_text = ''
        for i in range(len(M)//2):
            mystr = '{:08b}{:08b}'.format(int(M[2*i]),int(M[2*i+1]))
            m_text = m_text+self.bin_str(mystr)
        return m_text
    # 密文以文字形式展示
    def show_ctext(self):
        '''密文'''
        C = self.__ciphertext
        C = C.split(' ')[:-1]
        c_text = ''
        for i in range(len(C)):
            mystr= '{:016b}'.format(int(C[i]))
            c_text = c_text + self.bin_str(mystr)
        return c_text

if __name__ == '__main__':
    R = rsa()
    text = '面朝大海,春暖花开!!'
    R.change(11,47,39)#epqd
    R.encryption(text)
    c = R.show_ctext()
    print('c = ',c)
    R.dencryption(c, 0)
    print('m = ',R.show_mtext())

2.结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值