Procedura: crittografare gli elementi XML con chiavi asimmetriche
È possibile utilizzare le classi dello spazio dei nomi System.Security.Cryptography.Xml per crittografare un elemento all'interno di un documento XML. La crittografia XML è un sistema standard per lo scambio o la memorizzazione di dati XML crittografati che garantisce un'adeguata protezione da letture non autorizzate. Per ulteriori informazioni sulla crittografia XML, vedere la specifica W3C (World Wide Web Consortium) relativa a questo standard all'indirizzo http://www.w3.org/TR/xmldsig-core/ (informazioni in lingua inglese).
È possibile utilizzare la crittografia XML per sostituire qualsiasi elemento o documento XML con un elemento <EncryptedData> contenente i dati XML crittografati. L'elemento <EncryptedData> può contenere anche sottoelementi che includono informazioni sulle chiavi e i processi utilizzati durante la crittografia. La crittografia XML consente di inserire più elementi crittografati all'interno di un documento e di crittografare un elemento più volte. Nell'esempio di codice riportato in questa procedura viene illustrato come creare un elemento <EncryptedData> insieme a diversi altri sottoelementi utilizzabili in un secondo momento durante la decrittografia.
Nell'esempio un elemento XML viene crittografato mediante due chiavi. Una coppia di chiavi pubblica/privata RSA viene generata e quindi salvata in un contenitore di chiavi protetto. Successivamente, viene creata una chiave di sessione separata mediante l'algoritmo AES (Advanced Encryption Standard), noto anche come Rijndael. A questo punto vengono utilizzate, nell'ordine, la chiave di sessione AES per crittografare il documento XML e la chiave pubblica RSA per crittografare la chiave di sessione AES. Infine, la chiave di sessione AES crittografata e i dati XML crittografati vengono salvati nel documento XML all'interno di un nuovo elemento <EncryptedData>.
Per decrittografare l'elemento XML, è necessario richiamare la chiave privata RSA dal contenitore di chiavi, utilizzarla per decrittografare la chiave di sessione, quindi utilizzare quest'ultima per decrittografare il documento. Per ulteriori informazioni su come decrittografare un elemento XML crittografato mediante questa procedura, vedere Procedura: decrittografare gli elementi XML con chiavi asimmetriche.
Questo esempio si riferisce alle situazioni in cui più applicazioni devono condividere dati crittografati o un'applicazione deve salvare i dati crittografati tra un'esecuzione e l'altra.
Per crittografare un elemento XML con una chiave asimmetrica
Creare un oggetto CspParameters e specificare il nome del contenitore di chiavi.
Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
Generare una chiave simmetrica utilizzando la classe RSACryptoServiceProvider. La chiave viene salvata automaticamente nel contenitore di chiavi quando si passa l'oggetto CspParameters al costruttore della classe RSACryptoServiceProvider. Viene utilizzata per crittografare la chiave di sessione AES e può essere recuperata in un secondo momento per decrittografarla.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
Creare un oggetto XmlDocument caricando un file XML dal disco. L'oggetto XmlDocument contiene l'elemento XML da crittografare.
' 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); }
Trovare l'elemento specificato nell'oggetto XmlDocument e creare un nuovo oggetto XmlElement per rappresentare l'elemento da crittografare. In questo esempio viene crittografato l'elemento "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"); }
Creare una nuova chiave di sessione utilizzando la classe RijndaelManaged. Questa chiave verrà utilizzata per crittografare l'elemento XML, quindi sarà a sua volta crittografata e inserita nel documento 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;
Creare una nuova istanza della classe EncryptedXml e utilizzarla per crittografare l'elemento specificato mediante la chiave di sessione. Il metodo EncryptData restituisce l'elemento crittografato come una matrice di byte crittografati.
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);
Costruire un oggetto EncryptedData e inserire al suo interno l'identificatore URL dell'elemento XML crittografato. Tale identificatore indica a coloro che effettueranno la decrittografia che i dati XML contengono un elemento crittografato. È possibile utilizzare il campo XmlEncElementUrl per specificare l'identificatore URL. L'elemento XML in testo non crittografato verrà sostituito da un elemento <EncryptedData> incapsulato dall'oggetto EncryptedData.
Dim edElement As New EncryptedData() edElement.Type = EncryptedXml.XmlEncElementUrl edElement.Id = EncryptionElementID
EncryptedData edElement = new EncryptedData(); edElement.Type = EncryptedXml.XmlEncElementUrl; edElement.Id = EncryptionElementID;
Creare un oggetto EncryptionMethod inizializzato sull'identificatore URL dell'algoritmo di crittografia utilizzato per generare la chiave di sessione. Passare l'oggetto EncryptionMethod alla proprietà EncryptionMethod.
edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
Creare un oggetto EncryptedKey in cui contenere la chiave di sessione crittografata. Crittografare la chiave di sessione, aggiungerla all'oggetto EncryptedKey e immettere un nome della chiave di sessione e l'URL dell'identificatore di chiave.
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);
Creare un nuovo oggetto DataReference che esegua il mapping tra i dati crittografati e una determinata chiave di sessione. Questo passaggio facoltativo consente di specificare in modo semplice che più parti di un documento XML sono state crittografate da una singola chiave.
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);
Aggiungere la chiave crittografata all'oggetto EncryptedData.
edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
Creare un nuovo oggetto KeyInfo per specificare il nome della chiave RSA. Aggiungerla all'oggetto EncryptedData per rendere più semplice l'identificazione della chiave asimmetrica corretta da utilizzare durante la decrittografia della chiave di sessione.
' 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);
Aggiungere i dati dell'elemento crittografato all'oggetto EncryptedData.
edElement.CipherData.CipherValue = encryptedElement
edElement.CipherData.CipherValue = encryptedElement;
Sostituire l'elemento dell'oggetto XmlDocument originale con l'elemento EncryptedData.
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
Salvare l'oggetto XmlDocument.
xmlDoc.Save("test.xml")
xmlDoc.Save("test.xml");
Esempio
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();
}
}
In questo esempio si presuppone che un file denominato "test.xml" si trovi nella stessa directory del programma compilato e che contenga un elemento "creditcard". È possibile inserire i dati XML riportati di seguito in un file denominato test.xml e utilizzarlo con questo esempio.
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
Compilazione del codice
Per compilare l'esempio, è necessario includere un riferimento a System.Security.dll.
Includere gli spazi dei nomi seguenti: System.Xml, System.Security.Cryptography e System.Security.Cryptography.Xml.
Sicurezza
Non memorizzare mai una chiave di crittografia simmetrica né trasferire una chiave simmetrica da un computer all'altro in testo non crittografato. Inoltre, non memorizzare né trasferire mai la chiave privata di una coppia di chiavi asimmetriche in testo non crittografato. Per ulteriori informazioni sulle chiavi di crittografia simmetriche e asimmetriche, vedere Generazione di chiavi per crittografia e decrittografia.
Non incorporare mai una chiave direttamente nel codice sorgente. Le chiavi incorporate possono essere facilmente lette da un assembly attraverso lo strumento Ildasm.exe (disassemblatore MSIL) o aprendo l'assembly in un editor di testo quale Blocco note.
Dopo aver utilizzato una chiave di crittografia, cancellarla dalla memoria impostando ogni byte su zero o chiamando il metodo Clear della classe di crittografia gestita. Le chiavi di crittografia possono talvolta essere lette dalla memoria mediante un debugger o da un disco rigido se la posizione della memoria è paginata su disco.
Vedere anche
Attività
Procedura: decrittografare gli elementi XML con chiavi asimmetriche
Riferimenti
System.Security.Cryptography.Xml