【发布时间】:2010-12-11 21:55:23
【问题描述】:
我可以成功地进行手动引用验证(规范化每个引用的元素 --> SHA1 --> Base64 --> 检查它是否与 DigestValue 内容相同)但我在验证 SignatureValue 时失败了。这是要规范化和散列的 SignedInfo:
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#element-1-1291739860070-11803898">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>d2cIarD4atw3HFADamfO9YTKkKs=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#timestamp">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>YR/fZlwJdw+KbyP24UYiyDv8/Dc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
在删除标签之间的所有空格(因此将整个元素放在一行中)后,我得到了这个 sha1 摘要(在 Base64 中):
6l26iBH7il/yrCQW6eEfv/VqAVo=
现在我希望在解密 SignatureValue 内容后找到相同的摘要,但我得到了一个不同的和 longer 值:
MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH+u6R4N8Ig=
下面是一些用于解密的 java 代码:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new File(inputFilePath));
NodeList nl = doc.getElementsByTagName("ds:SignatureValue");
if (nl.getLength() == 0) {
throw new Exception("Cannot find SignatureValue element");
}
String signature = "OZg96GMrGh0cEwbpHwv3KDhFtFcnzPxbwp9Xv0pgw8Mr9+NIjRlg/G1OyIZ3SdcOYqqzF4/TVLDi5VclwnjBAFl3SEdkyUbbjXVAGkSsxPQcC4un9UYcecESETlAgV8UrHV3zTrjAWQvDg/YBKveoH90FIhfAthslqeFu3h9U20=";
X509Certificate cert = X509Certificate.getInstance(new FileInputStream(<a file path>));
PublicKey pubkey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA","SunJCE");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
byte[] decodedSignature = Base64Coder.decode(signature);
cipher.update(decodedSignature);
byte[] sha1 = cipher.doFinal();
System.out.println(Base64Coder.encode(sha1));
让我很困惑的是两个摘要的大小不同,但当然我还需要从两个计算中获得完全相同的值。有什么建议么?谢谢。
【问题讨论】:
-
"删除标签之间的所有空格"...对吗?看着w3.org/TR/2001/…,听起来你可能删除了太多的空白。
-
感谢您的回答。我理解你的观点,但是,正如我在问题开头所说的那样,我可以通过且仅通过删除这些空格来成功地对同一 SOAP 消息进行引用验证(两个引用,这不会是意外),所以我必须假设没错。
-
规范化不仅仅是删除空格。它处理命名空间前缀问题、属性排序,以及通常会更改 phisicaly 文件的字节顺序(以及因此哈希摘要)的所有内容,但不会更改 XML 信息集(== XML 的含义负载)
-
当然。我使用 org.apache.xml.security.c14n.Canonicalizer 但在我需要删除空格以获得与 xml 中相同的摘要之后。
-
好吧,我找到了为什么解密的摘要这么大:它是由前缀+实际摘要(w3.org/TR/2002/REC-xmldsig-core-20020212/Overview.html)组成的。实际摘要在最后 20 个字节中。现在我有两个大小相同的摘要,但仍然彼此不同:(
标签: java web-services soap cryptography xml-signature