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

Python中如何用PKCS12证书签名SHA256哈希后的XML请求?

使用PKCS12证书签名SOAP XML请求的正确实现

问题

要向SOAP API发送请求,需按以下流程处理:

  • 对XML请求内容生成SHA256哈希
  • 使用PKCS12证书中的RSA私钥对哈希值签名

尝试用PyCryptodome(Crypto库)实现时触发IndexError,换用cryptography库能成功加载PKCS12证书,但不清楚如何用该库完成签名流程,求可行的实现代码。

失败的Crypto库实现代码

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15

with open("/my/cert/file.p12", "rb") as f:
    cert_data = f.read()

private_key = RSA.import_key(cert_data, passphrase="some_passphrase")
signer = pkcs1_15.new(private_key)

hash = SHA256.new(xml_data)
signature = signer.sign(hashed)

报错信息

security/crypto.py:25: in __init__
    private_key = RSA.import_key(cert.certificate, passphrase=cert.passphrase)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/PublicKey/RSA.py:851: in import_key
    return _import_keyDER(extern_key, passphrase)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/PublicKey/RSA.py:746: in _import_keyDER
    return decoding(extern_key, passphrase)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/PublicKey/RSA.py:697: in _import_pkcs1_private
    der = DerSequence().decode(encoded, nr_elements=9, only_ints_expected=True)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/Util/asn1.py:610: in decode
    result = DerObject.decode(self, der_encoded, strict=strict)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/Util/asn1.py:228: in decode
    self._decodeFromStream(s, strict)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/Util/asn1.py:623: in _decodeFromStream
    DerObject._decodeFromStream(self, s, strict)
/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/Util/asn1.py:245: in _decodeFromStream
    length = self._decodeLen(s)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Crypto.Util.asn1.DerSequence object at 0x7f03288f97d0>
s = <Crypto.Util.asn1.BytesIO_EOF object at 0x7f0328890310>

    def _decodeLen(self, s):
            """Decode DER length octets from a file."""

            length = s.read_byte()

            if length > 127:
                encoded_length = s.read(length & 0x7F)
>               if bord(encoded_length[0]) == 0:
E               IndexError: index out of range

/Yv1Cv_rJ-py3.11/lib/python3.11/site-packages/Crypto/Util/asn1.py:205: IndexError

正确的cryptography库实现方案

cryptography库可以通过组合哈希与签名步骤,实现和Crypto库一致的PKCS#1 v1.5签名逻辑,以下是完整可行代码:

完整实现代码

import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import pkcs12

# 1. 加载PKCS12证书中的私钥
with open("/my/cert/file.p12", "rb") as f:
    private_key, certificate, additional_certs = pkcs12.load_key_and_certificates(
        f.read(),
        password=b"some_passphrase"  # 密码需传入字节类型
    )

# 2. 准备XML请求数据(确保为字节类型,字符串需先encode转换)
xml_data = "your_soap_xml_content_here".encode("utf-8")

# 3. 执行签名:自动完成SHA256哈希+RSA-PKCS#1 v1.5签名
signature = private_key.sign(
    xml_data,
    padding.PKCS1v15(),
    hashes.SHA256()
)

# 4. 将签名转为Base64格式(SOAP API通常要求此可传输格式)
base64_signature = base64.b64encode(signature).decode("utf-8")

print(base64_signature)

可选:手动哈希后签名(与Crypto库逻辑完全对齐)

如果需要先手动计算哈希再签名,可替换签名步骤为:

# 手动计算SHA256哈希
digest = hashes.Hash(hashes.SHA256())
digest.update(xml_data)
hashed_data = digest.finalize()

# 对哈希值签名
signature = private_key.sign(
    hashed_data,
    padding.PKCS1v15(),
    hashes.SHA256()
)

内容的提问来源于stack exchange,提问作者Woody1193

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:40:59