如何使用 Python 和 cryptography 生成 XML 的 ECDSA SignatureValue?
2024-03-12 21:21:37
如何使用 Python 和 cryptography (wsse) 为 XML 生成 ECDSA SignatureValue
问题陈述
想像你有一个包含 wsse (http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd) 标头、ds:Signature
和 ds:SignedInfo
元素的规范化 XML。此 XML 是 SOAP 请求,需要进行签名。
你已计算 signedinfo 元素的 ECDSA 数字签名,并获得了(r, s)
这对整数。
你现在需要将这些整数转换为 base64 编码的 SignatureValue
。这涉及将整数转换为 octet 序列,对 r 和 s 值进行编码,串联 octet 序列,进行 base64 编码并删除填充。
解决步骤
- 将整数转换为 octet 序列: 使用整数的二进制表示,将整数转换为 octet 序列。
- 编码 r 和 s 值: 使用 ASN.1 DER 规则编码 r 和 s 值。
- 串联 octet 序列: 将 r 和 s 值编码后的 octet 序列串联起来。
- 进行 base64 编码: 将串联的 octet 序列进行 base64 编码。
- 删除填充: 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 库的文档或寻求其他资源来获得帮助。