Mengenkripsi elemen XML dengan kunci asimetris

Anda dapat menggunakan kelas di System.Security.Cryptography.Xml namespace layanan untuk mengenkripsi dan elemen dalam dokumen XML. Enkripsi XML adalah cara standar untuk bertukar atau menyimpan data XML terenkripsi, tanpa khawatir tentang data yang mudah dibaca. Untuk informasi selengkapnya tentang standar Enkripsi XML, lihat spesifikasi World Wide Web Consortium (W3C) untuk Enkripsi XML yang terletak di https://www.w3.org/TR/xmldsig-core/.

Anda bisa menggunakan Enkripsi XML untuk mengganti elemen atau dokumen XML apa pun dengan <EncryptedData> elemen yang berisi data XML terenkripsi. Elemen <EncryptedData> ini juga dapat berisi sub elemen yang menyertakan informasi tentang kunci dan proses yang digunakan selama enkripsi. Enkripsi XML memungkinkan dokumen berisi beberapa elemen terenkripsi dan memungkinkan elemen dienkripsi beberapa kali. Contoh kode dalam prosedur ini menunjukkan cara membuat elemen <EncryptedData> bersama dengan beberapa sub elemen lain yang dapat Anda gunakan nanti selama dekripsi.

Contoh ini mengenkripsi elemen XML menggunakan dua kunci. Ini menghasilkan pasangan kunci publik/privat RSA dan menyimpan pasangan kunci ke kontainer kunci aman. Contoh kemudian membuat kunci sesi terpisah menggunakan algoritma Standar Enkripsi Lanjutan (AES). Contohnya menggunakan kunci sesi AES untuk mengenkripsi dokumen XML lalu menggunakan kunci publik RSA untuk mengenkripsi kunci sesi AES. Terakhir, contoh menyimpan kunci sesi AES terenkripsi dan data XML terenkripsi ke dokumen XML dalam elemen <EncryptedData> baru.

Untuk mendekripsi elemen XML, Anda mengambil kunci privat RSA dari kontainer kunci, menggunakannya untuk mendekripsi kunci sesi, lalu menggunakan kunci sesi untuk mendekripsi dokumen. Untuk informasi selengkapnya tentang cara mendekripsi elemen XML yang dienkripsi menggunakan prosedur ini, lihat Cara: Mendekripsi Elemen XML dengan Kunci Asimetris.

Contoh ini sesuai untuk situasi di mana beberapa aplikasi perlu berbagi data terenkripsi atau di mana aplikasi perlu menyimpan data terenkripsi antara waktu berjalannya.

