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

简介
最近工作需要对接接口,我记录了实现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,与第一、第二种加解密可以互通

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容