Compartir a través de


Cómo: Cifrar elementos XML con claves asimétricas

Actualización: noviembre 2007

Puede utilizar las clases del espacio de nombres System.Security.Cryptography.Xml para cifrar un elemento dentro de un documento XML. El cifrado XML es un medio estándar de intercambiar o almacenar datos XML cifrados, sin preocuparse de que pudiera resultar fácil leer los datos. Para obtener más información sobre el estándar de cifrado XML, vea la especificación de World Wide Web Consortium (W3C) acerca del cifrado XML en http://www.w3.org/TR/xmldsig-core/.

Puede utilizar el cifrado XML para reemplazar cualquier elemento o documento XML con un elemento <EncryptedData> que contenga los datos XML cifrados. El elemento <EncryptedData> también puede contener subelementos que incluyan información sobre las claves y los procesos utilizados durante el cifrado. El cifrado XML permite que un documento contenga varios elementos cifrados, así como cifrar varias veces un mismo elemento. En el ejemplo de código de este procedimiento se muestra cómo crear un elemento <EncryptedData> junto con otros subelementos que se pueden utilizar posteriormente durante el descifrado.

En este ejemplo se cifra un elemento XML mediante dos claves. Se genera un par de claves pública/privada RSA y se guarda en un contenedor de claves seguro. A continuación, en el ejemplo se crea una clave de sesión independiente mediante el algoritmo estándar de cifrado avanzado (AES), también denominado algoritmo de Rijndael. En el ejemplo se utiliza la clave de sesión AES para cifrar el documento XML y después se utiliza la clave pública RSA para cifrar la clave de sesión AES. Finalmente, en el ejemplo se guardan la clave de sesión AES cifrada y los datos XML cifrados en el documento XML dentro de un nuevo elemento <EncryptedData>.

Para descifrar el elemento XML, recupere la clave privada RSA del contenedor de claves, utilícela para descifrar la clave de sesión y utilice ésta para descifrar el documento. Para obtener más información sobre cómo descifrar un elemento XML que se cifró mediante este procedimiento, vea Cómo: Descifrar elementos XML con claves asimétricas.

Este ejemplo resulta adecuado para situaciones en las que varias aplicaciones tienen que compartir datos cifrados o cuando una aplicación debe guardar datos cifrados entre períodos de ejecución.

Para cifrar un elemento XML con una clave asimétrica

  1. Cree un objeto CspParameters y especifique el nombre del contenedor de claves.

    Dim cspParams As New CspParameters()
    cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
    
         CspParameters cspParams = new CspParameters();
            cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
    
  2. Genere una clave simétrica mediante la clase RSACryptoServiceProvider. La clave se guarda automáticamente en el contenedor de claves cuando pasa el objeto CspParameters al constructor de la clase RSACryptoServiceProvider. Esta clave se utilizará para cifrar la clave de sesión AES y se puede recuperar después para descifrarla.

    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
         RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    
  3. Cree un objeto XmlDocument; para ello, cargue un archivo XML de disco. El objeto XmlDocument contiene el elemento XML que se debe cifrar.

    ' 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);
            }
    
  4. Busque el elemento especificado en el objeto XmlDocument y cree un nuevo objeto XmlElement para representar el elemento que desea cifrar. En este ejemplo se cifra el elemento "creditcard".

    Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementToEncryptName)(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");
    
            }
    
  5. Cree una nueva clave de sesión mediante la clase RijndaelManaged. Esta clave cifrará el elemento XML y, a continuación, se cifrará a sí misma y se colocará en el 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;
    
  6. Cree una nueva instancia de la clase EncryptedXml y utilícela para cifrar el elemento especificado mediante la clave de sesión. El método EncryptData devuelve el elemento cifrado como una matriz de bytes cifrados.

    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);
    
  7. Construya un objeto EncryptedData y llénelo con el identificador de dirección URL del elemento XML cifrado. Este identificador de dirección URL permite a la parte descifradora saber que el XML contiene un elemento cifrado. Puede utilizar el campo XmlEncElementUrl para especificar el identificador de dirección URL. El elemento XML de texto sin formato será reemplazado por un elemento <EncrypotedData> encapsulado por este objeto EncryptedData.

    Dim edElement As New EncryptedData()
    edElement.Type = EncryptedXml.XmlEncElementUrl
    edElement.Id = EncryptionElementID
    
             EncryptedData edElement = new EncryptedData();
                edElement.Type = EncryptedXml.XmlEncElementUrl;
                edElement.Id = EncryptionElementID;
    
  8. Cree un objeto EncryptionMethod que se inicialice con el identificador de dirección URL del algoritmo criptográfico utilizado para generar la clave de sesión. Pase el objeto EncryptionMethod a la propiedad EncryptionMethod.

    edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
    
             edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
    
  9. Cree un objeto EncryptedKey para que contenga la clave de sesión cifrada. Cifre la clave de sesión, agréguela al objeto EncryptedKey y escriba un nombre de clave de sesión y la dirección URL del identificador de la clave.

    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);
    
  10. Cree un nuevo objeto DataReference que asigne los datos cifrados a una clave de sesión determinada. Este paso opcional le permite especificar con facilidad que una clave única cifró varias partes de un documento XML.

    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);
    
  11. Agregue la clave cifrada al objeto EncryptedData.

    edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
    
             edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
    
  12. Cree un nuevo objeto KeyInfo para especificar el nombre de la clave RSA. Agréguelo al objeto EncryptedData. Esto ayuda a la parte descifradora a identificar la clave asimétrica que se debe utilizar al descifrar la clave de sesión.

    ' Create a new KeyInfo element.
    edElement.KeyInfo = New KeyInfo()
    
    ' 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 KeyInfo element.
                edElement.KeyInfo = new KeyInfo();
    
                // 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);
    
  13. Agregue los datos de elemento cifrados al objeto EncryptedData.

    edElement.CipherData.CipherValue = encryptedElement
    
             edElement.CipherData.CipherValue = encryptedElement;
    
  14. Reemplace el elemento del objeto XmlDocument original con el elemento EncryptedData.

    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
    
             EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
    
  15. Guarde el objeto XmlDocument.

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