Untuk mengenkripsi elemen XML dengan kunci asimetris

  1. Buat objek CspParameters dan tentukan nama kontainer kunci.

    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
    
    Dim cspParams As New CspParameters()
    cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
    
  2. Buat kunci asimetris menggunakan kelas RSACryptoServiceProvider. Kunci secara otomatis disimpan ke kontainer kunci saat Anda meneruskan objek CspParameters ke konstruktor kelas RSACryptoServiceProvider. Kunci ini akan digunakan untuk mengenkripsi kunci sesi AES dan dapat diambil nanti untuk mendekripsinya.

    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    
    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
  3. Buat sebuah objek XmlDocument dengan memuat file XML dari disk. Objek XmlDocument berisi elemen XML untuk dienkripsi.

    // 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
    
  4. Temukan elemen yang ditentukan dalam XmlDocument objek dan buat XmlElement objek baru untuk mewakili elemen yang ingin Anda enkripsi. Dalam contoh ini, "creditcard" elemen dienkripsi.

    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
    
  5. Buat kunci sesi baru menggunakan kelas Aes. Kunci ini akan mengenkripsi elemen XML, lalu dienkripsi sendiri dan ditempatkan dalam dokumen XML.

    // Create an AES key.
    sessionKey = Aes.Create();
    
    ' Create an AES key.
    sessionKey = Aes.Create()
    
  6. Buat instans baru kelas EncryptedXml dan gunakan untuk mengenkripsi elemen yang ditentukan menggunakan kunci sesi. Metode EncryptData mengembalikan elemen terenkripsi sebagai array byte terenkripsi.

    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)
    
  7. Buat objek EncryptedData dan isi dengan pengidentifikasi URL elemen XML terenkripsi. Pengidentifikasi URL ini memungkinkan pihak yang mendekripsi mengetahui bahwa XML berisi elemen terenkripsi. Anda dapat menggunakan bidang XmlEncElementUrl untuk menentukan pengidentifikasi URL. Elemen XML teks biasa akan digantikan oleh elemen <EncryptedData> yang dienkapsulasi oleh objek EncryptedData ini.

    EncryptedData edElement = new EncryptedData();
    edElement.Type = EncryptedXml.XmlEncElementUrl;
    edElement.Id = EncryptionElementID;
    
    Dim edElement As New EncryptedData()
    edElement.Type = EncryptedXml.XmlEncElementUrl
    edElement.Id = EncryptionElementID
    
  8. Buat objek EncryptionMethod yang diinisialisasi ke pengidentifikasi URL algoritma kriptografi yang digunakan untuk menghasilkan kunci sesi. Teruskan objek EncryptionMethod ke properti EncryptionMethod.

    edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
    
    edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
    
  9. Buat objek EncryptedKey untuk memuat kunci sesi terenkripsi. Enkripsi kunci sesi, tambahkan ke objek EncryptedKey, dan masukkan nama kunci sesi dan URL pengidentifikasi kunci.

    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)
    
  10. Buat objek DataReference baru yang memetakan data terenkripsi ke kunci sesi tertentu. Langkah opsional ini memungkinkan Anda untuk dengan mudah menentukan bahwa beberapa bagian dokumen XML dienkripsi oleh satu kunci.

    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)
    
  11. Tambahkan kunci terenkripsi ke objek EncryptedData.

    edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
    
    edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
    
  12. Buat objek KeyInfo baru untuk menentukan nama kunci RSA. Tambahkan ke objek EncryptedData. Ini membantu pihak yang mendekripsi mengidentifikasi kunci asimetris yang benar untuk digunakan saat mendekripsi kunci sesi.

    
    // 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)
    
  13. Tambahkan data elemen terenkripsi ke objek EncryptedData.

    edElement.CipherData.CipherValue = encryptedElement;
    
    edElement.CipherData.CipherValue = encryptedElement
    
  14. Ganti elemen dari objek XmlDocument yang asli dengan elemen EncryptedData.

    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
    
    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
    
  15. Simpan XmlDocument objek.

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

Contoh

Contoh ini mengasumsikan bahwa file yang bernama "test.xml" berada dalam direktori yang sama dengan program yang dikompilasi. Ini juga mengasumsikan bahwa "test.xml" berisi elemen "creditcard". Anda dapat menempatkan XML berikut ke dalam file yang disebut test.xml dan menggunakannya dengan contoh ini.

<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


Mengompilasi kode

Keamanan .NET

Jangan pernah menyimpan kunci kriptografi simetris dalam teks biasa atau mentransfer kunci simetris antara mesin dalam teks biasa. Selain itu, jangan pernah menyimpan atau mentransfer kunci privat dari pasangan kunci asimetris dalam teks biasa. Untuk informasi selengkapnya tentang kunci kriptografi simetris dan asimetris, lihat Membuat Kunci untuk Enkripsi dan Dekripsi.

Tip

Untuk pengembangan, gunakan Secret Manager untuk penyimpanan rahasia yang aman. Dalam produksi, pertimbangkan produk seperti Azure Key Vault.

Jangan pernah menyematkan kunci langsung ke dalam kode sumber Anda. Kunci yang disematkan dapat dengan mudah dibaca dari perakitan menggunakan Ildasm.exe (IL Disassembler) atau dengan membuka rakitan di editor teks seperti Notepad.

Ketika Anda selesai menggunakan kunci kriptografi, bersihkan dari memori dengan mengatur setiap byte ke nol atau dengan memanggil metode Clear kelas kriptografi terkelola. Kunci kriptografi terkadang dapat dibaca dari memori oleh debugger atau dibaca dari hard drive jika lokasi memori di-page ke disk.

Lihat juga