如何:用非对称密钥对 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 元素替换该元素。

此示例使用了两个密钥对一个 XML 元素进行解密。 它从密钥容器中检索出先前生成的 RSA 私钥,然后用该 RSA 密钥对存储在 <EncryptedData> 元素的 <EncryptedKey> 元素中的会话密钥进行解密。 然后该示例使用该会话密钥对 XML 元素进行解密。

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

用非对称密钥对 XML 元素进行解密

  1. 创建 CspParameters 对象,并指定密钥容器的名称。

    Dim cspParams As New CspParameters()
    cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
    
         CspParameters cspParams = new CspParameters();
            cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
    
  2. 使用 RSACryptoServiceProvider 对象从容器中检索先前生成的非对称密钥。 当您将 CspParameters 对象传递给 RSACryptoServiceProvider 对象的构造函数时,该密钥将自动从密钥容器中检索出来。

    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
         RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    
  3. 创建新的 EncryptedXml 对象以对文档进行解密。

    Dim xmlDoc As New XmlDocument()
    
    ' Load an XML file into the XmlDocument object.
    Try
        xmlDoc.PreserveWhitespace = True
        xmlDoc.Load("test.xml")
    Catch e As Exception
        Console.WriteLine(e.Message)
    End Try
    
         XmlDocument xmlDoc = new XmlDocument();
    
            // Load an XML file into the XmlDocument object.
            try
            {
                xmlDoc.PreserveWhitespace = true;
                xmlDoc.Load("test.xml");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
    
  4. 添加密钥/名称映射,以将 RSA 密钥与要解密的文档中的元素关联起来。 用于密钥的名称必须与对文档加密时使用的名称相同。 请注意,此名称不同于用来标识步骤 1 中指定的密钥容器中的密钥的名称。

    ' Create a new EncryptedXml object.
    Dim exml As New EncryptedXml(Doc)
    
         // Create a new EncryptedXml object.
            EncryptedXml exml = new EncryptedXml(Doc);
    
  5. 调用 DecryptDocument 方法对 <EncryptedData> 元素进行解密。 此方法使用 RSA 密钥对会话密钥进行解密,然后自动使用该会话密钥对 XML 文档进行解密。 它还用原始纯文本自动替换 <EncryptedData> 元素。

    exml.AddKeyNameMapping(KeyName, Alg)
    
         exml.AddKeyNameMapping(KeyName, Alg);
    
  6. 保存 XML 文档。

    exml.DecryptDocument()
    
         exml.DecryptDocument();
    

示例

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



Module Program

    Sub Main(ByVal args() As String)

        ' Create an XmlDocument object.
        Dim xmlDoc As New XmlDocument()

        ' Load an XML file into the XmlDocument object.
        Try
            xmlDoc.PreserveWhitespace = True
            xmlDoc.Load("test.xml")
        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try
        Dim cspParams As New CspParameters()
        cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
        ' Get the RSA key from the key container.  This key will decrypt 
        ' a symmetric key that was imbedded in the XML document. 
        Dim rsaKey As New RSACryptoServiceProvider(cspParams)
        Try

            ' Decrypt the elements.
            Decrypt(xmlDoc, rsaKey, "rsaKey")

            ' Save the XML document.
            xmlDoc.Save("test.xml")
            ' Display the encrypted XML to the console.
            Console.WriteLine()
            Console.WriteLine("Decrypted XML:")
            Console.WriteLine()
            Console.WriteLine(xmlDoc.OuterXml)
        Catch e As Exception
            Console.WriteLine(e.Message)
        Finally
            ' Clear the RSA key.
            rsaKey.Clear()
        End Try


        Console.ReadLine()

    End Sub



    Sub Decrypt(ByVal Doc As XmlDocument, ByVal Alg As RSA, ByVal KeyName As String)
        ' Check the arguments.  
        If Doc Is Nothing Then
            Throw New ArgumentNullException("Doc")
        End If
        If Alg Is Nothing Then
            Throw New ArgumentNullException("Alg")
        End If
        If KeyName Is Nothing Then
            Throw New ArgumentNullException("KeyName")
        End If 
        ' Create a new EncryptedXml object.
        Dim exml As New EncryptedXml(Doc)
        ' Add a key-name mapping.
        ' This method can only decrypt documents
        ' that present the specified key name.
        exml.AddKeyNameMapping(KeyName, Alg)
        ' Decrypt the element.
        exml.DecryptDocument()
    End Sub
End Module

using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

class Program
{
    static void Main(string[] args)
    {

        // Create an XmlDocument object.
        XmlDocument xmlDoc = new XmlDocument();

        // Load an XML file into the XmlDocument object.
        try
        {
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load("test.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = "XML_ENC_RSA_KEY";

        // Get the RSA key from the key container.  This key will decrypt
        // a symmetric key that was imbedded in the XML document.
        RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);

        try
        {

            // Decrypt the elements.
            Decrypt(xmlDoc, rsaKey, "rsaKey");

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

            // Display the encrypted XML to the console.
            Console.WriteLine();
            Console.WriteLine("Decrypted XML:");
            Console.WriteLine();
            Console.WriteLine(xmlDoc.OuterXml);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            // Clear the RSA key.
            rsaKey.Clear();
        }


        Console.ReadLine();


    }

    public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
    {
        // Check the arguments.
        if (Doc == null)
            throw new ArgumentNullException("Doc");
        if (Alg == null)
            throw new ArgumentNullException("Alg");
        if (KeyName == null)
            throw new ArgumentNullException("KeyName");
        // Create a new EncryptedXml object.
        EncryptedXml exml = new EncryptedXml(Doc);

        // Add a key-name mapping.
        // This method can only decrypt documents
        // that present the specified key name.
        exml.AddKeyNameMapping(KeyName, Alg);

        // Decrypt the element.
        exml.DecryptDocument();

    }

}

此示例假定一个名为 "test.xml" 的文件与编译的程序在同一目录中。 它还假定 "test.xml" 包含使用 如何:用非对称密钥对 XML 元素进行加密 中描述的技术加密的 XML 元素。

编译代码

安全性

不要以纯文本格式存储对称加密密钥,也不要用纯文本在计算机之间传输对称密钥。 另外,不要用纯文本存储或传输非对称密钥对的私钥。 有关对称和非对称加密密钥的更多信息,请参见 生成加密和解密的密钥

不要将密钥直接嵌入到源代码中。 可以通过使用 MSIL 反汇编程序 (Ildasm.exe),或通过在诸如记事本的文本编辑器中打开程序集,从程序集轻松读取嵌入的密钥。

加密密钥使用完以后,请通过将每个字节设置为零,或通过调用托管密码类的 Clear 方法,将它从内存中清除。 加密密钥有时可以被调试器从内存读取或从硬盘读取(如果内存位置被分页到磁盘)。

请参见

任务

如何:用非对称密钥对 XML 元素进行加密

参考

System.Security.Cryptography.Xml

其他资源

XML 加密和数字签名