【问题标题】:XML Signature: How to calculate the digest value?XML 签名:如何计算摘要值?
【发布时间】:2017-10-20 18:50:38
【问题描述】:

我有一个这样的 XML

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar>
    <value>A</value>
  </bar>
  <bar>
    <value>B</value>
  </bar>
  <baz>
    <value>C</value>
  </baz><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>WqpRWHxXA0YgH+p3Sxy6hRo1XIk=</DigestValue></Reference></SignedInfo><SignatureValue>EoRk/GhR4UA4D+8AzGPPkeim1dZrlSy88eF73n/T9Lpeq9IxoGRHNUA8FEwuDNJuz3IugC0n2RHQQpQajiYvhlY3XG+z742pgsdMfFE4Pddk4gF1T8CVS1rsF7bjX+FKT/c8B2/C8FNgmfkxDlB/ochtbRvuAGPQGtgJ3h/wjSg=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIB8zCCAVygAwIBAgIQgfzbrIjhLL9FobStI2ub3zANBgkqhkiG9w0BAQQFADATMREwDwYDVQQDEwhUZXN0ZUFjbjAeFw0wMDAxMDEwMDAwMDBaFw0zNjAxMDEwMDAwMDBaMBMxETAPBgNVBAMTCFRlc3RlQWNuMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO+yAZ8/qJbhSVH/+2wMmzix3jM/CExb6sTgaiPwe6ylcHgF45zeQDq06OSJZCSns34em/ULINZddDf8z0b9uk/2sOGr1pYqsunLLBvw2FkvWJQDkhx2SzCm8v4xGX2kyXNbjiY/K56oPOMjpayKoAFnnvk7p2iFAxNZK/6lpZ7wIDAQABo0gwRjBEBgNVHQEEPTA7gBCOOHcajwnATYZ0t6w7LVU0oRUwEzERMA8GA1UEAxMIVGVzdGVBY26CEIH826yI4Sy/RaG0rSNrm98wDQYJKoZIhvcNAQEEBQADgYEABL9Qhi6f1Z+/t8oKXBQFx3UUsNF9N2o4k6q1c3CKZYqx2E/in+nARIYRdh5kbeLfomi6GIyVFeXExp8crob3MAzOQMvXf9+ByuezimMPIHDvv0u3kmmeITXfoZrHCDxLoWWlESN1owBfKPqe7JKAuu9ORDC0pUiUfCHWxCoqNos=</X509Certificate></X509Data></KeyInfo></Signature>
</foo>

引用中的摘要值(WqpRWHxXA0YgH+p3Sxy6hRo1XIk=)是如何创建的?我的意思是如何手动计算这个值?

【问题讨论】:

  • 为什么要手动计算?这将是一个乏味且容易出错的过程。
  • 我正在使用 .net 函数来验证签名。它返回签名无效。所以我想手动检查一下或者有没有工具可以检查签名...
  • 我了解到您解决了“参考摘要验证失败”错误?是否有可能详细解释您实际上是如何做到的?我在使用 Metro 和 .Net WCF 应用程序无法识别摘要值的签名肥皂消息时遇到了这个问题。

标签: xml digital-signature digest xml-signature


【解决方案1】:

我在尝试找出完全相同的事情时遇到了这个问题。后来我想出了如何做到这一点,所以我想我会在这里发布答案。

需要发生的事情是:

  • 规范化
  • 创建摘要值,通常是 SHA1(但也可以是 SHA256 等)
  • base64 编码

规范化部分相当简单,因为 Java 库为我做了这些。我挣扎的是下一点,即摘要的创建,因为我犯了一个致命错误,因为我生成的 SHA1 摘要是 HEX 形式的 SHA1。 SHA1 是 160 位,所以是 20 个字节,但是如果你以十六进制输出这 160 位,你会得到 40 个字符。如果您随后对其进行 base64 编码,那么与 DigestValue 中的值相比,您会得到完全错误的值

