当我直接对某些 xml 进行规范化时,我得到了同一个 xml 文档的两个不同的哈希值,而不是当我对其执行数字签名时,后者在对 xml 进行哈希处理之前也对 xml 执行相同的规范化算法?我发现数字签名规范化在规范化时包括换行符'\n'和空格字符,而直接算法则不包括。
虽然规范化规范中没有包含换行符 + 空格?我专门看这个版本http://www.w3.org/TR/2001/REC-xml-c14n-20010315
有人知道这是怎么回事吗?我已经包括了 xml 文档和代码的两个实现,以便您可以看到。
这真的让我感到困惑,我想知道为什么,我是否遗漏了一些明显的东西?
<root>
<child1>some text</child1>
<child2 attr="1" />
</root>
直接规范化代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.IO;
using System.ComponentModel;
namespace XML_SignatureGenerator
{
class XML_C14N
{
private String _filename;
private Boolean isCommented = false;
private XmlDocument xmlDoc = null;
public XML_C14N(String filename)
{
_filename = filename;
xmlDoc = new XmlDocument();
xmlDoc.Load(_filename);
}
//implement this spec http://www.w3.org/TR/2001/REC-xml-c14n-20010315
public String XML_Canonalize(System.Windows.Forms.RichTextBox tb)
{
//create c14n instance and load in xml file
XmlDsigC14NTransform c14n = new XmlDsigC14NTransform(isCommented);
c14n.LoadInput(xmlDoc);
//get canonalised stream
Stream s1 = (Stream)c14n.GetOutput(typeof(Stream));
SHA1 sha1 = new SHA1CryptoServiceProvider();
Byte[] output = sha1.ComputeHash(s1);
tb.Text = Convert.ToBase64String(output);
//create new xmldocument and save
String newFilename = _filename.Substring(0, _filename.Length - 4) + "C14N.xml";
XmlDocument xmldoc2 = new XmlDocument();
xmldoc2.Load(s1);
xmldoc2.Save(newFilename);
return newFilename;
}
public void set_isCommented(Boolean value)
{
isCommented = value;
}
public Boolean get_isCommented()
{
return isCommented;
}
}
}
xml数字签名代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
namespace XML_SignatureGenerator
{
class xmlSignature
{
public xmlSignature(String filename)
{
_filename = filename;
}
public Boolean SignXML()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
String fname = _filename; //"C:\\SigTest.xml";
xmlDoc.Load(fname);
SignedXml xmlSig = new SignedXml(xmlDoc);
xmlSig.SigningKey = rsa;
Reference reference = new Reference();
reference.Uri = "";
XmlDsigC14NTransform env = new XmlDsigC14NTransform(false);
reference.AddTransform(env);
xmlSig.AddReference(reference);
xmlSig.ComputeSignature();
XmlElement xmlDigitalSignature = xmlSig.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
xmlDoc.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/SignedXML.xml");
return true;
}
private String _filename;
}
}
任何想法都会很棒!顺便说一下,这都是 C# 代码。
提前致谢
乔恩
最佳答案
在我看来,XML Sig 处理空白的方式是错误的。它肯定不符合大多数思维正常的人所说的规范化。更改空格不会影响摘要,但在 xmlsig 中,它会。
一种可能的解决方法是在将文档传递给签名生成代码之前通过规范程序例程传递文档。这应该会使事情变得更加可预测。
This article可能有助于澄清事情。
关于直接调用 XML 规范化算法与作为 xml 数字签名的一部分调用时相比,XML 规范化算法会给出两种不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1026432/