Ejemplo

Imports System
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
        ' 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)

        Catch e As Exception
            Console.WriteLine(e.Message)
        Finally
            ' Clear the RSA key.
            rsaKey.Clear()
        End Try


        Console.ReadLine()

    End Sub


    Sub Encrypt(ByVal Doc As XmlDocument, ByVal ElementToEncryptName 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 ElementToEncryptName Is Nothing Then
            Throw New ArgumentNullException("ElementToEncrypt")
        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(ElementToEncryptName)(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 KeyInfo element.
            edElement.KeyInfo = New KeyInfo()

            ' 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
End Module
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);

        }
        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 KeyInfo element.
            edElement.KeyInfo = new KeyInfo();

            // 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();
            }

        }

    }

}

En este ejemplo se supone que existe un archivo llamado "test.xml" en el mismo directorio que el programa compilado. También se supone que "test.xml" contiene un elemento "creditcard". Puede situar el XML siguiente en un archivo llamado test.xml y utilizarlo con este ejemplo.

<root>
    <creditcard>
        <number>19834209</number>
        <expiry>02/02/2002</expiry>
    </creditcard>
</root>

Compilar el código

Seguridad

No almacene nunca una clave criptográfica simétrica en texto sin formato ni transfiera entre equipos una clave simétrica en texto sin formato. Tampoco almacene ni transfiera nunca la clave privada de un par de claves asimétricas en texto sin formato. Para obtener más información sobre claves criptográficas simétricas y asimétricas, vea Generar claves para cifrar y descifrar.

No incruste nunca una clave directamente en el código fuente. Las claves incrustadas se pueden leer con facilidad de un ensamblado mediante Desensamblador de MSIL (Ildasm.exe) o abriendo el ensamblado con un editor de texto como Bloc de notas.

Cuando haya terminado de usar una clave criptográfica, bórrela de la memoria; para ello, establezca todos los bytes en cero o llame al método Clear de la clase de criptografía administrada. En ocasiones, las claves criptográficas pueden ser leídas de la memoria por un depurador, o bien de una unidad de disco duro si la ubicación de la memoria se pagina en el disco.

Vea también

Tareas

Cómo: Descifrar elementos XML con claves asimétricas

Referencia

System.Security.Cryptography.Xml

Otros recursos

Cifrado XML y firmas digitales