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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:57:19