可以使用命名空间中的 System.Security.Cryptography.Xml 类使用数字签名对 XML 文档或 XML 文档的一部分进行签名。 XML 数字签名(XMLDSIG)允许验证数据在签名后未更改。 有关 XMLDSIG 标准的详细信息,请参阅万维网联盟 (W3C) 建议 的 XML 签名语法和处理。
注释
本文中的代码适用于 Windows。
此过程中的代码示例演示如何对整个 XML 文档进行数字签名,以及如何将签名附加到元素中的 <Signature> 文档。 该示例创建 RSA 签名密钥,将密钥添加到安全密钥容器,然后使用密钥对 XML 文档进行数字签名。 然后,可以检索密钥来验证 XML 数字签名,或者可用于对另一个 XML 文档进行签名。
有关如何验证使用此过程创建的 XML 数字签名的信息,请参阅 如何:验证 XML 文档的数字签名。
对 XML 文档进行数字签名
创建对象 CspParameters 并指定密钥容器的名称。
CspParameters cspParams = new() { KeyContainerName = "XML_DSIG_RSA_KEY" };Dim cspParams As New CspParameters With { .KeyContainerName = "XML_DSIG_RSA_KEY" }使用 RSACryptoServiceProvider 类生成非对称密钥。 将对象传递给 CspParameters 类的 RSACryptoServiceProvider 构造函数时,密钥会自动保存到密钥容器。 此密钥将用于对 XML 文档进行签名。
RSACryptoServiceProvider rsaKey = new(cspParams);Dim rsaKey As New RSACryptoServiceProvider(cspParams)XmlDocument通过从磁盘加载 XML 文件来创建对象。 该 XmlDocument 对象包含要加密的 XML 元素。
XmlDocument xmlDoc = new() { // Load an XML file into the XmlDocument object. PreserveWhitespace = true }; xmlDoc.Load("test.xml");' Load an XML file into the XmlDocument object. Dim xmlDoc As New XmlDocument With { .PreserveWhitespace = True } xmlDoc.Load("test.xml")创建一个新的 SignedXml 对象,并将 XmlDocument 对象传递给它。
SignedXml signedXml = new(xmlDoc) {Dim signedXml As New SignedXml(xmlDoc)将签名 RSA 密钥添加到 SignedXml 对象。
SigningKey = rsaKey };signedXml.SigningKey = rsaKey创建一个描述要签名的Reference对象。 若要对整个文档进行签名,请将 Uri 属性设置为
"".// Create a reference to be signed. Reference reference = new() { Uri = "" };' Create a reference to be signed. Dim reference As New Reference() reference.Uri = ""将对象 XmlDsigEnvelopedSignatureTransform 添加到 Reference 对象。 转换允许验证程序以与签名者使用的相同方式表示 XML 数据。 XML 数据可以以不同的方式表示,因此此步骤对于验证至关重要。
XmlDsigEnvelopedSignatureTransform env = new(); reference.AddTransform(env);Dim env As New XmlDsigEnvelopedSignatureTransform() reference.AddTransform(env)将 Reference 对象添加到 SignedXml 对象。
signedXml.AddReference(reference);signedXml.AddReference(reference)通过调用 ComputeSignature 方法计算签名。
signedXml.ComputeSignature();signedXml.ComputeSignature()检索签名的 XML 表示形式(元素 <
Signature> ),并将其保存到新 XmlElement 对象。XmlElement xmlDigitalSignature = signedXml.GetXml();Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()将元素追加到 XmlDocument 对象。
xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))保存文档。
xmlDoc.Save("test.xml");xmlDoc.Save("test.xml")
示例
此示例假定命名 test.xml 的文件与编译的程序位于同一目录中。 可以将以下 XML 放入一个名为test.xml 的文件中,并将其与此示例一起使用。
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
using System;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;
[SupportedOSPlatform("Windows")]
public class SignXML
{
public static void Main(String[] args)
{
try
{
// Create a new CspParameters object to specify
// a key container.
CspParameters cspParams = new()
{
KeyContainerName = "XML_DSIG_RSA_KEY"
};
// Create a new RSA signing key and save it in the container.
RSACryptoServiceProvider rsaKey = new(cspParams);
// Create a new XML document.
XmlDocument xmlDoc = new()
{
// Load an XML file into the XmlDocument object.
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 rsaKey)
{
// Check arguments.
if (xmlDoc == null)
throw new ArgumentException(null, nameof(xmlDoc));
if (rsaKey == null)
throw new ArgumentException(null, nameof(rsaKey));
// Create a SignedXml object.
SignedXml signedXml = new(xmlDoc)
{
// Add the key to the SignedXml document.
SigningKey = rsaKey
};
// Create a reference to be signed.
Reference reference = new()
{
Uri = ""
};
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new();
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));
}
}
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Xml
Module SignXML
Sub Main(ByVal args() As String)
Try
' Create a new CspParameters object to specify
' a key container.
Dim cspParams As New CspParameters With {
.KeyContainerName = "XML_DSIG_RSA_KEY"
}
' Create a new RSA signing key and save it in the container.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
' Create a new XML document.
' Load an XML file into the XmlDocument object.
Dim xmlDoc As New XmlDocument With {
.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 e As Exception
Console.WriteLine(e.Message)
End Try
End Sub
' Sign an XML file.
' This document cannot be verified unless the verifying
' code has the key with which it was signed.
Sub SignXml(ByVal xmlDoc As XmlDocument, ByVal rsaKey As RSA)
' Check arguments.
If xmlDoc Is Nothing Then
Throw New ArgumentException(
"The XML doc cannot be nothing.", NameOf(xmlDoc))
End If
If rsaKey Is Nothing Then
Throw New ArgumentException(
"The RSA key cannot be nothing.", NameOf(rsaKey))
End If
' Create a SignedXml object.
Dim signedXml As New SignedXml(xmlDoc)
' Add the key to the SignedXml document.
signedXml.SigningKey = rsaKey
' Create a reference to be signed.
Dim reference As New Reference()
reference.Uri = ""
' Add an enveloped transformation to the reference.
Dim env As 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.
Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
' Append the element to the XML document.
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
End Sub
End Module
编译代码
在面向 .NET Framework 的项目中,添加对
System.Security.dll的引用。在面向 .NET Core 或 .NET 5 的项目中,安装 NuGet 包 System.Security.Cryptography.Xml。
包括以下命名空间: System.Xml、 System.Security.Cryptography和 System.Security.Cryptography.Xml。
.NET 安全性
切勿以纯文本方式存储或传输非对称密钥对的私钥。 有关对称和非对称加密密钥的详细信息,请参阅 生成用于加密和解密的密钥。
切勿直接将私钥嵌入源代码中。 可以通过使用 Ildasm.exe(IL 反汇编程序) 或在文本编辑器(如记事本)中打开程序集,轻松读取嵌入的键。