Postupy: Šifrování elementů XML pomocí asymetrických klíčů
K zašifrování elementu dokumentu XML lze použít třídy v oboru názvů System.Security.Cryptography.Xml. Šifrování XML představuje standardní způsob pro předávají nebo ukládaní zašifrovaných dat XML bez obav, že by byla data snadno čitelná. Další informace o standardu šifrování XML naleznete ve specifikaci šifrování XML na webových stránkách konsorcia W3C (World Wide Web Consortium) http://www.w3.org/TR/xmldsig-core/.
Pomocí šifrování XML lze nahradit libovolný element XML nebo dokument XML elementem <EncryptedData>, který obsahuje šifrovaná data XML. Element <EncryptedData> může také obsahovat dílčí elementy, které obsahují informace o klíčích a postupech použitých při šifrování. Šifrování XML umožňuje, aby dokument obsahoval více šifrovaných elementů a umožňuje, aby byl element zašifrován vícekrát. Příklad kódu v tomto postupu ukazuje, jak vytvořit element <EncryptedData> spolu s několika dalšími dílčími elementy, které lze použít později během dešifrování.
V tomto příkladu je šifrován element XML pomocí dvou klíčů. Vygeneruje dvojici RSA veřejný/privátní klíč a uloží tento pár do zabezpečeného kontejneru klíčů. Příklad poté vytvoří samostatný klíč relace pomocí algoritmu AES (Advanced Encryption Standard), rovněž nazývaného algoritmus Rijndael. Příklad používá klíč relace standardu AES k zašifrování dokumentu XML a poté pomocí veřejného klíče RSA zašifruje samotný klíč relace. Nakonec příklad uloží zašifrovaný klíč relace a zašifrovaná data XML do dokumentu XML v rámci nového elementu <EncryptedData>.
K dešifrování elementu XML je třeba načíst z kontejneru klíčů privátní klíč RSA, použít jej k dešifrování klíče relace a potom klíč relace použít k dešifrování dokumentu. Další informace o dešifrování elementu XML, který byl zašifrován pomocí tohoto postupu, naleznete v tématu Postupy: Dešifrování elementů XML pomocí asymetrických klíčů.
Tento příklad je vhodný pro situace, kde je třeba sdílení zašifrovaných dat mezi více aplikacemi nebo pokud aplikace potřebuje uložit zašifrovaná data za běhu.
Postup pro zašifrování elementu XML asymetrickým klíčem
Vytvořte objekt CspParameters a zadejte název kontejneru klíčů.
Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
Vygenerujte symetrický klíč pomocí třídy RSACryptoServiceProvider. Klíč je automaticky uložen do kontejneru klíčů při předání objektu CspParameters konstruktoru třídy RSACryptoServiceProvider. Tento klíč se použije k zašifrování klíče relace (standardu AES) a může být později načten k jeho rozšifrování.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
Vytvořte objekt XmlDocument načtením souboru XML z disku. Objekt XmlDocument obsahuje element XML určený k zašifrování.
' 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 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); }
Nalezněte zadaný element v objektu XmlDocument a vytvořte nový objekt XmlElement představující element, který má být zašifrován. V tomto příkladu je zašifrován element "creditcard".
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
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"); }
Vytvořte nový klíč relace pomocí třídy RijndaelManaged. Tento klíč bude použit k zašifrování elementu XML a potom bude sám zašifrován a umístěn v dokumentu XML.
' Create a 256 bit Rijndael key. sessionKey = New RijndaelManaged() sessionKey.KeySize = 256
// Create a 256 bit Rijndael key. sessionKey = new RijndaelManaged(); sessionKey.KeySize = 256;
Vytvořte novou instanci třídy EncryptedXml a použijte ji k zašifrování daného elementu pomocí klíče relace. Metoda EncryptData vrací šifrovaný element jako pole zašifrovaných bajtů.
Dim eXml As New EncryptedXml() Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, sessionKey, False)
EncryptedXml eXml = new EncryptedXml(); byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
Vytvořte objekt EncryptedData a naplňte jej identifikátorem URL šifrovaného elementu XML. Tento identifikátor URL říká dešifrující straně, že XML obsahuje šifrovaný element. Můžete použít pole XmlEncElementUrl k určení identifikátoru URL. Nešifrovaný element XML bude nahrazen elementem <EncryptedData> zapouzdřeným tímto objektem EncryptedData.
Dim edElement As New EncryptedData() edElement.Type = EncryptedXml.XmlEncElementUrl edElement.Id = EncryptionElementID
EncryptedData edElement = new EncryptedData(); edElement.Type = EncryptedXml.XmlEncElementUrl; edElement.Id = EncryptionElementID;
Vytvořte objekt EncryptionMethod, který je inicializován na identifikátor URL kryptografického algoritmu použitého ke generování klíče relace. Předejte objekt EncryptionMethod vlastnosti EncryptionMethod.
edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
Vytvořte objekt EncryptedKey, který bude obsahovat šifrovaný klíč relace. Zašifrujte klíč relace, přidejte jej do objektu EncryptedKey a zadejte název klíče relace a URL identifikátor klíče.
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)
EncryptedKey ek = new EncryptedKey(); byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false); ek.CipherData = new CipherData(encryptedKey); ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
Vytvořte nový objekt DataReference, který mapuje šifrovaná data na určitý klíč relace. Tento volitelný krok umožní snadno určit, že více částí dokumentu XML bylo šifrováno pomocí jediného klíče.
Dim dRef As New DataReference() ' Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID ' Add the DataReference to the EncryptedKey. ek.AddReference(dRef)
DataReference dRef = new DataReference(); // Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID; // Add the DataReference to the EncryptedKey. ek.AddReference(dRef);
Přidejte šifrovaný klíč do objektu EncryptedData.
edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
Vytvořte nový objekt KeyInfo k zadání názvu klíče RSA. Přidejte jej do objektu EncryptedData. To pomáhá dešifrující straně v identifikaci správného asymetrického klíče při dešifrování klíče relace.
' 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)
// 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);
Přidejte data šifrovaného elementu do objektu EncryptedData.
edElement.CipherData.CipherValue = encryptedElement
edElement.CipherData.CipherValue = encryptedElement;
Nahraďte element z původního objektu XmlDocument elementem EncryptedData.
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
Uložte objekt XmlDocument.
xmlDoc.Save("test.xml")
xmlDoc.Save("test.xml");
Příklad
Imports System
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 encryped 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 'Main
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.
If Doc Is Nothing Then
Throw New ArgumentNullException("Doc")
End If
If EncryptionElement Is Nothing Then
Throw New ArgumentNullException("EncryptionElement")
End If
If EncryptionElementID Is Nothing Then
Throw New ArgumentNullException("EncryptionElementID")
End If
If Alg Is Nothing Then
Throw New ArgumentNullException("Alg")
End If
If KeyName Is Nothing Then
Throw New ArgumentNullException("KeyName")
End If
'//////////////////////////////////////////////
' Find the specified element in the XmlDocument
' object and create a new XmlElemnt 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 RijndaelManaged = 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 a 256 bit Rijndael key.
sessionKey = New RijndaelManaged()
sessionKey.KeySize = 256
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 e
Finally
If Not (sessionKey Is Nothing) Then
sessionKey.Clear()
End If
End Try
End Sub 'Encrypt
Public Shared 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 'Decrypt
End Class 'Program
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);
}
// 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 encryped 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 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");
}
RijndaelManaged 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 a 256 bit Rijndael key.
sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256;
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);
}
catch (Exception e)
{
// re-throw the exception.
throw e;
}
finally
{
if (sessionKey != null)
{
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();
}
}
Tento příklad předpokládá, že soubor s názvem "test.xml" existuje ve stejném adresáři jako Zkompilovaný program. Dále předpokládá, že "test.xml" obsahuje element "creditcard". Následující kód jazyka XML můžete umístit do souboru s názvem test.xml a použít jej v tomto příkladu.
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
Probíhá kompilace kódu
Abyste mohli zkompilovat tento příklad, musíte přidat odkaz na System.Security.dll.
Je potřeba zahrnout následující obory názvů: System.Xml, System.Security.Cryptography a System.Security.Cryptography.Xml
Zabezpečení
Nikdy neukládejte symetrický šifrovací klíč jako prostý text ani nepřenášejte symetrický klíč mezi stroji jako prostý text. Také nikdy neukládejte ani nepřenášejte privátní klíč asymetrického páru klíčů jako prostý text. Další informace o symetrických a asymetrických kryptografických klíčích naleznete v tématu Generování klíčů pro šifrování a dešifrování.
Nikdy nevkládejte klíč přímo do zdrojového kódu. Vložené klíče lze snadno přečíst ze sestavení pomocí Ildasm.exe (MSIL Disassembler) nebo otevřením sestavení v textovém editoru, jako je například Poznámkový blok.
Jakmile přestanete používat kryptografický klíč, vymažte jej z paměti nastavením všech bajtů na nulu nebo voláním metody Clear ze spravované kryptografické třídy. Kryptografické klíče mohou být někdy přečteny z paměti ladicím programem nebo přečteny z pevného disku, pokud je oblast paměti stránkována na disk.
Viz také
Úkoly
Postupy: Dešifrování elementů XML pomocí asymetrických klíčů
Odkaz
System.Security.Cryptography.Xml