You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生成RSA密钥对后对对象使用copy.deepcopy()出现PicklingError如何解决?

报错原因

PyCryptodome库的RSA密钥对象出于安全考量,直接禁止了pickle序列化操作,而Python标准库的copy.deepcopy深拷贝能力底层依赖pickle实现。你的Transaction类实例中存储了requesterPK、requesterPubkey两个原生RSA密钥对象,执行深拷贝时就会触发RSA类内置的PicklingError抛出。

解决方案

方案1:移除实例中的原生RSA对象(最推荐)

你的代码本身已经完成了公私钥的本地文件导出,完全不需要在实例属性中保存原生RSA对象,仅存储导出后的密钥文件路径或PEM格式字符串即可,需要使用密钥时再通过RSA.importKey()方法导入,从根源避免序列化问题。
修改后可正常运行的代码参考:

from Crypto.PublicKey import RSA
import random
import sys
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
import copy 

class Transaction():
    def __init__(self,
     id=0,requester=0,requester_priv_pem=b'', pubkey_path='', privkey_path='',data=''):
        self.id = id               #the uinque id or the hash of the transaction   
        self.requester = requester     
        self.requester_priv_pem = requester_priv_pem # 存PEM格式的私钥字符串,不要存RSA实例
        self.pubkey_path = pubkey_path
        self.privkey_path = privkey_path
        self.data = data
        self.verified=False
        # 不需要单独存requesterPubkey,需要用的时候从PEM导入再取公钥即可
    @classmethod
    def create_transactions(cls):# Tx sender changes as the Tx propagates while Tx requester stays same        
        Tn = 5
        simTime = 5
        Psize= int(Tn * simTime) # Tx rate times simTime
        for i in range(Psize):
            tx= cls()
            tx.id= random.randrange(100000000000)
            tx.data = f"{tx.id}file.txt"
            file1 = open(tx.data, "w")
            s= str(tx.id)
            file1.write(s)
            file1.close()
            # 生成RSA密钥后直接导出为PEM字符串存到实例,不要存原生RSA对象
            requester_pk = RSA.generate(1024)
            tx.requester_priv_pem = requester_pk.exportKey('PEM')
            tx.privkey_path = f"{tx.id}Privkey.out"
            f = open(tx.privkey_path,"wb")
            f.write(tx.requester_priv_pem)
            f.close()
            requester_pub = requester_pk.publickey()
            tx.pubkey_path = f"{tx.id}Pubkey.out"
            f = open(tx.pubkey_path, "wb")
            f.write(requester_pub.exportKey('OpenSSH'))
            f.close()
            tx.transaction_prop()
    def transaction_prop(self):
        t= copy.deepcopy(self)
        # 后续需要用RSA对象时再导入即可,示例:
        # rsa_obj = RSA.importKey(self.requester_priv_pem)
        # pubkey = rsa_obj.publickey()

Transaction.create_transactions() 

方案2:自定义深拷贝逻辑

如果业务需要必须在实例中保留原生RSA对象,可以重写Transaction类的__deepcopy__方法,手动处理RSA密钥的复制逻辑,绕开默认的pickle流程:

class Transaction():
    # 你的原有__init__、create_transactions等方法保持不变
    def __deepcopy__(self, memo):
        new_tx = Transaction()
        # 先复制所有普通可序列化属性
        for k, v in self.__dict__.items():
            if k not in ['requesterPK', 'requesterPubkey']:
                new_tx.__dict__[k] = copy.deepcopy(v, memo)
        # 手动处理RSA密钥的复制:导出为PEM后再导入生成新的RSA实例
        if hasattr(self, 'requesterPK'):
            priv_pem = self.requesterPK.exportKey('PEM')
            new_tx.requesterPK = RSA.importKey(priv_pem)
        if hasattr(self, 'requesterPubkey'):
            pub_pem = self.requesterPubkey.exportKey('PEM')
            new_tx.requesterPubkey = RSA.importKey(pub_pem)
        memo[id(self)] = new_tx
        return new_tx

添加上述方法后,执行copy.deepcopy时就会走自定义的拷贝逻辑,不会再触发pickle报错。

内容的提问来源于stack exchange,提问作者Riham ELSAADANY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 00:45:03