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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:13:16