如何用Python cryptography库实现带签名的RSA加密?
RSA实现带保密性、完整性、真实性的消息传输问题解答
核心问题与方案梳理
你需要用RSA实现Alice到Bob的消息传输,同时满足三个核心安全要求:
- 保密性:仅Bob能解密消息
- 真实性:Bob可确认消息来自Alice
- 完整性:消息传输中未被篡改
你尝试过两种拼接式方案,遇到了RSA加密长度限制的问题,对Topaco提出的"密文+签名分离发送"方案存在疑惑,以下是具体分析和修正方案:
1. 你当前拼接方案的缺陷
你当前代码中用分隔符拼接消息与签名后加密,存在两个关键问题:
- 长度限制:RSA单次加密的明文长度受密钥和填充算法约束(4096位RSA+OAEP-SHA256的最大明文长度为446字节左右),长消息+签名的组合很容易超出限制导致加密失败。
- 拆分风险:如果消息本身包含分隔符
|,拆分操作会直接出错,存在逻辑隐患。
2. Topaco方案的合理性解释
你觉得"发送两个内容奇怪"是多虑了,这种密文与签名分离的方式是业内标准做法,原因如下:
- RSA签名针对的是哈希值,长度固定(4096位RSA的签名为512字节),不会受消息长度影响。
- 先加密再签名的逻辑更清晰:签名保证密文未被篡改且来自Alice,解密保证只有Bob能获取原始消息。
- 避免了拼接拆分的潜在风险,同时便于扩展(比如后续切换为更高效的混合加密方案)。
3. 修正后的代码实现
我们基于Topaco方案优化,同时用长度前缀的方式打包密文与签名(避免分隔符的缺陷):
from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa import struct # 生成密钥对 alice_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096) alice_public_key = alice_private_key.public_key() bob_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096) bob_public_key = bob_private_key.public_key() message = b"Hello, world! This is a longer message to test RSA length limits." # Alice侧操作:先加密,再签名,最后打包 # 1. 用Bob公钥加密消息(保证保密性) ciphertext = bob_public_key.encrypt( message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) # 2. 用Alice私钥对密文签名(保证真实性与完整性) signature = alice_private_key.sign( ciphertext, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) # 3. 打包数据:4字节大端存储签名长度 + 签名 + 密文 packed_data = struct.pack('>I', len(signature)) + signature + ciphertext # Bob侧操作:先解析,再验签,最后解密 # 1. 解析打包的数据 sig_len = struct.unpack('>I', packed_data[:4])[0] received_signature = packed_data[4:4+sig_len] received_ciphertext = packed_data[4+sig_len:] # 2. 验证签名 try: alice_public_key.verify( received_signature, received_ciphertext, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) print("签名验证通过:消息来自Alice且未被篡改") # 3. 解密密文 plaintext = bob_private_key.decrypt( received_ciphertext, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) print("解密后的消息:", plaintext.decode('utf-8')) except InvalidSignature as e: print("签名验证失败:消息可能被篡改或非Alice发送")
4. 生产环境最优方案:混合加密
RSA加密大消息效率极低,实际场景中会采用对称加密+RSA的混合方案:
- Alice生成随机对称密钥(如AES-256-GCM)
- 用对称密钥加密消息(高效处理大消息)
- 用Bob公钥加密对称密钥
- 用Alice私钥对「加密后的对称密钥+密文哈希」签名
- 发送:加密后的对称密钥 + 密文 + 签名
- Bob:先验签,再解密对称密钥,最后解密密文
该方案兼顾了安全性与效率,是工业界的标准实践。
关键知识点总结
- 私钥用于签名(证明身份),公钥用于加密(保证仅对应私钥持有者可解密),切勿混淆用途。
- RSA加密存在长度限制,无法直接处理大消息,优先考虑混合加密方案。
- 签名应针对需要验证完整性的内容(如密文),而非原始消息,避免额外的加密/解密开销。
- 二进制内容拼接优先用长度前缀替代分隔符,避免消息含分隔符导致的拆分错误。
内容的提问来源于stack exchange,提问作者BOSS_ladis
相关产品推荐
相关产品推荐

