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

可以使用 System.Security.Cryptography.Xml 命名空间中的类对 XML 文档内的元素进行加密和解密。 XML 加密是交换或存储加密的 XML 数据的一种标准方式,使用后就无需担心数据被轻易读取。 有关 XML 加密标准的详细信息,请参阅万维网联盟 (W3C) 建议 XML 签名语法和处理

注意

本文中的代码适用于 Windows。

此步骤中的示例对使用如何:用非对称密钥对 XML 元素进行加密中描述的方法进行加密的 XML 元素进行解密。 它找到一个 <EncryptedData> 元素,解密该元素,然后将其替换为原始纯文本 XML 元素。

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

此示例适用于以下情况:多个应用程序必须共享加密数据,或应用程序必须保存其每次运行之间的加密数据。

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

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

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

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

    // Create a new EncryptedXml object.
    EncryptedXml exml = new EncryptedXml(Doc);
    
    ' Create a new EncryptedXml object.
    Dim exml As New EncryptedXml(Doc)
    
  4. 添加一个密钥/名称映射,以便 RSA 密钥与应该进行解密的文档中的元素相关联。 必须使用与加密文档时所用密钥名称相同的名称。 请注意,此名称独立于用来标识在步骤 1 中指定的密钥容器中的密钥名称。

    exml.AddKeyNameMapping(KeyName, Alg);
    
    exml.AddKeyNameMapping(KeyName, Alg)
    
  5. 调用 DecryptDocument 方法以解密 <EncryptedData> 元素。 此方法使用 RSA 密钥来解密会话密钥,并自动使用会话密钥来解密 XML 元素。 它还会自动将 <EncryptedData> 元素替换为原始的纯文本。

    exml.DecryptDocument();
    
    exml.DecryptDocument()
    
  6. 保存 XML 文档。

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

示例

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


using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Runtime.Versioning;

[SupportedOSPlatform("windows")]
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();
    }
}
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.  
        ArgumentNullException.ThrowIfNull(Doc)
        ArgumentNullException.ThrowIfNull(Alg)
        ArgumentNullException.ThrowIfNull(KeyName)

        ' 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

编译代码

.NET 安全性

永远不要以纯文本形式存储对称加密密钥,也不要以纯文本形式在计算机之间传输对称密钥。 此外,绝不存储或传输纯文本形式的非对称密钥的私钥。 有关对称和非对称加密密钥的详细信息,请参阅生成加密和解密的密钥

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

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

另请参阅