相反,您应该生成 SHA1 摘要并对 20 字节输出进行 base64 编码。不要尝试将 20 个字节输出到 STDOUT,因为它不太可能是可读的(这就是人们经常输出 HEX 等价物的原因,因为它可读的)。相反,只需对 20 个字节进行 base64 编码,这就是您的 DigestValue。

【讨论】:

  • 我也这么想,但我也得到了不同的价值。你是直接消化了 Canonicalization Bytes 还是消化了 String 字节?
  • 什么的SHA1摘要?
  • @lonelyloner:删除签名节点后规范化输入 xml 的 SHA1。在我的例子中,xml 是由 .NET 创建的,所以我还必须在规范化和创建 SHA1 之前删除标签之间的 \r \n 和空格
【解决方案2】:

很简单,在控制台使用openssl:

openssl dgst -binary -sha1 文件 | openssl enc -base64

完成

【讨论】:

  • OP 没有将“手动”指定为“编程”。这无论如何都是一种很好的检查方式。
  • 你知道如何获取签名值吗?
  • 发现这非常有用。看起来也很想生成 signturevalue ,就像上面的 @dev4life 一样。
【解决方案3】:

我自己也遇到过这个问题:我在 Java 中生成 XML 签名并在 .NET 中进行验证,但验证总是失败。在我的情况下,原因是“打印 XML 到文件”函数 XMLWrite.m(是的,在 MATLAB* 中),它“漂亮地打印”了 XML,插入了它认为合适的制表符、空格和换行符。由于这些是文档的一部分,因此验证自然会失败(在 Java 中也失败了)。查看您的消息来源,这可能发生在您身上。使用 Transformer (javax.xml.transform.*) 在不更改内容的情况下正确序列化您的 DOM。

*您知道 MATLAB 也理解 Java 吗?您只需在解释器控制台中输入 Java 语句,它们就会像本地 m-code 一样执行。

【讨论】:

  • 依赖于 XML 规范化的 XML 签名已经解决了这个问题。首先对 XML 进行规范化,然后正确处理语法差异(空格、命名空间等)。
  • True:但它是被规范化的 DOM,而不是它的序列化。在计算摘要之后,在序列化过程中插入额外的空白字符(到文件),并且当验证代码创建其 DOM、对其进行规范化并重新计算摘要时,它们仍然存在。空格在解析的字符数据节点中很重要。
【解决方案4】:

这是一个需要以下 jars 的 JAVA 解决方案:

  • commons-logging-1.2.jar
  • commons-codec-1.6.jar
  • Saxon-HE-9.4.jar
  • xmlsec-1.3.0.jar

本方案使用http://www.w3.org/2001/10/xml-exc-c14n#作为规范化算法,使用SHA256作为哈希算法和base64编码。

注意:document 将 XML 文档表示为 JAVA 中的 DOM 对象。

代码示例:

        // create the transformer in order to transform the document from
        // DOM Source as a JAVA document class, into a character stream (StreamResult) of
        // type String writer, in order to be converted to a string later on
        TransformerFactory tf = new net.sf.saxon.TransformerFactoryImpl();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

        // create the string writer and transform the document to a character stream
        StringWriter sw = new StringWriter();
        transformer.transform(new DOMSource(document), new StreamResult(sw));

        String documentAsString = sw.toString();

        // initialize the XML security object, which is necessary to run the apache canonicalization
        com.sun.org.apache.xml.internal.security.Init.init();

        // canonicalize the document to a byte array and convert it to string
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        byte canonXmlBytes[] = canon.canonicalize(documentAsString.getBytes());
        String canonXmlString = new String(canonXmlBytes);

        // get instance of the message digest based on the SHA-256 hashing algorithm
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        // call the digest method passing the byte stream on the text, this directly updates the message
        // being digested and perform the hashing
        byte[] hash = digest.digest(canonXmlString.getBytes(StandardCharsets.UTF_8));

        // encode the endresult byte hash
        byte[] encodedBytes = Base64.encodeBase64(hash);

        return new String(encodedBytes);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多