返回

如何使用 Python 和 cryptography 生成 XML 的 ECDSA SignatureValue?

python

如何使用 Python 和 cryptography (wsse) 为 XML 生成 ECDSA SignatureValue

问题陈述

想像你有一个包含 wsse (http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd) 标头、ds:Signatureds:SignedInfo 元素的规范化 XML。此 XML 是 SOAP 请求,需要进行签名。

你已计算 signedinfo 元素的 ECDSA 数字签名,并获得了(r, s)这对整数。

你现在需要将这些整数转换为 base64 编码的 SignatureValue。这涉及将整数转换为 octet 序列,对 r 和 s 值进行编码,串联 octet 序列,进行 base64 编码并删除填充。

解决步骤

  1. 将整数转换为 octet 序列: 使用整数的二进制表示,将整数转换为 octet 序列。
  2. 编码 r 和 s 值: 使用 ASN.1 DER 规则编码 r 和 s 值。
  3. 串联 octet 序列: 将 r 和 s 值编码后的 octet 序列串联起来。
  4. 进行 base64 编码: 将串联的 octet 序列进行 base64 编码。
  5. 删除填充: ASN.1 DER 编码可能会在 octet 序列的末尾添加填充。从 base64 编码的签名值中删除此填充。

代码示例

以下是使用 Python 和 cryptography 库生成 ECDSA SignatureValue 的代码示例:

import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec

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

# 计算签名
signedinfo_c14n_xml_data = b"canonicalized_signedinfo_xml_data"
bin_signature = private_key.sign(
    signedinfo_c14n_xml_data, ec.ECDSA(hashes.SHA256())
)

# 解码签名
r, s = ec.decode_dss_signature(bin_signature)

# 将整数转换为 octet 序列
r_octet_sequence = r.to_bytes(32, byteorder="big")
s_octet_sequence = s.to_bytes(32, byteorder="big")

# 编码 r 和 s 值
r_encoded = int.from_bytes(r_octet_sequence, "big").to_bytes(32, "big")
s_encoded = int.from_bytes(s_octet_sequence, "big").to_bytes(32, "big")

# 串联 octet 序列
concatenated_octet_sequence = r_encoded + s_encoded

# 进行 base64 编码
base64_encoded = base64.b64encode(concatenated_octet_sequence)

# 删除填充
signature_value = base64_encoded.replace("=", "")

# 输出 SignatureValue
print(signature_value)

结论

通过遵循这些步骤,你可以将 ECDSA (r, s)值转换为 base64 编码的 SignatureValue,该值可用于对 XML 进行签名。

常见问题解答

  • 为什么需要删除填充?

ASN.1 DER 编码可能会在 octet 序列的末尾添加填充。删除此填充是出于安全原因,因为它可以防止在签名中注入额外数据。

  • 我可以使用其他语言或库吗?

当然可以!本示例使用 Python 和 cryptography 库,但你可以使用其他语言和库(如 Java 中的 org.apache.wss4j)来实现相同的结果。

  • SignatureValue 中为什么会有一个空格字符?

空格字符可能出现在由某些库(如 org.apache.wss4j)生成的签名值中。根据 base64 规范,空格字符应被忽略,因此它们不会影响签名值的有效性。

  • 如何验证 ECDSA 签名?

要验证 ECDSA 签名,你需要 signedinfo 元素的规范化 XML、签名值的 base64 编码和公钥。你可以使用 cryptography 库或其他工具来进行验证。

  • 我遇到的麻烦,如何解决?

如果你在生成或验证 ECDSA 签名时遇到问题,请查看 cryptography 库的文档或寻求其他资源来获得帮助。