如何:用 X.509 证书对 XML 元素进行加密

更新:2007 年 11 月

可以使用 System.Security.Cryptography.Xml 命名空间中的类对 XML 文档中的元素进行加密。 XML 加密是交换或存储加密的 XML 数据的标准方法,无需担心数据被轻易读取。 有关 XML 加密标准的更多信息,请参见位于 http://www.w3.org/TR/xmldsig-core/ 上的关于 XML 加密的 WWW 联合会 (W3C) 规范。

可以使用 XML 加密,用包含加密的 XML 数据的 <EncryptedData> 元素替换任何 XML 元素或文档。<EncryptedData> 元素可以包含一些子元素来收入关于加密期间使用的密钥和进程的信息。 XML 加密允许一个文档包含多个加密的元素,并允许多次加密一个元素。 此过程中的代码示例演示了如何创建一个 <EncryptedData> 元素和几个其他子元素,以便以后在解密过程中使用。

此示例使用了两个密钥对一个 XML 元素进行加密。 它使用证书创建工具 (Makecert.exe) 生成了测试 X.509 证书,并将该证书保存到证书存储区中。 然后示例以编程方式检索该证书,并使用它通过 Encrypt 方法对 XML 元素进行加密。 在内部,Encrypt 方法创建一个单独的会话密钥,并用它对 XML 文档进行加密。此方法对会话密钥进行加密,并将它与加密的 XML 一起保存在一个新的 <EncryptedData> 元素中。

若要对 XML 元素进行解密,只需调用 DecryptDocument 方法,此方法将从存储区中自动检索出 X.509 证书,并执行必要的解密。 有关如何对使用此过程加密的 XML 元素进行解密的更多信息,请参见如何:用 X.509 证书对 XML 元素进行解密

此示例适合于以下情形:多个应用程序需要共享加密数据,或者一个应用程序需要在多次运行之间保存加密数据。

用 X.509 证书对 XML 元素进行加密

  1. 使用证书创建工具 (Makecert.exe) 生成测试 X.509 证书,并将它放在本地用户存储区中。 必须生成一个交换密钥,而且此密钥必须是可导出的。运行下面的命令:

    makecert -r -pe -n "CN=XML_ENC_TEST_CERT" -b 01/01/2005 -e 01/01/2010 -sky exchange -ss my
    
  2. 创建 X509Store 对象,将它初始化,以打开当前用户的存储区。

    Dim store As New X509Store(StoreLocation.CurrentUser)
    
    X509Store store = new X509Store(StoreLocation.CurrentUser);
    
  3. 以只读模式打开存储区。

    store.Open(OpenFlags.ReadOnly)
    
    store.Open(OpenFlags.ReadOnly);
    
  4. 用存储区中的所有证书初始化 X509Certificate2Collection

    Dim certCollection As X509Certificate2Collection = store.Certificates
    
    X509Certificate2Collection certCollection = store.Certificates;
    
  5. 依次枚举存储区中的证书,查找具有适当名称的证书。 在此示例中,证书的名称为 "CN=XML_ENC_TEST_CERT"。

    Dim cert As X509Certificate2 = Nothing
    
    ' Loop through each certificate and find the certificate 
    ' with the appropriate name.
    Dim c As X509Certificate2
    For Each c In certCollection
        If c.Subject = "CN=XML_ENC_TEST_CERT" Then
            cert = c
    
            Exit For
        End If
    Next c
    
    X509Certificate2 cert = null;
    
    // Loop through each certificate and find the certificate 
    // with the appropriate name.
    foreach (X509Certificate2 c in certCollection)
    {
        if (c.Subject == "CN=XML_ENC_TEST_CERT")
        {
            cert = c;
    
            break;
        }
    }
    
  6. 找到证书后关闭存储区。

    store.Close()
    
    store.Close();
    
  7. 通过从磁盘加载 XML 文件创建 XmlDocument 对象。 XmlDocument 对象包含要加密的 XML 元素。

    Dim xmlDoc As New XmlDocument()
    
    XmlDocument xmlDoc = new XmlDocument();
    
  8. XmlDocument 对象中找到指定的元素,然后创建一个新的 XmlElement 对象来表示要加密的元素。 在此示例中,"creditcard" 元素要加密。

    Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementToEncryptName)(0)
    
    
    XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
    
  9. 创建 EncryptedXml 类的新实例,并使用它通过 X.509 证书对指定的元素进行加密。 Encrypt 方法将加密的元素作为 EncryptedData 对象返回。

    Dim eXml As New EncryptedXml()
    
    ' Encrypt the element.
    Dim edElement As EncryptedData = eXml.Encrypt(elementToEncrypt, Cert)
    
    EncryptedXml eXml = new EncryptedXml();
    
    // Encrypt the element.
    EncryptedData edElement = eXml.Encrypt(elementToEncrypt, Cert);
    
  10. EncryptedData 元素替换原始 XmlDocument 对象中的元素。

    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
    
    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
    
  11. 保存 XmlDocument 对象。

    xmlDoc.Save("test.xml")
    
    xmlDoc.Save("test.xml");
    

示例

Imports System
Imports System.Xml
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Security.Cryptography.X509Certificates



