如何在C#中使用XmlDsigC14NTransform类

art*_*nce 5 c# xml canonicalization xml-signature

我试图通过使用System.Security.Cryptography.Xml.XMLDsigC14nTransformc#.net Framework 2.0类来规范化xml节点。

该实例需要三种不同的输入类型,即NodeList,Stream和XMLDocument。我尝试使用所有这些输入类型进行转换,但是得到了不同的结果。我真正想做的是规范化单个节点,但是正如您在输出文件中看到的那样,输出不包含任何内部xml。

非常感谢有关规范XML节点的正确方法的任何建议。最好,

string path = @"D:\Test\xml imza\sign.xml";
XmlDocument xDoc = new XmlDocument();
xDoc.PreserveWhitespace = true;
using (FileStream fs = new FileStream(path, FileMode.Open))
{
    xDoc.Load(fs);
}

// canon node list
XmlNodeList nodeList = xDoc.SelectNodes("//Child1");

XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
transform.LoadInput(nodeList);
MemoryStream ms = (MemoryStream)transform.GetOutput(typeof(Stream));

File.WriteAllBytes(@"D:\Test\xml imza\child1.xml", ms.ToArray());

// canon XMLDocument
transform = new XmlDsigC14NTransform();
transform.LoadInput(xDoc);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));

File.WriteAllBytes(@"D:\Test\xml imza\doc.xml", ms.ToArray());

// Document to Stream
ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
xDoc.WriteTo(xw);
xw.Flush();
ms.Position = 0;

transform = new XmlDsigC14NTransform();
transform.LoadInput(ms);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));

File.WriteAllBytes(@"D:\Test\xml imza\ms.xml", ms.ToArray());

// node to stream
ms = new MemoryStream();
xw = XmlWriter.Create(ms);
nodeList[0].WriteTo(xw);
xw.Flush();
ms.Position = 0;

transform = new XmlDsigC14NTransform();
transform.LoadInput(ms);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));

File.WriteAllBytes(@"D:\Test\xml imza\ms2.xml", ms.ToArray());
Run Code Online (Sandbox Code Playgroud)

sign.xml

<?xml version="1.0" encoding="utf-8" ?>
<Root Attr="root" xmlns:test="http://www.test.com/xades#">
  <Child1 Cttribute="c3" Attribute1="c1" Bttribute="c2">
    <child11 Attribute11="c11">Element11</child11>
  </Child1>
  <Child2 Attribute2="c2">
    <child21 Attribute21="c21">Element21</child21>
    <child22 Attribute22="c22">Element22</child22>
  </Child2>
  <Child3 Attribute3="c3">
    <child31 Attribute32="c31">
      <child311 Attribute311="c311">Element311</child311>
    </child31>
  </Child3>  
</Root>
Run Code Online (Sandbox Code Playgroud)

Child1.xml

<Child1 xmlns:test="http://www.test.com/xades#"></Child1>
Run Code Online (Sandbox Code Playgroud)

doc.xml

<Root xmlns:test="http://www.test.com/xades#" Attr="root">&#xD;
  <Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">&#xD;
    <child11 Attribute11="c11">Element11</child11>&#xD;
  </Child1>&#xD;
  <Child2 Attribute2="c2">&#xD;
    <child21 Attribute21="c21">Element21</child21>&#xD;
    <child22 Attribute22="c22">Element22</child22>&#xD;
  </Child2>&#xD;
  <Child3 Attribute3="c3">&#xD;
    <child31 Attribute32="c31">&#xD;
      <child311 Attribute311="c311">Element311</child311>&#xD;
    </child31>&#xD;
  </Child3>  &#xD;
</Root>
Run Code Online (Sandbox Code Playgroud)

ms.xml

<Root xmlns:test="http://www.test.com/xades#" Attr="root">
  <Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
    <child11 Attribute11="c11">Element11</child11>
  </Child1>
  <Child2 Attribute2="c2">
    <child21 Attribute21="c21">Element21</child21>
    <child22 Attribute22="c22">Element22</child22>
  </Child2>
  <Child3 Attribute3="c3">
    <child31 Attribute32="c31">
      <child311 Attribute311="c311">Element311</child311>
    </child31>
  </Child3>  
</Root>
Run Code Online (Sandbox Code Playgroud)

ms2.xml

<Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
    <child11 Attribute11="c11">Element11</child11>
  </Child1>
Run Code Online (Sandbox Code Playgroud)

Jon*_*nna 6

我想,你的答案就在你的问题中,“我真正想做的是规范化单个节点,但正如你在输出文件中看到的那样,输出不包含任何内部 xml。”

如果我理解您的意思,那么您确实不想规范化单个节点,或者您会很高兴它不包含内部 XML。您想要规范化单个子树

XPath 返回节点,而不是子树。默认情况下,XPath 表达式返回的节点上的某些操作将包括其子节点和属性节点,但规范化故意不是其中之一,因为其中一些子节点可能会以您未签名的方式可变。在签名时,您仅对您所说的正在签名的节点进行签名。

将代码中的行更改为:

XmlNodeList nodeList = xDoc.SelectNodes("//Child1");
Run Code Online (Sandbox Code Playgroud)

到:

XmlNodeList nodeList =
    xDoc.SelectNodes("//Child1/descendant-or-self::node()|//Child1//@*");
Run Code Online (Sandbox Code Playgroud)

意味着我在 child1.xml 中得到以下内容:

<Child1 xmlns:test="http://www.test.com/xades#" Attribute1="c1" Bttribute="c2" Cttribute="c3">&#xD;
    <child11 Attribute11="c11">Element11</child11>&#xD;
  </Child1>
Run Code Online (Sandbox Code Playgroud)

我认为这就是你想要的是否正确?

顺便说一句,更精确的是:

XmlNodeList nodeList =
    xDoc.SelectNodes("//Child1[1]/descendant-or-self::node()|//Child1[1]//@*");
Run Code Online (Sandbox Code Playgroud)

可能有用,因为 xpath 评估可以在到达第一个时停止</Child1>,如果您的实际数据很大,则性能增益可能会很大。