美文网首页Debian 12 折腾
Python实现RSA加解密的三种方式

Python实现RSA加解密的三种方式

作者: 空山晚来秋 | 来源:发表于2023-12-23 15:16 被阅读0次

    简介
    最近工作需要对接接口,我记录了实现RSA加解密的3种不同方式,希望给有需要的人带来帮助

    使用的Python版本为3.10.13

    第一种:RSA包

    需要安装RSA包

    pip install rsa
    

    具体代码如下

    # rsa==4.9
    import json
    import base64
    import rsa
    
    # `RsaRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
    class RsaRsaUtil:
        def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
            """
            公钥私钥为不带开头的文本
            这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
            :param rsa_publicKey: rsa_publicKey
            :param rsa_privateKey: rsa_privateKey
            """
            self.public_key = rsa.PublicKey.load_pkcs1(rsa_publicKey)
            self.private_key = rsa.PrivateKey.load_pkcs1(rsa_privateKey)
        def decrypt(self, data: str) -> str:
            """
            “解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要解密的数据。
            :type data: str
            :return: “解密”函数返回一个解密的字符串。
            """
            if isinstance(data, str):
                data = data.encode('utf-8')
                data = base64.b64decode(data)
            # default_length = 128
            default_length = 256  #1024bit的证书用128,2048bit证书用256位
            length = len(data)
            # print(length)
            if len(data) < default_length:
                res_data = rsa.decrypt(data, self.private_key)
                return str(res_data, encoding='utf8')
            else:
                # 文本太长,需要分段解密
                offset = 0
                res = []
                while length - offset > 0:
                    if length - offset > default_length:
                        res.append(rsa.decrypt(data[offset:offset + default_length], self.private_key))
                    else:
                        res.append(rsa.decrypt(data[offset:], self.private_key))
                    offset += default_length
                res_data = b''.join(res)
                return str(res_data, encoding='utf8')
        
        def encrypt(self, data: str) -> str:
            """
            “加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要加密的数据。
            :type data: str
            :return: “加密”函数返回一个解密的字符串。
            """
            if isinstance(data, str):
                data = data.encode('utf-8')
            length = len(data)
            default_length = 117
            if length < default_length:
                res_data = rsa.encrypt(data, self.public_key)
                return str(base64.b64encode(res_data), encoding='utf8')
            # 需要分段加密
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > default_length:
                    res.append(rsa.encrypt(data[offset:offset + default_length], self.public_key))
                else:
                    res.append(rsa.encrypt(data[offset:], self.public_key))
                offset += default_length
            res_data = b''.join(res)
            return str(base64.b64encode(res_data), encoding='utf8')
    
    
        def sign(self, data: str) -> str:
            """
            “签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要签名的数据。
            :type data: str
            :return: “签名”函数返回一个签名的字符串。
            """
            data = data.encode('utf-8')
            signature = rsa.sign(data, self.private_key, 'SHA-256')
            return str(base64.b64encode(signature), encoding='utf8')
        
        def verify(self, data: str, sign: str) -> bool:
            """
            验签
            """
            if isinstance(data, str):
                data = data.encode('utf-8')
                # data = base64.b64decode(data)
            if isinstance(sign, str):
                sign = sign.encode('utf-8')
                sign = base64.b64decode(sign)
            try:
                rsa.verify(data, sign, self.public_key)
                print('The signature is valid.')
                return True
            except (ValueError,TypeError):
                print('The signature is invalid.')
                return False
    
    if __name__ == '__main__':
        # 生成新的rsa秘钥对
        # (public_key, private_key) = rsa.newkeys(1024)
        # public_key = public_key.save_pkcs1().decode('utf-8')
        # private_key = private_key.save_pkcs1().decode('utf-8')
    
        # 使用现有秘钥对
        with open('public_key.pem', 'r') as f:
            public_key = f.read()
    
        with open('private_key.pem', 'r') as f:
            private_key = f.read()
        rsaUtil = RsaRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
        
        msg = {  
            "key1": "This is a random string that contains random characters and numbers.",  
            "key2": "Another random string with more random characters and numbers.",  
            "key3": "Here is another random string that may contain special characters and spaces.",  
            "key4": "This string is longer and contains more random characters and numbers.",  
            "key5": "A random string with some special characters and spaces.",  
            "key6": "This is a random string that may contain special characters and spaces.",  
            "key7": "Here is another random string that may contain more special characters and spaces.",  
            "key8": "This string is longer and contains more random characters and numbers.",  
            "key9": "A random string with some special characters and spaces.",  
            "key10": "This is a very long random string that may contain more special characters and spaces."  
        }
        data = json.dumps(msg)
        data = "xxxxxxxxeerererre"
        # 加密
        data_encrypt = rsaUtil.encrypt(data)
        print(data_encrypt)
        # # 解密
        data_decrypt = rsaUtil.decrypt(data_encrypt)
        print(data_decrypt)
    
        # 加签名
        signature = rsaUtil.sign(data)
        print(signature)
        # 验签
        print(rsaUtil.verify(data, signature))
    

    第二种:pycryptodome

    许安装pycryptodome包

    pip install pycryptodome==3.19.0
    

    代码如下

    # pycryptodome==3.19.0
    import json
    import base64
    from Crypto.Hash import SHA256
    from Crypto.PublicKey import RSA
    from Crypto.Signature import PKCS1_v1_5
    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    
    
    # `CryptoRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
    class CryptoRsaUtil:
        def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
            """
            公钥私钥为不带开头的文本
            这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
            :param rsa_publicKey: rsa_publicKey
            :param rsa_privateKey: rsa_privateKey
            """
            self.public_key = RSA.importKey(rsa_publicKey)
            self.private_key = RSA.importKey(rsa_privateKey)
    
        def decrypt(self, data: str) -> str:
            """
            “解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要解密的数据。
            :type data: str
            :return: “解密”函数返回一个解密的字符串。
            """
            data = base64.b64decode(data)
            length = len(data)
            print(length)
            # default_length = 128
            default_length = 256  #1024bit的证书用128,2048bit证书用256位
            # 私钥解密
            priobj = Cipher_pkcs1_v1_5.new(self.private_key)
            # 长度不用分段
            if length < default_length:
                return b''.join(priobj.decrypt(data, b' '))
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > default_length:
                    res.append(priobj.decrypt(data[offset:offset + default_length], b' '))
                else:
                    res.append(priobj.decrypt(data[offset:], b' '))
                offset += default_length
            res_data = b''.join(res)
            return str(res_data, encoding='utf8')
        
        def encrypt(self, data: str) -> str:
            """
            “加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要加密的数据。
            :type data: str
            :return: “加密”函数返回一个解密的字符串。
            """
            length = len(data)
            #单次加密串的长度最大为 (key_size/8)-11,1024bit的证书用100, 2048bit的证书用 200
            default_length = 117
            # default_length = 100
            # 公钥加密
            pubobj = Cipher_pkcs1_v1_5.new(self.public_key)
            # 长度不用分段
            if length < default_length:
                return str(base64.b64encode(pubobj.encrypt(data.encode('utf-8'))), encoding='utf8')
            # 需要分段
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > default_length:
                    res.append(pubobj.encrypt(data[offset:offset + default_length].encode('utf-8')))
                else:
                    res.append(pubobj.encrypt(data[offset:].encode('utf-8')))
                offset += default_length
            byte_data = b''.join(res)
    
            return str(base64.b64encode(byte_data), encoding='utf8')
        
    
        def sign(self, data: str) -> str:
            """
            “签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要签名的数据。
            :type data: str
            :return: “签名”函数返回一个签名的字符串。
            """
            data = data.encode('utf-8')
            hash_obj = SHA256.new(data)
            signer = PKCS1_v1_5.new(self.private_key)
            signature = signer.sign(hash_obj)
            return str(base64.b64encode(signature), encoding='utf8')
        
        def verify(self, data: str, sign: str) -> bool:
            if isinstance(data, str):
                data = data.encode('utf-8')
            if isinstance(sign, str):
                sign = sign.encode('utf-8')
            #data做“哈希”处理,RSA签名这么要求的
            hash_obj = SHA256.new(data)
            try:
                #因为签名被base64编码,所以这里先解码,再验签
                PKCS1_v1_5.new(self.public_key).verify(hash_obj,base64.b64decode(sign))
                print('The signature is valid.')
                return True
            except (ValueError,TypeError):
                print('The signature is invalid.')
                return False
    
    if __name__ == '__main__':
        x = RSA.generate(2048)
    
        private_key = str(x.export_key(), encoding = "utf-8")   #私钥
        public_key = str(x.publickey().export_key(), encoding = "utf-8")   #公钥
        rsa = CryptoRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
        
        msg = {  
            "key1": "This is a random string that contains random characters and numbers.",  
            "key2": "Another random string with more random characters and numbers.",  
            "key3": "Here is another random string that may contain special characters and spaces.",  
            "key4": "This string is longer and contains more random characters and numbers.",  
            "key5": "A random string with some special characters and spaces.",  
            "key6": "This is a random string that may contain special characters and spaces.",  
            "key7": "Here is another random string that may contain more special characters and spaces.",  
            "key8": "This string is longer and contains more random characters and numbers.",  
            "key9": "A random string with some special characters and spaces.",  
            "key10": "This is a very long random string that may contain more special characters and spaces."  
        }
        data = json.dumps(msg)
        # 加密
        data_encrypt = rsa.encrypt(data)
        print(data_encrypt)
        # 解密
        data_decrypt = rsa.decrypt(data_encrypt)
        print(data_decrypt)
    
        # 加签名
        signature = rsa.sign(data)
        print(signature)
        # 验签
        print(rsa.verify(data, signature))
    

    第三种:cryptography

    需安装cryptography包

    pip install cryptography==41.0.7
    

    代码如下

    # cryptography==41.0.7
    import json
    import base64
    from cryptography.hazmat.primitives import serialization, hashes
    from cryptography.hazmat.primitives.asymmetric import padding, rsa
    
    
    # `CryptographyRsaUtil` 类提供使用 RSA 加密来加密、解密、签名和验证数据的方法。
    class CryptographyRsaUtil:
        def __init__(self, rsa_publicKey: str = None, rsa_privateKey: str = None):
            """
            公钥私钥为不带开头的文本
            这里公钥与私钥是对方给的,不是同一对秘钥(也可以是同一对)
            :param rsa_publicKey: rsa_publicKey
            :param rsa_privateKey: rsa_privateKey
            """
            self.public_key = serialization.load_pem_public_key(rsa_publicKey.encode())
            self.private_key = serialization.load_pem_private_key(rsa_privateKey.encode(), password=None)
    
        def decrypt(self, data: str) -> str:
            """
            “解密”函数接收字符串“data”,使用公钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要解密的数据。
            :type data: str
            :return: “解密”函数返回一个解密的字符串。
            """
            if isinstance(data, str):
                data = data.encode()
            res_data = self.private_key.decrypt(
                base64.b64decode(data), 
                padding=padding.PKCS1v15()
                )
            return str(res_data, encoding='utf8')
        
        def encrypt(self, data: str) -> str:
            """
            “加密”函数接收字符串“data”,使用私钥对其进行解密,并将解密后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要加密的数据。
            :type data: str
            :return: “加密”函数返回一个解密的字符串。
            """
            if isinstance(data, str):
                data = data.encode()
            res_data = self.public_key.encrypt(
                data, 
                padding=padding.PKCS1v15()
                )
            return str(base64.b64encode(res_data), encoding='utf8')
        
    
        def sign(self, data: str) -> str:
            """
            “签名”函数接收字符串“data”,使用私钥对其进行签名,并将签名后的数据作为字符串返回。
            
            :param data: “data”参数是一个字符串,表示要签名的数据。
            :type data: str
            :return: “签名”函数返回一个签名的字符串。
            """
            signature = self.private_key.sign(
                data.encode(), 
                padding.PKCS1v15(),
                hashes.SHA256()
                )
            return str(base64.b64encode(signature), encoding='utf8')
        
        def verify(self, data: str, sign: str) -> bool:
            if isinstance(data, str):
                data = data.encode('utf-8')
            if isinstance(sign, str):
                sign = sign.encode('utf-8')
            bysign = base64.b64decode(sign) 
            try:
                #因为签名被base64编码,所以这里先解码,再验签
                self.public_key.verify(
                    bysign, 
                    data, 
                    padding.PKCS1v15(),
                    hashes.SHA256())
                print('The signature is valid.')
                return True
            except (ValueError,TypeError):
                print('The signature is invalid.')
                return False
    
    if __name__ == '__main__':
        # 生成公钥私钥
        # 长的字符串需要长的秘钥才能加密
        private_key_obj = rsa.generate_private_key(
            public_exponent=65537, 
            key_size=2048*3
            )
        public_key_obj = private_key_obj.public_key()
    
        public_key = public_key_obj.public_bytes(
            encoding=serialization.Encoding.PEM, 
            format=serialization.PublicFormat.SubjectPublicKeyInfo
            )
        private_key = private_key_obj.private_bytes(
            encoding=serialization.Encoding.PEM, 
            format=serialization.PrivateFormat.PKCS8, 
            encryption_algorithm=serialization.NoEncryption()
            )
        # print(public_key)
        # print(private_key)
        public_key = public_key.decode('utf-8')
        private_key = private_key.decode('utf-8')
        rsaUtil = CryptographyRsaUtil(rsa_publicKey=public_key, rsa_privateKey=private_key)
        
        msg = {  
            "key1": "This is a random string that contains random characters and numbers.",  
            "key2": "Another random string with more random characters and numbers.",  
            "key3": "Here is another random string that may contain special characters and spaces.",  
            "key4": "This string is longer and contains more random characters and numbers.",  
            "key5": "A random string with some special characters and spaces.",  
            "key6": "This is a random string that may contain special characters and spaces.",  
            "key7": "Here is another random string that may contain more special characters and spaces.",  
            "key8": "This string is longer and contains more random characters and numbers.",  
            "key9": "A random string with some special characters and spaces.",  
            "key10": "This is a very long random string that may contain more special characters and spaces."  
        }
        data = json.dumps(msg)
        # data = "b0989a5c4b93b02957973a9dc41e032e"
        # 加密
        data_encrypt = rsaUtil.encrypt(data)
        print(data_encrypt)
        # 解密
        data_decrypt = rsaUtil.decrypt(data_encrypt)
        print(data_decrypt)
    
        # # 加签名
        signature = rsaUtil.sign(data)
        print(signature)
        # # 验签
        print(rsaUtil.verify(data, signature))
    

    📌注意:cryptography包需要更长的秘钥去加密更长的密文。
    若用同一套秘钥,且填充方式为PKCS1v15,与第一、第二种加解密可以互通

    相关文章

      网友评论

        本文标题:Python实现RSA加解密的三种方式

        本文链接:https://www.haomeiwen.com/subject/qgqcndtx.html