如何在Python中实现c14n11 XML规范化?lxml等库不支持该算法
问题
我正在使用Python的signxml库对XML文档进行签名,代码如下:
signer = XMLSigner( method=methods.enveloped, signature_algorithm="rsa-sha256", c14n_algorithm="http://www.w3.org/2006/12/xml-c14n11", digest_algorithm="sha256", ) signed_root = signer.sign( document_to_sign, key=private_key, cert=public_key, key_info=key_info )
签名完成后,我需要向签名中添加一些额外信息,因此必须生成规范化XML元素的摘要值。我尝试使用lxml执行此操作,但它不支持c14n11,相关代码如下:
def generate_custom_digest_value(signature_element, element, namespace): element_to_digest = signature_element.xpath(element, namespaces=namespace)[0] # Serialize the element to canonical XML canonicalized_element = etree.tostring( element_to_digest, method="c14n11", exclusive=False ) # this does not work and throws an error because there's no method "c14n11" # Calculate the SHA-256 digest digest_value = hashlib.sha256(canonicalized_element).digest() # Convert digest value to base64 for inclusion in XML digest_value_base64 = base64.b64encode(digest_value).decode("utf-8") return digest_value_base64
我还尝试过xmlsec库,它同样不支持c14n11。请问如何使用lxml或其他Python库实现c14n11 XML规范化?
解决方案
方法1:复用signxml内置的规范化工具
signxml本身已经实现了c14n11支持,直接复用它的内部逻辑即可,无需额外依赖:
from signxml import XMLSigner import hashlib import base64 def generate_custom_digest_value(signature_element, element, namespace): element_to_digest = signature_element.xpath(element, namespaces=namespace)[0] # 获取signxml的c14n11规范化器 canonicalizer = XMLSigner( c14n_algorithm="http://www.w3.org/2006/12/xml-c14n11" )._get_canonicalizer() canonicalized_element = canonicalizer.process(element_to_digest) # 计算SHA-256摘要并转为Base64 digest_value = hashlib.sha256(canonicalized_element).digest() return base64.b64encode(digest_value).decode("utf-8")
方法2:使用xmlcanonicalizer库
xmlcanonicalizer是专门处理XML规范化的库,原生支持c14n11。先安装依赖:
pip install xmlcanonicalizer
然后修改你的函数:
from xmlcanonicalizer import XmlCanonicalizer import hashlib import base64 def generate_custom_digest_value(signature_element, element, namespace): element_to_digest = signature_element.xpath(element, namespaces=namespace)[0] # 初始化c14n11规范化器(非独占模式) canonicalizer = XmlCanonicalizer( include_comments=False, exclusive=False, algorithm="http://www.w3.org/2006/12/xml-c14n11" ) canonicalized_element = canonicalizer.canonicalize(element_to_digest) # 计算摘要并转Base64 digest_value = hashlib.sha256(canonicalized_element).digest() return base64.b64encode(digest_value).decode("utf-8")
方法3:升级xmlsec到支持c14n11的版本
如果坚持使用xmlsec,确保安装的xmlsec1底层库版本在1.2.30以上(该版本开始支持c14n11),然后通过以下代码调用:
import xmlsec import hashlib import base64 def generate_custom_digest_value(signature_element, element, namespace): element_to_digest = signature_element.xpath(element, namespaces=namespace)[0] # 创建c14n11规范化上下文 ctx = xmlsec.Ctx() c14n_ctx = xmlsec.C14NCtx.create(ctx) c14n_ctx.set_algorithm(xmlsec.Transform.C14N11) # 执行规范化 canonicalized_element = c14n_ctx.process_node(element_to_digest) # 清理资源 c14n_ctx.destroy() ctx.destroy() # 计算摘要并转Base64 digest_value = hashlib.sha256(canonicalized_element).digest() return base64.b64encode(digest_value).decode("utf-8")
内容的提问来源于stack exchange,提问作者Package.JSON
相关产品推荐
相关产品推荐

