How to: Encrypt XML Elements with Symmetric Keys
You can use the classes in the System.Security.Cryptography.Xml namespace to encrypt an element within an XML document. XML Encryption allows you to store or transport sensitive XML, without worrying about the data being easily read. This procedure encrypts an XML element using the Advanced Encryption Standard (AES) algorithm.
For information about how to decrypt an XML element that was encrypted using this procedure, see How to: Decrypt XML Elements with Symmetric Keys.
When you use a symmetric algorithm like AES to encrypt XML data, you must use the same key to encrypt and decrypt the XML data. The example in this procedure assumes that the encrypted XML will be decrypted using the same key, and that the encrypting and decrypting parties agree on the algorithm and key to use. This example does not store or encrypt the AES key within the encrypted XML.
This example is appropriate for situations where a single application needs to encrypt data based on a session key stored in memory, or based on a cryptographically strong key derived from a password. For situations where two or more applications need to share encrypted XML data, consider using an encryption scheme based on an asymmetric algorithm or an X.509 certificate.
To encrypt an XML element with a symmetric key
Generate a symmetric key using the Aes class. This key will be used to encrypt the XML element.
Aes? key = null; try { // Create a new AES key. key = Aes.Create();
Dim key As Aes = Nothing Try ' Create a new Aes key. key = Aes.Create()
Create an XmlDocument object by loading an XML file from disk. The XmlDocument object contains the XML element to encrypt.
// Load an XML document. XmlDocument xmlDoc = new() { PreserveWhitespace = true }; xmlDoc.Load("test.xml");
' Load an XML document. Dim xmlDoc As New XmlDocument() xmlDoc.PreserveWhitespace = True xmlDoc.Load("test.xml")
Find the specified element in the XmlDocument object and create a new XmlElement object to represent the element you want to encrypt. In this example, the
"creditcard"
element is encrypted.XmlElement? elementToEncrypt = Doc.GetElementsByTagName(ElementName)[0] as XmlElement;
Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementName)(0)
Create a new instance of the EncryptedXml class and use it to encrypt the XmlElement with the symmetric key. The EncryptData method returns the encrypted element as an array of encrypted bytes.
EncryptedXml eXml = new(); byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Key, false);
Dim eXml As New EncryptedXml() Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, Key, False)
Construct an EncryptedData object and populate it with the URL identifier of the XML Encryption element. This URL identifier lets a decrypting party know that the XML contains an encrypted element. You can use the XmlEncElementUrl field to specify the URL identifier.
EncryptedData edElement = new() { Type = EncryptedXml.XmlEncElementUrl };
Dim edElement As New EncryptedData() edElement.Type = EncryptedXml.XmlEncElementUrl
Create an EncryptionMethod object that is initialized to the URL identifier of the cryptographic algorithm used to generate the key. Pass the EncryptionMethod object to the EncryptionMethod property.
string? encryptionMethod; if (Key is Aes) { encryptionMethod = EncryptedXml.XmlEncAES256Url; } else { // Throw an exception if the transform is not AES throw new CryptographicException("The specified algorithm is not supported or not recommended for XML Encryption."); } edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);
Dim encryptionMethod As String = Nothing If TypeOf Key Is Aes Then encryptionMethod = EncryptedXml.XmlEncAES256Url Else ' Throw an exception if the transform is not in the previous categories Throw New CryptographicException("The specified algorithm is not supported or not recommended for XML Encryption.") End If edElement.EncryptionMethod = New EncryptionMethod(encryptionMethod)
Add the encrypted element data to the EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
edElement.CipherData.CipherValue = encryptedElement
Replace the element from the original XmlDocument object with the EncryptedData element.
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
Example
<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;
namespace CSCrypto
{
class Program
{
static void Main(string[] args)
{
Aes? key = null;
try
{
// Create a new AES key.
key = Aes.Create();
// Load an XML document.
XmlDocument xmlDoc = new()
{
PreserveWhitespace = true
};
xmlDoc.Load("test.xml");
// Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", key);
Console.WriteLine("The element was encrypted");
Console.WriteLine(xmlDoc.InnerXml);
Decrypt(xmlDoc, key);
Console.WriteLine("The element was decrypted");
Console.WriteLine(xmlDoc.InnerXml);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
key?.Clear();
}
}
public static void Encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
{
// Check the arguments.
ArgumentNullException.ThrowIfNull(Doc);
ArgumentNullException.ThrowIfNull(ElementName);
ArgumentNullException.ThrowIfNull(Key);
////////////////////////////////////////////////
// Find the specified element in the XmlDocument
// object and create a new XmlElement object.
////////////////////////////////////////////////
XmlElement? elementToEncrypt = Doc.GetElementsByTagName(ElementName)[0] as XmlElement;
// Throw an XmlException if the element was not found.
if (elementToEncrypt == null)
{
throw new XmlException("The specified element was not found");
}
//////////////////////////////////////////////////
// Create a new instance of the EncryptedXml class
// and use it to encrypt the XmlElement with the
// symmetric key.
//////////////////////////////////////////////////
EncryptedXml eXml = new();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Key, false);
////////////////////////////////////////////////
// Construct an EncryptedData object and populate
// it with the desired encryption information.
////////////////////////////////////////////////
EncryptedData edElement = new()
{
Type = EncryptedXml.XmlEncElementUrl
};
// Create an EncryptionMethod element so that the
// receiver knows which algorithm to use for decryption.
// Determine what kind of algorithm is being used and
// supply the appropriate URL to the EncryptionMethod element.
string? encryptionMethod;
if (Key is Aes)
{
encryptionMethod = EncryptedXml.XmlEncAES256Url;
}
else
{
// Throw an exception if the transform is not AES
throw new CryptographicException("The specified algorithm is not supported or not recommended for XML Encryption.");
}
edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);
// 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);
}
public static void Decrypt(XmlDocument Doc, SymmetricAlgorithm Alg)
{
// Check the arguments.
ArgumentNullException.ThrowIfNull(Doc);
ArgumentNullException.ThrowIfNull(Alg);
// Find the EncryptedData element in the XmlDocument.
XmlElement? encryptedElement = Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
// If the EncryptedData element was not found, throw an exception.
if (encryptedElement == null)
{
throw new XmlException("The EncryptedData element was not found.");
}
// Create an EncryptedData object and populate it.
EncryptedData edElement = new();
edElement.LoadXml(encryptedElement);
// Create a new EncryptedXml object.
EncryptedXml exml = new();
// Decrypt the element using the symmetric key.
byte[] rgbOutput = exml.DecryptData(edElement, Alg);
// Replace the encryptedData element with the plaintext XML element.
exml.ReplaceData(encryptedElement, rgbOutput);
}
}
}
Imports System.Xml
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Module Program
Sub Main(ByVal args() As String)
Dim key As Aes = Nothing
Try
' Create a new Aes key.
key = Aes.Create()
' Load an XML document.
Dim xmlDoc As New XmlDocument()
xmlDoc.PreserveWhitespace = True
xmlDoc.Load("test.xml")
' Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", key)
Console.WriteLine("The element was encrypted")
Console.WriteLine(xmlDoc.InnerXml)
Decrypt(xmlDoc, key)
Console.WriteLine("The element was decrypted")
Console.WriteLine(xmlDoc.InnerXml)
Catch e As Exception
Console.WriteLine(e.Message)
Finally
' Clear the key.
If Not (key Is Nothing) Then
key.Clear()
End If
End Try
End Sub
Sub Encrypt(ByVal Doc As XmlDocument, ByVal ElementName As String, ByVal Key As SymmetricAlgorithm)
' Check the arguments.
ArgumentNullException.ThrowIfNull(Doc)
ArgumentNullException.ThrowIfNull(ElementName)
ArgumentNullException.ThrowIfNull(Key)
''''''''''''''''''''''''''''''''''''''''''''''''''
' Find the specified element in the XmlDocument
' object and create a new XmlElemnt object.
''''''''''''''''''''''''''''''''''''''''''''''''''
Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementName)(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
''''''''''''''''''''''''''''''''''''''''''''''''''
' Create a new instance of the EncryptedXml class
' and use it to encrypt the XmlElement with the
' symmetric key.
''''''''''''''''''''''''''''''''''''''''''''''''''
Dim eXml As New EncryptedXml()
Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, Key, False)
''''''''''''''''''''''''''''''''''''''''''''''''''
' Construct an EncryptedData object and populate
' it with the desired encryption information.
''''''''''''''''''''''''''''''''''''''''''''''''''
Dim edElement As New EncryptedData()
edElement.Type = EncryptedXml.XmlEncElementUrl
' Create an EncryptionMethod element so that the
' receiver knows which algorithm to use for decryption.
' Determine what kind of algorithm is being used and
' supply the appropriate URL to the EncryptionMethod element.
Dim encryptionMethod As String = Nothing
If TypeOf Key Is Aes Then
encryptionMethod = EncryptedXml.XmlEncAES256Url
Else
' Throw an exception if the transform is not in the previous categories
Throw New CryptographicException("The specified algorithm is not supported or not recommended for XML Encryption.")
End If
edElement.EncryptionMethod = New EncryptionMethod(encryptionMethod)
' 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)
End Sub
Sub Decrypt(ByVal Doc As XmlDocument, ByVal Alg As SymmetricAlgorithm)
' 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
' Find the EncryptedData element in the XmlDocument.
Dim encryptedElement As XmlElement = Doc.GetElementsByTagName("EncryptedData")(0)
' If the EncryptedData element was not found, throw an exception.
If encryptedElement Is Nothing Then
Throw New XmlException("The EncryptedData element was not found.")
End If
' Create an EncryptedData object and populate it.
Dim edElement As New EncryptedData()
edElement.LoadXml(encryptedElement)
' Create a new EncryptedXml object.
Dim exml As New EncryptedXml()
' Decrypt the element using the symmetric key.
Dim rgbOutput As Byte() = exml.DecryptData(edElement, Alg)
' Replace the encryptedData element with the plaintext XML element.
exml.ReplaceData(encryptedElement, rgbOutput)
End Sub
End Module
Compiling the Code
In a project that targets .NET Framework, include a reference to
System.Security.dll
.In a project that targets .NET Core or .NET 5, install NuGet package System.Security.Cryptography.Xml.
Include the following namespaces: System.Xml, System.Security.Cryptography, and System.Security.Cryptography.Xml.
.NET Security
Never store a cryptographic key in plaintext or transfer a key between machines in plaintext. Instead, use a secure key container to store cryptographic keys.
When you are done using a cryptographic key, clear it from memory by setting each byte to zero or by calling the Clear method of the managed cryptography class.
See also
- Cryptography Model - Describes how cryptography is implemented in the base class library.
- Cryptographic Services
- Cross-Platform Cryptography
- System.Security.Cryptography.Xml
- How to: Decrypt XML Elements with Symmetric Keys
- ASP.NET Core Data Protection