Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Классы в System.Security.Cryptography.Xml пространстве имен можно использовать для шифрования элемента в XML-документе. Шифрование XML — это стандартный способ обмена или хранения зашифрованных XML-данных, не беспокоясь о том, что данные легко считываются. Дополнительные сведения о стандарте шифрования XML см. в спецификации консорциума W3C для XML-шифрования, расположенного по адресу https://www.w3.org/TR/xmldsig-core/.
Шифрование XML можно использовать для замены любого XML-элемента или документа элементом <EncryptedData> , содержащим зашифрованные XML-данные. Элемент <EncryptedData> также может содержать вложенные элементы, содержащие сведения о ключах и процессах, используемых во время шифрования. Xml-шифрование позволяет документу содержать несколько зашифрованных элементов и позволяет шифровать элемент несколько раз. В примере кода в этой процедуре показано, как создать <EncryptedData> элемент вместе с несколькими другими вложенными элементами, которые можно использовать позже во время расшифровки.
В этом примере шифруется XML-элемент с помощью двух ключей. Он создает пару открытого и закрытого ключа RSA и сохраняет пару ключей в контейнер безопасного ключа. Затем в примере создается отдельный ключ сеанса с помощью алгоритма расширенного шифрования (AES). В примере используется ключ сеанса AES для шифрования XML-документа, а затем используется открытый ключ RSA для шифрования ключа сеанса AES. Наконец, в примере сохраняется зашифрованный ключ сеанса AES и зашифрованные XML-данные в XML-документ в новом <EncryptedData> элементе.
Чтобы расшифровать XML-элемент, вы получите закрытый ключ RSA из контейнера ключей, используйте его для расшифровки ключа сеанса, а затем используйте ключ сеанса для расшифровки документа. Дополнительные сведения о расшифровке XML-элемента, зашифрованного с помощью этой процедуры, см. в статье "Практическое руководство. Расшифровка 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 класса. Этот ключ будет использоваться для шифрования ключа сеанса AES и может быть получен позже для расшифровки.
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);Dim rsaKey As New RSACryptoServiceProvider(cspParams)XmlDocument Создайте объект, загрузив XML-файл с диска. Объект XmlDocument содержит XML-элемент для шифрования.
// 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); }' 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Найдите указанный элемент в объекте XmlDocument и создайте новый XmlElement объект для представления элемента, который требуется зашифровать. В этом примере
"creditcard"элемент шифруется.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"); }Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(EncryptionElement)(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Создайте новый ключ сеанса Aes с помощью класса. Этот ключ шифрует XML-элемент, а затем шифруется и помещается в XML-документ.
// Create an AES key. sessionKey = Aes.Create();' Create an AES key. sessionKey = Aes.Create()Создайте новый экземпляр класса и используйте его для шифрования указанного EncryptedXml элемента с помощью ключа сеанса. Метод EncryptData возвращает зашифрованный элемент в виде массива зашифрованных байтов.
EncryptedXml eXml = new EncryptedXml(); byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);Dim eXml As New EncryptedXml() Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, sessionKey, False)EncryptedData Создайте объект и заполните его идентификатором URL-адреса зашифрованного XML-элемента. Этот идентификатор URL-адреса позволяет расшифровывающей стороне определить, что XML-документ содержит зашифрованный элемент. Поле XmlEncElementUrl можно использовать для указания идентификатора URL. XML-элемент открытого текста будет заменен элементом
<EncryptedData>, который инкапсулирован этим EncryptedData объектом.EncryptedData edElement = new EncryptedData(); edElement.Type = EncryptedXml.XmlEncElementUrl; edElement.Id = EncryptionElementID;Dim edElement As New EncryptedData() edElement.Type = EncryptedXml.XmlEncElementUrl edElement.Id = EncryptionElementIDEncryptionMethod Создайте объект, инициализируемый идентификатором URL-адреса криптографического алгоритма, используемого для создания ключа сеанса. EncryptionMethod Передайте объект свойствуEncryptionMethod.
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)Создайте объект, EncryptedKey содержащий зашифрованный ключ сеанса. Зашифруйте ключ сеанса, добавьте его в EncryptedKey объект и введите имя ключа сеанса и URL-адрес идентификатора ключа.
EncryptedKey ek = new EncryptedKey(); byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false); ek.CipherData = new CipherData(encryptedKey); ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);Dim ek As New EncryptedKey() Dim encryptedKey As Byte() = EncryptedXml.EncryptKey(sessionKey.Key, Alg, False) ek.CipherData = New CipherData(encryptedKey) ek.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncRSA15Url)Создайте объект DataReference , который сопоставляет зашифрованные данные с определенным ключом сеанса. Этот необязательный шаг позволяет легко указать, что несколько частей XML-документа были зашифрованы одним ключом.
DataReference dRef = new DataReference(); // Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID; // Add the DataReference to the EncryptedKey. ek.AddReference(dRef);Dim dRef As New DataReference() ' Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID ' Add the DataReference to the EncryptedKey. ek.AddReference(dRef)Добавьте зашифрованный ключ в EncryptedData объект.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))Создайте новый KeyInfo объект, чтобы указать имя ключа RSA. Добавьте его в EncryptedData объект. Это помогает стороне, выполняющей расшифровку, определить правильный асимметричный ключ для использования при расшифровке ключа сеанса.
// Create a new KeyInfoName element. KeyInfoName kin = new KeyInfoName(); // Specify a name for the key. kin.Value = KeyName; // Add the KeyInfoName element to the // EncryptedKey object. ek.KeyInfo.AddClause(kin);' Create a new KeyInfoName element. Dim kin As New KeyInfoName() ' Specify a name for the key. kin.Value = KeyName ' Add the KeyInfoName element to the ' EncryptedKey object. ek.KeyInfo.AddClause(kin)Добавьте зашифрованные данные элемента в EncryptedData объект.
edElement.CipherData.CipherValue = encryptedElement;edElement.CipherData.CipherValue = encryptedElementЗамените элемент из исходного XmlDocument объекта элементом EncryptedData .
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)Сохраните XmlDocument объект.
xmlDoc.Save("test.xml");xmlDoc.Save("test.xml")
Пример
В этом примере предполагается, что файл с именем "test.xml" существует в том же каталоге, что и скомпилированная программа. Кроме того, предполагается, что "test.xml" содержит "creditcard" элемент. Можно поместить следующий XML в файл под названием test.xml и использовать его с этим примером.
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
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);
}
// Create a new CspParameters object to specify
// a key container.
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
// Create a new RSA key and save it in the container. This key will encrypt
// a symmetric key, which will then be encrypted in the XML document.
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
try
{
// Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", "EncryptedElement1", rsaKey, "rsaKey");
// 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);
Decrypt(xmlDoc, rsaKey, "rsaKey");
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 Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
////////////////////////////////////////////////
// Find the specified element in the XmlDocument
// object and create a new XmlElement 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");
}
Aes? sessionKey = null;
try
{
//////////////////////////////////////////////////
// Create a new instance of the EncryptedXml class
// and use it to encrypt the XmlElement with the
// a new random symmetric key.
//////////////////////////////////////////////////
// Create an AES key.
sessionKey = Aes.Create();
EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
////////////////////////////////////////////////
// Construct an EncryptedData object and populate
// it with the desired encryption information.
////////////////////////////////////////////////
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
// Create an EncryptionMethod element so that the
// receiver knows which algorithm to use for decryption.
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
// Encrypt the session key and add it to an EncryptedKey element.
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
// Create a new DataReference element
// for the KeyInfo element. This optional
// element specifies which EncryptedData
// uses this key. An XML document can have
// multiple EncryptedData elements that use
// different keys.
DataReference dRef = new DataReference();
// Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID;
// Add the DataReference to the EncryptedKey.
ek.AddReference(dRef);
// Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Set the KeyInfo element to specify the
// name of the RSA key.
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Specify a name for the key.
kin.Value = KeyName;
// Add the KeyInfoName element to the
// EncryptedKey object.
ek.KeyInfo.AddClause(kin);
// Add the encrypted element data to the
// EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
////////////////////////////////////////////////////
// Replace the element from the original XmlDocument
// object with the EncryptedData element.
////////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
finally
{
sessionKey?.Clear();
}
}
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
Class Program
Shared 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
' Create a new CspParameters object to specify
' a key container.
Dim cspParams As New CspParameters()
cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
' Create a new RSA key and save it in the container. This key will encrypt
' a symmetric key, which will then be encrypted in the XML document.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
Try
' Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", "EncryptedElement1", rsaKey, "rsaKey")
' 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)
Decrypt(xmlDoc, rsaKey, "rsaKey")
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
Public Shared Sub Encrypt(ByVal Doc As XmlDocument, ByVal EncryptionElement As String, ByVal EncryptionElementID As String, ByVal Alg As RSA, ByVal KeyName As String)
' Check the arguments.
ArgumentNullException.ThrowIfNull(Doc)
ArgumentNullException.ThrowIfNull(EncryptionElement)
ArgumentNullException.ThrowIfNull(EncryptionElementID)
ArgumentNullException.ThrowIfNull(Alg)
ArgumentNullException.ThrowIfNull(KeyName)
'//////////////////////////////////////////////
' Find the specified element in the XmlDocument
' object and create a new XmlElement object.
'//////////////////////////////////////////////
Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(EncryptionElement)(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
Dim sessionKey As Aes = Nothing
Try
'////////////////////////////////////////////////
' Create a new instance of the EncryptedXml class
' and use it to encrypt the XmlElement with the
' a new random symmetric key.
'////////////////////////////////////////////////
' Create an AES key.
sessionKey = Aes.Create()
Dim eXml As New EncryptedXml()
Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, sessionKey, False)
'//////////////////////////////////////////////
' Construct an EncryptedData object and populate
' it with the desired encryption information.
'//////////////////////////////////////////////
Dim edElement As New EncryptedData()
edElement.Type = EncryptedXml.XmlEncElementUrl
edElement.Id = EncryptionElementID
' Create an EncryptionMethod element so that the
' receiver knows which algorithm to use for decryption.
edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
' Encrypt the session key and add it to an EncryptedKey element.
Dim ek As New EncryptedKey()
Dim encryptedKey As Byte() = EncryptedXml.EncryptKey(sessionKey.Key, Alg, False)
ek.CipherData = New CipherData(encryptedKey)
ek.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncRSA15Url)
' Create a new DataReference element
' for the KeyInfo element. This optional
' element specifies which EncryptedData
' uses this key. An XML document can have
' multiple EncryptedData elements that use
' different keys.
Dim dRef As New DataReference()
' Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID
' Add the DataReference to the EncryptedKey.
ek.AddReference(dRef)
' Add the encrypted key to the
' EncryptedData object.
edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
' Set the KeyInfo element to specify the
' name of the RSA key.
' Create a new KeyInfoName element.
Dim kin As New KeyInfoName()
' Specify a name for the key.
kin.Value = KeyName
' Add the KeyInfoName element to the
' EncryptedKey object.
ek.KeyInfo.AddClause(kin)
' Add the encrypted element data to the
' EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement
'//////////////////////////////////////////////////
' Replace the element from the original XmlDocument
' object with the EncryptedData element.
'//////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
Catch e As Exception
' re-throw the exception.
Throw
Finally
If Not (sessionKey Is Nothing) Then
sessionKey.Clear()
End If
End Try
End Sub
Public Shared 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 Class
Компиляция программы
- В проекте, который предназначен для .NET Framework, добавьте ссылку на
System.Security.dll. - В проекте, который предназначен для .NET Core или .NET 5, установите пакет NuGet System.Security.Cryptography.Xml.
- Включите следующие пространства имен: System.Xml, System.Security.Cryptographyи System.Security.Cryptography.Xml.
Безопасность .NET
Никогда не храните симметричный криптографический ключ в виде обычного текста и не передавайте симметричный ключ между компьютерами в открытом виде. Кроме того, никогда не храните или не передавайте закрытый ключ асимметричной пары ключей в незашифрованном виде. Дополнительные сведения о симметричных и асимметричных криптографических ключах см. в разделе "Создание ключей для шифрования и расшифровки".
Подсказка
Для разработки используйте диспетчер секретов для безопасного хранилища секретов. В рабочей среде рассмотрите такой продукт, как Azure Key Vault.
Никогда не внедряйте ключ непосредственно в исходный код. Внедренные ключи можно легко считывать из сборки с помощью Ildasm.exe (IL Disassembler) или открытия сборки в текстовом редакторе, например Блокнот.
Когда вы закончите использовать криптографический ключ, очистите его от памяти, задав каждому байту значение нулю или вызвав Clear метод управляемого класса криптографии. Криптографические ключи иногда можно считывать из памяти отладчиком или считывать с жесткого диска, если расположение памяти отображается на диск.