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

在Python中使用SHA256签名字节串的问题求助

解决纯Python实现SHA256签名与OpenSSL二进制结果不一致的问题

我懂你碰到的这个麻烦——之前靠调用本地OpenSSL二进制处理SHA256签名,大字节串容易因为进程通信出问题,换成纯Python实现后签名却完全对不上,这确实挺闹心的。咱们一步步拆解问题,把签名和OpenSSL的结果对齐:

1. 对齐签名的核心流程:别手动哈希后直接签名

OpenSSL用openssl dgst -sha256 -sign命令签名时,实际做了三件事:

  • 对原始数据计算SHA256哈希
  • 给哈希值加上ASN.1格式的哈希算法标识(这是很多人忽略的关键步骤)
  • 用私钥对带标识的哈希值做RSA-PKCS#1 v1.5填充签名

如果Python里手动哈希后直接签名,就跳过了ASN.1标识这一步,结果自然不一样。正确的做法是让加密库自动处理整个流程:

错误示例(会导致签名不一致)

import hashlib
from cryptography.hazmat.primitives.asymmetric import padding

# 错误:手动哈希后直接签名,缺少ASN.1哈希标识
data = b"你的大字节串数据"
hash_data = hashlib.sha256(data).digest()
signature = private_key.sign(
    hash_data,
    padding.PKCS1v15(),
    None  # 没有指定哈希算法,直接签名原始哈希值
)

正确示例(和OpenSSL流程完全对齐)

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# 正确:让cryptography库自动处理SHA256哈希+ASN.1标识+PKCS#1 v1.5填充
signature = private_key.sign(
    data,
    padding.PKCS1v15(),
    hashes.SHA256()
)

2. 确保私钥加载方式完全一致

OpenSSL加载私钥时会自动处理不同格式(PEM/DER、加密/未加密),Python里加载时要和OpenSSL的参数对齐:

  • 如果私钥是加密的PEM,OpenSSL用-passin参数输入密码,Python加载时也要提供密码:
from cryptography.hazmat.primitives import serialization

with open("private.key", "rb") as key_file:
    private_key = serialization.load_pem_private_key(
        key_file.read(),
        password=b"你的私钥密码",  # 和OpenSSL用的密码一致
    )
  • 如果是未加密的私钥,直接传password=None即可。

3. 验证原始数据的字节一致性

签名的前提是原始数据完全相同,先确认OpenSSL和Python处理的是同一批字节:

  • 用OpenSSL计算数据的SHA256哈希:
openssl dgst -sha256 your_data.bin
  • 用Python计算同样数据的哈希:
import hashlib
with open("your_data.bin", "rb") as f:
    data = f.read()
print(hashlib.sha256(data).hexdigest())

如果两个哈希值不一样,说明数据处理有问题(比如编码错误、文件读取方式不同),先解决这个问题再看签名。

4. 对齐签名的输出格式

OpenSSL默认输出二进制签名,Python生成的也是二进制字节串。如果需要转成Base64或十六进制,两边的转换方式要一致:

  • OpenSSL转Base64:
openssl dgst -sha256 -sign private.key your_data.bin | base64
  • Python转Base64:
import base64
signature_b64 = base64.b64encode(signature).decode('utf-8')

完整验证示例

准备好测试文件test.data和未加密私钥private.pem,先跑OpenSSL命令生成签名:

# 生成二进制签名
openssl dgst -sha256 -sign private.pem -out sig_openssl.bin test.data
# 转成十六进制方便对比
xxd -p sig_openssl.bin > sig_openssl.hex

再用Python生成签名并对比:

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

# 加载私钥
with open("private.pem", "rb") as key_file:
    private_key = serialization.load_pem_private_key(
        key_file.read(),
        password=None,
    )

# 读取测试数据
with open("test.data", "rb") as f:
    data = f.read()

# 生成签名
signature = private_key.sign(
    data,
    padding.PKCS1v15(),
    hashes.SHA256()
)

# 转成十六进制保存
with open("sig_python.hex", "w") as f:
    f.write(signature.hex())

最后对比sig_openssl.hex和sig_python.hex,内容应该完全一致。


内容的提问来源于stack exchange,提问作者Luis Alberto Santana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:24:17