如何发送RSA加密的encrypted_data.bin文件?混合加密后是否需签名存储?
RSA+AES混合加密:要不要给每条消息签名?
嘿,我来帮你理清楚这个问题——非常建议你给每条发送的消息加上签名,下面给你拆解原因和具体的实现方式:
为什么需要签名?
你当前的RSA+AES混合加密方案已经解决了机密性问题(只有拥有对应私钥的接收方能解密消息),但它没法保证两点:
- 完整性:接收方无法确认消息在传输过程中有没有被篡改;
- 不可否认性:接收方没法证明这条消息确实是你发送的,存在被伪造的风险。
而数字签名正好能补上这两个漏洞——它相当于你的“数字公章”,接收方用你的公钥就能验证消息的真实性和完整性。
具体实现思路
- 签名对象:建议对**整个加密数据包(加密后的AES密钥 + nonce + tag + 密文)**进行签名,这样能直接关联所有传输的核心内容,避免单独对明文签名可能出现的漏洞;
- 签名存储:把签名和其他加密数据一起写入
encrypted_data.bin文件。为了后续能正确拆分各部分内容,建议在写入每个数据段前先写入它的长度(用固定字节数存储,比如4字节大端格式)。
代码补充示例(基于PyCryptodome)
加密端代码(新增签名逻辑)
from Crypto.PublicKey import RSA from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.Signature import pkcs1_15 # 也可以用更安全的PSS方案 from Crypto.Hash import SHA256 from Crypto.Random import get_random_bytes # 加载RSA密钥对(假设你已经生成好私钥private.pem和公钥public.pem) private_key = RSA.import_key(open("private.pem").read()) public_key = RSA.import_key(open("public.pem").read()) # 待传输的明文消息 message = b"这是需要保密的敏感数据内容" # --- 原有AES+RSA加密逻辑 --- # 生成随机AES密钥(这里用AES-128,密钥长度16字节) aes_key = get_random_bytes(16) # AES-GCM模式加密 cipher_aes = AES.new(aes_key, AES.MODE_GCM) ciphertext, tag = cipher_aes.encrypt_and_digest(message) nonce = cipher_aes.nonce # RSA加密AES密钥,让只有接收方能解密拿到AES密钥 cipher_rsa = PKCS1_OAEP.new(public_key) encrypted_aes_key = cipher_rsa.encrypt(aes_key) # --- 新增:生成数字签名 --- # 把所有需要验证的内容拼接起来 data_to_sign = encrypted_aes_key + nonce + tag + ciphertext # 生成SHA256哈希 hash_obj = SHA256.new(data_to_sign) # 用私钥签名 signature = pkcs1_15.new(private_key).sign(hash_obj) # --- 写入文件:按「长度+内容」的顺序存储 --- with open("encrypted_data.bin", "wb") as f: # 写入签名长度和签名 f.write(len(signature).to_bytes(4, byteorder='big')) f.write(signature) # 写入加密后的AES密钥长度和密钥 f.write(len(encrypted_aes_key).to_bytes(4, byteorder='big')) f.write(encrypted_aes_key) # 写入nonce长度和nonce f.write(len(nonce).to_bytes(4, byteorder='big')) f.write(nonce) # 写入tag长度和tag f.write(len(tag).to_bytes(4, byteorder='big')) f.write(tag) # 写入密文长度和密文 f.write(len(ciphertext).to_bytes(4, byteorder='big')) f.write(ciphertext)
解密端代码(新增签名验证逻辑)
from Crypto.PublicKey import RSA from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 # 加载密钥(接收方用发送方的公钥验证签名,用自己的私钥解密AES密钥) sender_public_key = RSA.import_key(open("sender_public.pem").read()) receiver_private_key = RSA.import_key(open("receiver_private.pem").read()) # 读取加密文件 with open("encrypted_data.bin", "rb") as f: # 读取签名 sig_len = int.from_bytes(f.read(4), byteorder='big') signature = f.read(sig_len) # 读取加密的AES密钥 aes_key_len = int.from_bytes(f.read(4), byteorder='big') encrypted_aes_key = f.read(aes_key_len) # 读取nonce nonce_len = int.from_bytes(f.read(4), byteorder='big') nonce = f.read(nonce_len) # 读取tag tag_len = int.from_bytes(f.read(4), byteorder='big') tag = f.read(tag_len) # 读取密文 ciphertext_len = int.from_bytes(f.read(4), byteorder='big') ciphertext = f.read(ciphertext_len) # --- 第一步:验证签名(必须先做,避免解密恶意数据)--- data_to_verify = encrypted_aes_key + nonce + tag + ciphertext hash_obj = SHA256.new(data_to_verify) try: pkcs1_15.new(sender_public_key).verify(hash_obj, signature) print("✅ 签名验证通过:消息来源合法且未被篡改") except (ValueError, TypeError): print("❌ 签名验证失败:消息可能被篡改或来源非法") exit() # --- 第二步:解密消息 --- # 解密AES密钥 cipher_rsa = PKCS1_OAEP.new(receiver_private_key) aes_key = cipher_rsa.decrypt(encrypted_aes_key) # AES-GCM解密并验证tag cipher_aes = AES.new(aes_key, AES.MODE_GCM, nonce=nonce) message = cipher_aes.decrypt_and_verify(ciphertext, tag) print("🎉 解密后的消息:", message.decode('utf-8'))
额外小贴士
- 如果你追求更高的安全性,可以把
pkcs1_15签名方案换成PSS(概率签名方案),只需要替换签名和验证的代码部分:# 签名时 from Crypto.Signature import pss signature = pss.new(private_key).sign(hash_obj) # 验证时 pss.new(sender_public_key).verify(hash_obj, signature) - 如果你的传输通道本身已经提供了完整性和身份认证(比如基于TLS的HTTPs),可以考虑简化签名步骤,但直接传输文件的场景下,签名依然是必要的安全保障。
内容的提问来源于stack exchange,提问作者Ahmed Salama
相关产品推荐
相关产品推荐