Module Program

    Sub Main(ByVal args() As String)
        Try
            ' Create an XmlDocument object.
            Dim xmlDoc As New XmlDocument()
            ' Load an XML file into the XmlDocument object.
            xmlDoc.PreserveWhitespace = True
            xmlDoc.Load("test.xml")

            ' Open the X.509 "Current User" store in read only mode.
            Dim store As New X509Store(StoreLocation.CurrentUser)
            store.Open(OpenFlags.ReadOnly)
            ' Place all certificates in an X509Certificate2Collection object.
            Dim certCollection As X509Certificate2Collection = store.Certificates
            Dim cert As X509Certificate2 = Nothing

            ' Loop through each certificate and find the certificate 
            ' with the appropriate name.
            Dim c As X509Certificate2
            For Each c In certCollection
                If c.Subject = "CN=XML_ENC_TEST_CERT" Then
                    cert = c

                    Exit For
                End If
            Next c
            If cert Is Nothing Then
                Throw New CryptographicException("The X.509 certificate could not be found.")
            End If

            ' Close the store.
            store.Close()
            ' Encrypt the "creditcard" element.
            Encrypt(xmlDoc, "creditcard", cert)

            ' Save the XML document.
            xmlDoc.Save("test.xml")
            ' Display the encrypted XML to the console.
            Console.WriteLine("Encrypted XML:")
            Console.WriteLine()
            Console.WriteLine(xmlDoc.OuterXml)

        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try

    End Sub 'Main


    Sub Encrypt(ByVal Doc As XmlDocument, ByVal ElementToEncryptName As String, ByVal Cert As X509Certificate2)
        ' Check the arguments.  
        If Doc Is Nothing Then
            Throw New ArgumentNullException("Doc")
        End If
        If ElementToEncryptName Is Nothing Then
            Throw New ArgumentNullException("ElementToEncrypt")
        End If
        If Cert Is Nothing Then
            Throw New ArgumentNullException("Cert")
        End If
        ''''''''''''''''''''''''''''''''''''''''''''''''
        ' Find the specified element in the XmlDocument
        ' object and create a new XmlElemnt object.
        ''''''''''''''''''''''''''''''''''''''''''''''''
        Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementToEncryptName)(0)

        ' Throw an XmlException if the element was not found.
        If elementToEncrypt Is Nothing Then
            Throw New XmlException("The specified element was not found")
        End If

        ''''''''''''''''''''''''''''''''''''''''''''''''
        ' Create a new instance of the EncryptedXml class 
        ' and use it to encrypt the XmlElement with the 
        ' X.509 Certificate.
        ''''''''''''''''''''''''''''''''''''''''''''''''
        Dim eXml As New EncryptedXml()

        ' Encrypt the element.
        Dim edElement As EncryptedData = eXml.Encrypt(elementToEncrypt, Cert)
        ''''''''''''''''''''''''''''''''''''''''''''''''
        ' Replace the element from the original XmlDocument
        ' object with the EncryptedData element.
        ''''''''''''''''''''''''''''''''''''''''''''''''
        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
    End Sub
End Module
using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            // Create an XmlDocument object.
            XmlDocument xmlDoc = new XmlDocument();

            // Load an XML file into the XmlDocument object.
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load("test.xml");

            // Open the X.509 "Current User" store in read only mode.
            X509Store store = new X509Store(StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);

            // Place all certificates in an X509Certificate2Collection object.
            X509Certificate2Collection certCollection = store.Certificates;

            X509Certificate2 cert = null;

            // Loop through each certificate and find the certificate 
            // with the appropriate name.
            foreach (X509Certificate2 c in certCollection)
            {
                if (c.Subject == "CN=XML_ENC_TEST_CERT")
                {
                    cert = c;

                    break;
                }
            }

            if (cert == null)
            {
                throw new CryptographicException("The X.509 certificate could not be found.");
            }

            // Close the store.
            store.Close();

            // Encrypt the "creditcard" element.
            Encrypt(xmlDoc, "creditcard", cert);

            // Save the XML document.
            xmlDoc.Save("test.xml");

            // Display the encrypted XML to the console.
            Console.WriteLine("Encrypted XML:");
            Console.WriteLine();
            Console.WriteLine(xmlDoc.OuterXml);

        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

    }

    public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, X509Certificate2 Cert)
    {
        // Check the arguments.  
        if (Doc == null)
            throw new ArgumentNullException("Doc");
        if (ElementToEncrypt == null)
            throw new ArgumentNullException("ElementToEncrypt");
        if (Cert == null)
            throw new ArgumentNullException("Cert");

        ////////////////////////////////////////////////
        // Find the specified element in the XmlDocument
        // object and create a new XmlElemnt object.
        ////////////////////////////////////////////////

        XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
        // Throw an XmlException if the element was not found.
        if (elementToEncrypt == null)
        {
            throw new XmlException("The specified element was not found");

        }

        //////////////////////////////////////////////////
        // Create a new instance of the EncryptedXml class 
        // and use it to encrypt the XmlElement with the 
        // X.509 Certificate.
        //////////////////////////////////////////////////

        EncryptedXml eXml = new EncryptedXml();

        // Encrypt the element.
        EncryptedData edElement = eXml.Encrypt(elementToEncrypt, Cert);

        ////////////////////////////////////////////////////
        // Replace the element from the original XmlDocument
        // object with the EncryptedData element.
        ////////////////////////////////////////////////////
        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
    }
}

此示例假定一个名为 "test.xml" 的文件与编译的程序在同一目录中。 它还假定 "test.xml" 包含一个 "creditcard" 元素。 您可以将以下 XML 放入名为 test.xml 的文件中,并将它和此示例一起使用。

<root>
    <creditcard>
        <number>19834209</number>
        <expiry>02/02/2002</expiry>
    </creditcard>
</root>

编译代码

安全性

此示例中使用的 X.509 证书仅用于测试目的。 应用程序应当使用由受信任的证书颁发机构生成的 X.509 证书,或者使用 Microsoft Windows Certificate Server 生成的证书。

请参见

任务

如何:用 X.509 证书对 XML 元素进行解密

参考

System.Security.Cryptography.Xml

其他资源

XML 加密和数字签名