作法:使用非對稱金鑰解密 XML 元素
您可以使用 System.Security.Cryptography.Xml 命名空間中的類別來加密和解密 XML 文件內的項目。 XML 加密是交換或儲存加密 XML 資料的標準方法,不必擔心資料被輕易讀取。 如需 XML 加密標準的詳細資訊,請參閱全球資訊網協會 (W3C) 的建議 XML 簽章語法和處理。
注意
本文中的程式碼適用於 Windows。
此程序中的範例會解密已使用 HOW TO:使用非對稱金鑰加密 XML 項目中所述方法加密的 XML 項目。 其會找出 <EncryptedData
> 項目、解密該項目,然後再以原始純文字 XML 項目取代該項目。
此範例會使用兩個金鑰來解密 XML 項目。 其會從金鑰容器中,擷取先前產生的 RSA 私密金鑰,然後使用 RSA 金鑰來解密儲存在 <EncryptedKey
> 項目之 <EncryptedData
> 項目中的工作階段金鑰。 範例接著會使用工作階段金鑰解密 XML 項目。
這個範例適合多個應用程式必須共用加密資料或應用程式必須在它執行時間之間儲存加密資料的情況。
使用非對稱金鑰解密 XML 項目
建立 CspParameters 物件,並指定金鑰容器的名稱。
CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
使用 RSACryptoServiceProvider 物件從容器擷取先前產生的非對稱金鑰。 當您將 CspParameters 物件傳遞到 RSACryptoServiceProvider 建構函式時,金鑰會自動從金鑰容器擷取。
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
建立新的 EncryptedXml 物件以解密文件。
// Create a new EncryptedXml object. EncryptedXml exml = new EncryptedXml(Doc);
' Create a new EncryptedXml object. Dim exml As New EncryptedXml(Doc)
加入金鑰/名稱對應以將 RSA 金鑰與應該解密之文件中的項目相關聯。 您必須使用與加密文件時所使用金鑰相同的名稱。 請注意,這個名稱與用來識別步驟 1 中所指定金鑰容器中的金鑰名稱不同。
exml.AddKeyNameMapping(KeyName, Alg);
exml.AddKeyNameMapping(KeyName, Alg)
呼叫 DecryptDocument 方法來解密 <
EncryptedData
> 項目。 這個方法會使用 RSA 金鑰來解密工作階段金鑰,並會自動使用工作階段金鑰解密 XML 項目。 其也會自動將 <EncryptedData
> 項目取代為原始的純文字。exml.DecryptDocument();
exml.DecryptDocument()
儲存 XML 文件。
xmlDoc.Save("test.xml");
xmlDoc.Save("test.xml")
範例
這個範例假設名為 test.xml
的檔案已存在於和編譯程式相同的目錄中。 其也假設 test.xml
包含的 XML 項目是使用 HOW TO:使用非對稱金鑰加密 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 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 反組譯工具) 或是藉由在文字編輯器 (例如記事本) 中開啟組件,輕鬆地從組件讀取。
當您使用完密碼編譯金鑰,請從記憶體清除它,方法是將每個位元組設定為零,或呼叫 Managed 密碼編譯類別的 Clear 方法。 偵錯工具有時可以從記憶體讀取密碼編譯金鑰,或是在記憶體位置被分頁至磁碟的情況下從硬碟機讀取。