Export (0) Print
Expand All
6 out of 13 rated this helpful - Rate this topic

How to: Encrypt XML Elements with Asymmetric Keys 

You can use the classes in the System.Security.Cryptography.Xml namespace to encrypt an element within an XML document. XML Encryption is a standard way to exchange or store encrypted XML data, without worrying about the data being easily read. For more information about the XML Encryption standard, see the World Wide Web Consortium (W3C) specification for XML Encryption located at http://www.w3.org/TR/xmldsig-core/.

You can use XML Encryption to replace any XML element or document with an <EncryptedData> element that contains the encrypted XML data. The <EncryptedData> element can also contain sub elements that include information about the keys and processes used during encryption. XML Encryption allows a document to contain multiple encrypted elements and allows an element to be encrypted multiple times. The code example in this procedure shows how to create an <EncryptedData> element along with several other sub elements that you can use later during decryption.

This example encrypts an XML element using two keys. It generates an RSA public/private key pair and saves the key pair to a secure key container. The example then creates a separate session key using the Advanced Encryption Standard (AES) algorithm, also called the Rijndael algorithm. The example uses the AES session key to encrypt the XML document and then uses the RSA public key to encrypt the AES session key. Finally, the example saves the encrypted AES session key and the encrypted XML data to the XML document within a new <EncryptedData> element.

To decrypt the XML element, you retrieve the RSA private key from the key container, use it to decrypt the session key, and then use the session key to decrypt the document. For more information about how to decrypt an XML element that was encrypted using this procedure, see How to: Decrypt XML Elements with Asymmetric Keys.

This example is appropriate for situations where multiple applications need to share encrypted data or where an application needs to save encrypted data between the times that it runs.

To encrypt an XML element with an asymmetric key

  1. Create a CspParameters object and specify the name of the key container.

    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
    
    
  2. Generate a symmetric key using the RSACryptoServiceProvider class. The key is automatically saved to the key container when you pass the CspParameters object to the constructor of the RSACryptoServiceProvider class. This key will be used to encrypt the AES session key and can be retrieved later to decrypt it.

    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    
    
  3. Create an XmlDocument object by loading an XML file from disk. The XmlDocument object contains the XML element to encrypt.

    // 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. 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(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. Create a new session key using the RijndaelManaged class. This key will encrypt the XML element, and then be encrypted itself and placed in the XML document.

    // Create a 256 bit Rijndael key.
    sessionKey = new RijndaelManaged();
    sessionKey.KeySize = 256;
    
    
  6. Create a new instance of the EncryptedXml class and use it to encrypt the specified element using the session key. The EncryptData method returns the encrypted element as an array of encrypted bytes.

    EncryptedXml eXml = new EncryptedXml();
    
    byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
    
    
  7. Construct an EncryptedData object and populate it with the URL identifier of the encrypted XML 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. The plaintext XML element will be replaced by an <EncrypotedData> element encapsulated by this EncryptedData object.

    EncryptedData edElement = new EncryptedData();
    edElement.Type = EncryptedXml.XmlEncElementUrl;
    edElement.Id = EncryptionElementID;
    
    
  8. Create an EncryptionMethod object that is initialized to the URL identifier of the cryptographic algorithm used to generate the session key. Pass the EncryptionMethod object to the EncryptionMethod property.

    edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
    
    
  9. Create an EncryptedKey object to contain the encrypted session key. Encrypt the session key, add it to the EncryptedKey object, and enter a session key name and key identifier URL.

    EncryptedKey ek = new EncryptedKey();
    
    byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
    
    ek.CipherData = new CipherData(encryptedKey);
    
    ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
    
    
  10. Create a new DataReference object that maps the encrypted data to a particular session key. This optional step allows you to easily specify that multiple parts of an XML document were encrypted by a single key.

    DataReference dRef = new DataReference();
    
    // Specify the EncryptedData URI.
    dRef.Uri = "#" + EncryptionElementID;
    
    // Add the DataReference to the EncryptedKey.
    ek.AddReference(dRef);
    
    
  11. Add the encrypted key to the EncryptedData object.

    edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
    
    
  12. Create a new KeyInfo object to specify the name of the RSA key. Add it to the EncryptedData object. This helps the decrypting party identify the correct asymmetric key to use when decrypting the session 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);
    
    
  13. Add the encrypted element data to the EncryptedData object.

    edElement.CipherData.CipherValue = encryptedElement;
    
    
  14. Replace the element from the original XmlDocument object with the EncryptedData element.

    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
    
    
  15. Save the XmlDocument object.

    xmlDoc.Save("test.xml");
    
    

Example


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

		}

	}

}


This example assumes that a file named "test.xml" exists in the same directory as the compiled program. It also assumes that "test.xml" contains a "creditcard" element. You can place the following XML into a file called test.xml and use it with this example.

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

Compiling the Code

  • To compile this example, you need to include a reference to System.Security.dll.

  • Include the following namespaces: System.Xml, System.Security.Cryptography, and System.Security.Cryptography.Xml.

Security

Never store a symmetric cryptographic key in plaintext or transfer a symmetric key between machines in plaintext. Additionally, never store or transfer the private key of an asymmetric key pair in plaintext. For more information about symmetric and asymmetric cryptographic keys, see Generating Keys for Encryption and Decryption.

Never embed a key directly into your source code. Embedded keys can be easily read from an assembly using the MSIL Disassembler (Ildasm.exe) or by opening the assembly in a text editor such as Notepad.

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. Cryptographic keys can sometimes be read from memory by a debugger or read from a hard drive if the memory location is paged to disk.

See Also

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.