XML签名:如何计算摘要值?

问题描述 投票:0回答:4

我有一个像这样的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=)是如何创建的?我的意思是如何手动计算这个值?

xml digital-signature digest xml-signature
4个回答
28
投票

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

需要发生的事情是:

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

规范化部分相当简单,因为 Java 库为我做到了这一点。 我遇到的困难是接下来的一点,即摘要的创建,因为我犯了一个致命错误,我生成的 SHA1 摘要是十六进制形式的 SHA1。 SHA1 是 160 位,即 20 个字节,但如果以十六进制输出这 160 位,则会得到 40 个字符。 如果您随后对其进行 base64 编码,则与 DigestValue 中应有的值相比,您会得到“完全错误的值”。 相反,您应该生成 SHA1 摘要并对 20 字节输出进行 Base64 编码。 不要尝试将 20 个字节输出到 STDOUT,因为它不太可能可读(这就是为什么人们经常输出等价的十六进制,因为它

可读的)。 相反,只需对 20 个字节进行 base64 编码,这就是您的 DigestValue。


8
投票

openssl dgst -二进制-sha1 文件 | openssl enc -base64

完成


3
投票

*您确实知道 MATLAB 也理解 Java?您只需在解释器控制台中输入 Java 语句即可,它们将像本机 m 代码一样执行。


3
投票

commons-logging-1.2.jar
  • commons-codec-1.6.jar
  • 撒克逊-HE-9.4.jar
  • xmlsec-1.3.0.jar
  • 该解决方案使用
http://www.w3.org/2001/10/xml-exc-c14n#

作为规范化算法,并使用

SHA256
作为哈希算法和base64编码。

注:
document

在JAVA中表示XML文档为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);

	
© www.soinside.com 2019 - 2024. All rights reserved.