生成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
相关产品推荐
相关产品推荐

