Python3.6用cryptography/pycrypto复现M2Crypto private_encrypt签名问题
解决M2Crypto private_encrypt与cryptography/pycrypto签名不兼容问题
我之前也碰到过一模一样的坑——M2Crypto的private_encrypt生成的签名能过对方验证,但换用cryptography或pycrypto就不行,核心原因是这几个库在签名流程的细节上有默认差异,得把每一步都对齐才行。
最可能的差异点及对应解决方案
1. 签名流程的填充与哈希逻辑对齐
M2Crypto的private_encrypt本身是原始的RSA加密接口,很多人用它做签名时,会手动先哈希消息,再用PKCS#1 v1.5填充后加密;而cryptography的sign()方法是封装了「哈希+填充+加密」的标准签名流程,如果你没对齐这个逻辑,生成的签名自然不对。
举个具体的例子:
Python2.7 M2Crypto 签名代码(假设你是这么写的)
import M2Crypto from hashlib import sha256 # 加载私钥 priv_key = M2Crypto.RSA.load_key("private_key.pem") # 载荷必须是字节流(Python2的str就是字节) payload = b"your_payload_here" # 先计算哈希 hash_bytes = sha256(payload).digest() # 用PKCS#1 v1.5填充后加密(这就是签名的本质) signature = priv_key.private_encrypt(hash_bytes, M2Crypto.RSA.pkcs1_padding)
对应Python3.6 cryptography 复现代码
from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.backends import default_backend # 加载私钥(注意密码如果有就传对应的bytes,没有就传None) with open("private_key.pem", "rb") as f: priv_key = serialization.load_pem_private_key( f.read(), password=None, backend=default_backend() ) payload = b"your_payload_here" # 用标准PKCS#1 v1.5签名,指定和M2Crypto一致的哈希算法 signature = priv_key.sign( payload, padding.PKCS1v15(), hashes.SHA256() # 必须和M2Crypto里用的哈希完全一致,比如SHA1/SHA256/SHA512 )
如果你的M2Crypto代码是直接对原始载荷做加密(没有先哈希)(这其实不是标准签名,但硬要复现的话),cryptography里要这么写:
# 直接对载荷做PKCS#1 v1.5加密(非标准签名,不推荐但适配你的场景) signature = priv_key.private_encrypt( payload, padding.PKCS1v15() )
2. 确保载荷的字节流完全一致
Python2和Python3的字符串编码差异是隐形坑:Python2的str是字节,Python3的str是Unicode。如果你的载荷是字符串,一定要确保在两个版本中转换成完全相同的字节流,比如:
- Python2:
payload = "test".encode("utf-8")(或者直接用b"test") - Python3:
payload = "test".encode("utf-8")
3. 私钥加载的一致性
检查M2Crypto和cryptography加载的私钥是否完全相同:
- M2Crypto导出私钥:
priv_key.save_key("exported_from_m2.pem") - 对比导出的PEM和cryptography加载的私钥文件,确保没有格式差异(比如是否带密码、是否是PKCS#1还是PKCS#8格式)。如果是PKCS#8格式,cryptography可以直接加载,M2Crypto可能需要转换。
排查小技巧
如果还是不对,把两个库生成的签名转成十六进制字符串对比:
# M2Crypto(Python2) print(signature.encode("hex")) # cryptography(Python3) print(signature.hex())
如果差异很大,大概率是哈希或填充没对齐;如果只有个别字节不同,可能是字节序或编码问题。
内容的提问来源于stack exchange,提问作者Abhishek
相关产品推荐
相关产品推荐

