Python RSA非对称分段加密示例(支持长文本)

1. 条件

  • Python运行环境(博主用的Python3.8+)
  • 需安装Python模块(Windows安装pycryptodome,Linux安装pycrypto
    • pip install pybase64
    • pip install pycryptodome
  • 生成自己的pem格式密钥(Base64
    • Private Key保存至 private.pem
    • Public Key保存至 public.pem

2. 代码

  • 加密

    import Crypto
    from Crypto.Hash import MD5
    from Crypto.PublicKey import RSA
    # 计算签名
    from Crypto.Signature import PKCS1_v1_5
    # 计算加密解密
    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    from base64 import b64decode, b64encode
    
    
    class RsaUtil(object):
    
        def sign_encrypt(self, message, private_key):
            """ RSA私钥加密 MD5withRSA """
            # digest = SHA.new()
            digest = MD5.new()
            digest.update(message.encode(encoding='utf8'))
            private_key = RSA.importKey(b64decode(private_key))
            signer = PKCS1_v1_5.new(private_key)
            sig = b64encode(signer.sign(digest))
            return sig.decode('utf8')
    
        def get_max_length(self, rsa_key, encrypt=True):
            """加密内容过长时 需要分段加密 换算每一段的长度.
                :param rsa_key: 钥匙.
                :param encrypt: 是否是加密.
            """
            blocksize = Crypto.Util.number.size(rsa_key.n) / 8
            reserve_size = 11  # 预留位为11
            if not encrypt:  # 解密时不需要考虑预留位
                reserve_size = 0
            maxlength = blocksize - reserve_size
            return maxlength
    
        def long_rsa_public_encrypt(self, msg, public_key):
            """ 分段使用公钥加密
            单次加密串的长度最大为(key_size / 8 - 11)
            加密的 plaintext 最大长度是 证书key位数 / 8 - 11, 例如1024 bit的证书,被加密的串最长 1024 / 8 - 11=117,
            解决办法是分块加密,然后分块解密就行了,
            因为 证书key固定的情况下,加密出来的串长度是固定的。
            """
            # base64加密后 再进行RSA加密,也可以选择直接进行RSA加密,这个看业务要求
            msg = b64encode(msg.encode('utf-8'))
            
            length = len(msg)
            public_key = RSA.importKey(b64decode(public_key))
            max_length = int(self.get_max_length(public_key))
            pub_obj = Cipher_pkcs1_v1_5.new(public_key)
            # 长度不用分段
            if length < max_length:
                return b64encode(pub_obj.encrypt(msg))
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > max_length:
                    res.append(pub_obj.encrypt(msg[offset:offset + max_length]))
                else:
                    res.append(pub_obj.encrypt(msg[offset:]))
                offset += max_length
            byte_data = b''.join(res)
    
            return b64encode(byte_data)
    
        def long_decrypt_by_private_key(self, msg, private_key):
            """ 使用私钥分段解密 """
            msg = b64decode(msg)
            length = len(msg)
            private_key = RSA.importKey(b64decode(private_key))
            max_length = int(self.get_max_length(private_key, False))
            # 私钥解密
            private_obj = Cipher_pkcs1_v1_5.new(private_key)
            # 长度不用分段
            if length < max_length:
                return b''.join(private_obj.decrypt(msg, b'xyz'))
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > max_length:
                    res.append(private_obj.decrypt(msg[offset:offset + max_length], b'xyz'))
                else:
                    res.append(private_obj.decrypt(msg[offset:], b'xyz'))
                offset += max_length
            # RSA解密后再进行一次base64解密,也可以直接返回,这个看加密的数据有没有base64加密
            de_base_res = b64decode(b''.join(res))
            return de_base_res
    
    
    #Read
    f = open('text/decrypt.txt',encoding="UTF-8")
    decrypt_text = f.read()
    f.close()
    
    #Encrypt
    instance = RsaUtil()                                                                #实例化
    public_key = open('pem/public.pem').read()                                          #获取公钥
    encrypt_text = instance.long_rsa_public_encrypt(decrypt_text, public_key)           #加密
    
    #Write
    f = open('text/encrypt.txt','wb+')
    f.write(encrypt_text)
    f.close()
    
  • 解密

    import Crypto
    from Crypto.Hash import MD5
    from Crypto.PublicKey import RSA
    # 计算签名
    from Crypto.Signature import PKCS1_v1_5
    # 计算加密解密
    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    from base64 import b64decode, b64encode
    
    
    class RsaUtil(object):
    
        def sign_encrypt(self, message, private_key):
            """ RSA私钥加密 MD5withRSA """
            # digest = SHA.new()
            digest = MD5.new()
            digest.update(message.encode(encoding='utf8'))
            private_key = RSA.importKey(b64decode(private_key))
            signer = PKCS1_v1_5.new(private_key)
            sig = b64encode(signer.sign(digest))
            return sig.decode('utf8')
    
        def get_max_length(self, rsa_key, encrypt=True):
            """加密内容过长时 需要分段加密 换算每一段的长度.
                :param rsa_key: 钥匙.
                :param encrypt: 是否是加密.
            """
            blocksize = Crypto.Util.number.size(rsa_key.n) / 8
            reserve_size = 11  # 预留位为11
            if not encrypt:  # 解密时不需要考虑预留位
                reserve_size = 0
            maxlength = blocksize - reserve_size
            return maxlength
    
        def long_rsa_public_encrypt(self, msg, public_key):
            """ 分段使用公钥加密
            单次加密串的长度最大为(key_size / 8 - 11)
            加密的 plaintext 最大长度是 证书key位数 / 8 - 11, 例如1024 bit的证书,被加密的串最长 1024 / 8 - 11=117,
            解决办法是分块加密,然后分块解密就行了,
            因为 证书key固定的情况下,加密出来的串长度是固定的。
            """
            # base64加密后 再进行RSA加密,也可以选择直接进行RSA加密,这个看业务要求
            msg = b64encode(msg.encode('utf-8'))
            
            length = len(msg)
            public_key = RSA.importKey(b64decode(public_key))
            max_length = int(self.get_max_length(public_key))
            pub_obj = Cipher_pkcs1_v1_5.new(public_key)
            # 长度不用分段
            if length < max_length:
                return b64encode(pub_obj.encrypt(msg))
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > max_length:
                    res.append(pub_obj.encrypt(msg[offset:offset + max_length]))
                else:
                    res.append(pub_obj.encrypt(msg[offset:]))
                offset += max_length
            byte_data = b''.join(res)
    
            return b64encode(byte_data)
    
        def long_decrypt_by_private_key(self, msg, private_key):
            """ 使用私钥分段解密 """
            msg = b64decode(msg)
            length = len(msg)
            private_key = RSA.importKey(b64decode(private_key))
            max_length = int(self.get_max_length(private_key, False))
            # 私钥解密
            private_obj = Cipher_pkcs1_v1_5.new(private_key)
            # 长度不用分段
            if length < max_length:
                return b''.join(private_obj.decrypt(msg, b'xyz'))
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > max_length:
                    res.append(private_obj.decrypt(msg[offset:offset + max_length], b'xyz'))
                else:
                    res.append(private_obj.decrypt(msg[offset:], b'xyz'))
                offset += max_length
            # RSA解密后再进行一次base64解密,也可以直接返回,这个看加密的数据有没有base64加密
            de_base_res = b64decode(b''.join(res))
            return de_base_res
    
    
    #Read
    f = open('text/encrypt.txt',encoding="UTF-8")
    encrypt_text = f.read()
    f.close()
    
    #Decrypt
    instance = RsaUtil()                                                                #实例化
    private_key = open('pem/private.pem').read()                                        #获取公钥
    decrypt_text = instance.long_decrypt_by_private_key(encrypt_text, private_key)
    
    #Write
    f = open('text/decrypt.txt','wb+')
    f.write(decrypt_text)
    f.close()
    

3. 演示

  • 加密
    • 未加密文本->加密文本
      Python RSA非对称分段加密示例(支持长文本)_第1张图片
    • 执行加密->生成加密文本
      - 解密
    • 加密文本->未加密文本
      Python RSA非对称分段加密示例(支持长文本)_第2张图片
    • 执行解密->生成解密文本
      Python RSA非对称分段加密示例(支持长文本)_第3张图片

你可能感兴趣的:(Python,python,开发语言)