使用数字签名为 XML 文档签名
可以使用 System.Security.Cryptography.Xml 命名空间中的类通过数字签名对 XML 文档或 XML 文档的部分进行签名。使用 XML 数字签名 (XMLDSIG),您可以验证签名后的数据没有被更改。有关 XMLDSIG 标准的更多信息,请参见万维网联盟 (W3C) 建议 XML Signature Syntax and Processing(XML 签名语法和处理)。
此过程中的代码示例演示了如何对整个 XML 文档进行数字签名,以及如何将签名附加到文档中的 <Signature> 元素中。该示例创建一个 RSA 签名密钥,将该密钥添加到安全密钥容器中,然后使用该密钥对 XML 文档进行数字签名。然后可以检索该密钥来验证 XML 数字签名,或使用它对另一个 XML 文档进行签名。
有关如何验证使用此过程创建的 XML 数字签名的信息,请参见 如何:验证 XML 文档的数字签名。
对 XML 文档进行数字签名
-
创建 CspParameters 对象,并指定密钥容器的名称。
C#VBCspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";
-
使用 RSACryptoServiceProvider 类生成一个对称密钥。当您将 CspParameters 对象传递给 RSACryptoServiceProvider 类的构造函数时,该密钥将自动保存到密钥容器中。该密钥将被用来对 XML 文档签名。
C#VBRSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
-
通过从磁盘加载 XML 文件创建 XmlDocument 对象。XmlDocument 对象包含要加密的 XML 元素。
C#VBXmlDocument xmlDoc = new XmlDocument(); // Load an XML file into the XmlDocument object. xmlDoc.PreserveWhitespace = true; xmlDoc.Load("test.xml");
-
创建一个新的 SignedXml 对象,并将 XmlDocument 对象传递给它。
C#VBSignedXml signedXml = new SignedXml(xmlDoc);
-
将签名 RSA 密钥添加到 SignedXml 对象。
C#VBsignedXml.SigningKey = rsaKey;
-
创建说明签名内容的 Reference 对象。若要对整个文档进行签名,请将 Uri 属性设置为 ""。
C#VB// Create a reference to be signed. Reference reference = new Reference(); reference.Uri = "";
-
将 XmlDsigEnvelopedSignatureTransform 对象添加到 Reference 对象中。变换使验证工具可以使用与签名工具所用的相同方式表示 XML 数据。XML 数据可以用不同方式表示,因此这一步对于验证来说至关重要。
C#VBXmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env);
-
将 Reference 对象添加到 SignedXml 对象中。
C#VBsignedXml.AddReference(reference);
-
通过调用 ComputeSignature 方法计算签名。
C#VBsignedXml.ComputeSignature();
-
检索签名(一个 <<Signature>> 元素)的 XML 表示形式,并将它保存到一个新的 XmlElement 对象中。
C#VBXmlElement xmlDigitalSignature = signedXml.GetXml();
-
将元素追加到 XmlDocument 对象中。
C#VBxmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
-
保存文档。
C#VBxmlDoc.Save("test.xml");
此示例假定一个名为 test.xml 的文件与编译的程序在同一目录中。您可以将以下 XML 放入名为 test.xml 的文件中,并将它和此示例一起使用。
<root> <creditcard> <number>19834209</number> <expiry>02/02/2002</expiry> </creditcard> </root>
using System; using System.Security.Cryptography; using System.Security.Cryptography.Xml; using System.Xml; public class SignXML { public static void Main(String[] args) { try { // Create a new CspParameters object to specify // a key container. CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"; // Create a new RSA signing key and save it in the container. RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams); // Create a new XML document. XmlDocument xmlDoc = new XmlDocument(); // Load an XML file into the XmlDocument object. xmlDoc.PreserveWhitespace = true; xmlDoc.Load("test.xml"); // Sign the XML document. SignXml(xmlDoc, rsaKey); Console.WriteLine("XML file signed."); // Save the document. xmlDoc.Save("test.xml"); } catch (Exception e) { Console.WriteLine(e.Message); } } // Sign an XML file. // This document cannot be verified unless the verifying // code has the key with which it was signed. public static void SignXml(XmlDocument xmlDoc, RSA Key) { // Check arguments. if (xmlDoc == null) throw new ArgumentException("xmlDoc"); if (Key == null) throw new ArgumentException("Key"); // Create a SignedXml object. SignedXml signedXml = new SignedXml(xmlDoc); // Add the key to the SignedXml document. signedXml.SigningKey = rsaKey; // Create a reference to be signed. Reference reference = new Reference(); reference.Uri = ""; // Add an enveloped transformation to the reference. XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); // Add the reference to the SignedXml object. signedXml.AddReference(reference); // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation of the signature and save // it to an XmlElement object. XmlElement xmlDigitalSignature = signedXml.GetXml(); // Append the element to the XML document. xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); } }