Avoid man-in-middle attack using XML Encryption.

Post date: Jul 26, 2011 3:49:12 AM

The goal of the XML encryption specification is to describe a digitally encrypted Web resource using XML. Following the XML encryption specification creates a document that combines the benefits of both XML and encryption to produce a human-readable, standardized document that code can parse independent of platform, at the same time containing secrets encrypted with your choice of symmetrical or asymmetrical algorithms.

The Web resource used in XML encryption can be anything from an HTML document to a GIF file or even an entire XML document. With respect to XML documents, the XML encryption specification provides for the encryption of an element, including the start and end tags, the content within an element between the start and end tags, and the entire XML document. The specification describes that the encrypted data is placed within an EncryptedData element. The EncryptedData element also contains details pertaining to encrypting and/or decrypting the information. These details include the pertinent encryption algorithm, the key used for encryption, references to external data objects, and either the encrypted data or a reference to the encrypted data.

Encrypting XML Data

Summary:

Threats:

XML encryption is useful for encrypting specific elements of a document for transport across insecure networks as well as for archival purposes

Information leakage, data corruption, man-in-the-middle attacks

The SSL Internet encryption protocol might seem sufficient in protecting data transferred across the Internet. However, XML encryption provides a slightly different solution than creating an encrypted data stream. XML encryption allows you to encrypt a single, specific element of an XML document instead of encrypting the entire document, as would be the case in SSL. For example, if you are sending medical information across the Internet, a patient’s nonidentifying details such as height, weight, and blood test could remain unencrypted, whereas you would encrypt the patient’s identity and more sensitive information such as name and Social Security number. The resource benefit of encrypting only a small amount of data instead of the entire document becomes substantial.

Another benefit of the XML encryption specification arises with stored data. SSL provides an encrypted channel only or transient data across the Internet. In contrast, XML is a data-formatting specification that you can use to archive and store data. For instance, the previously mentioned medical records could be archived without concern for exposing the patient’s identity.

XML Encryption Specification

The XML encryption specification is in the recommended stage and is ready for adoption. For further details, you may review the official W3C XML Encryption Syntax and Processing specification, found at www.w3.org/TR/xmlenc-core. Figure 8.1 shows the XML encryption specification syntax.

<EncryptedData Id? Type? MimeType? Encoding?>   <EncryptionMethod/>?   <ds:KeyInfo>     <EncryptedKey>?     <AgreementMethod>?     <ds:KeyName>?     <ds:RetrievalMethod>?     <ds:*>?   </ds:KeyInfo>?   <CipherData>     <CipherValue>?     <CipherReference URI?>?   </CipherData>   <EncryptionProperties>? 

</EncryptedData>

Figure 8.1: XML Encryption Specification Syntax

You can find the entire XML encryption schema at www.w3.org/TR/xmlenc-core/xenc-schema.xsd, as well as in Figure 8.2. The elements in bold are explained following the schema.

<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE schema  PUBLIC "-//W3C//DTD XMLSchema 200102//EN"  "http://www.w3.org/2001/XMLSchema.dtd"  [    <!ATTLIST schema      xmlns:xenc CDATA #FIXED 'http://www.w3.org/2001/04/xmlenc#'      xmlns:ds CDATA #FIXED 'http://www.w3.org/2000/09/xmldsig#'>    <!ENTITY xenc 'http://www.w3.org/2001/04/xmlenc#'>    <!ENTITY % p ''>    <!ENTITY % s ''>   ]> 

<schema xmlns='http://www.w3.org/2001/XMLSchema' version='1.0'         xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'         xmlns:ds='http://www.w3.org/2000/09/xmldsig#'         targetNamespace='http://www.w3.org/2001/04/xmlenc#'         elementFormDefault='qualified'> 

  <import namespace='http://www.w3.org/2000/09/xmldsig#'            schemaLocation='http://www.w3.org/TR/2002/

REC-xmldsig-core-20020212/xmldsig-core-schema.xsd'/> 

  <complexType name='EncryptedType' abstract='true'>     <sequence>       <element name='EncryptionMethod' type='xenc:EncryptionMethodType'        minOccurs='0'/>       <element ref='ds:KeyInfo' minOccurs='0'/>       <element ref='xenc:CipherData'/>       <element ref='xenc:EncryptionProperties' minOccurs='0'/>     </sequence>     <attribute name='Id' type='ID' use='optional'/>     <attribute name='Type' type='anyURI' use='optional'/>     <attribute name='MimeType' type='string' use='optional'/>     <attribute name='Encoding' type='anyURI' use='optional'/>   </complexType>      <complexType name='EncryptionMethodType' mixed='true'>     <sequence>       <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/>       <element name='OAEPparams' minOccurs='0' type='base64Binary'/>       <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>     </sequence>     <attribute name='Algorithm' type='anyURI' use='required'/>   </complexType> 

    <simpleType name='KeySizeType'>       <restriction base="integer"/>     </simpleType> 

  <element name='CipherData' type='xenc:CipherDataType'/>   <complexType name='CipherDataType'>      <choice>        <element name='CipherValue' type='base64Binary'/>        <element ref='xenc:CipherReference'/>      </choice>     </complexType> 

   <element name='CipherReference' type='xenc:CipherReferenceType'/>    <complexType name='CipherReferenceType'>        <choice>           <element name='Transforms' type='xenc:TransformsType' _  minOccurs='0'/>        </choice>        <attribute name='URI' type='anyURI' use='required'/>    </complexType> 

     <complexType name='TransformsType'>        <sequence>          <element ref='ds:Transform' maxOccurs='unbounded'/>        </sequence>      </complexType> 

  <element name='EncryptedData' type='xenc:EncryptedDataType'/>   <complexType name='EncryptedDataType'>     <complexContent>       <extension base='xenc:EncryptedType'>        </extension>     </complexContent>   </complexType> 

  <!-- Children of ds:KeyInfo --> 

  <element name='EncryptedKey' type='xenc:EncryptedKeyType'/>   <complexType name='EncryptedKeyType'>     <complexContent>       <extension base='xenc:EncryptedType'>         <sequence>           <element ref='xenc:ReferenceList' minOccurs='0'/>           <element name='CarriedKeyName' type='string' minOccurs='0'/>         </sequence>         <attribute name='Recipient' type='string'          use='optional'/>       </extension>     </complexContent>   </complexType> 

    <element name="AgreementMethod" type="xenc:AgreementMethodType"/>     <complexType name="AgreementMethodType" mixed="true">       <sequence>         <element name="KA-Nonce" minOccurs="0" type="base64Binary"/>         <!-- <element ref="ds:DigestMethod" minOccurs="0"/> -->         <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>          <element name="OriginatorKeyInfo" minOccurs="0" _  type="ds:KeyInfoType"/>          <element name="RecipientKeyInfo" minOccurs="0" _  type="ds:KeyInfoType"/>       </sequence>       <attribute name="Algorithm" type="anyURI" use="required"/>     </complexType> 

  <!-- End Children of ds:KeyInfo --> 

  <element name='ReferenceList'>     <complexType>       <choice minOccurs='1' maxOccurs='unbounded'>         <element name='DataReference' type='xenc:ReferenceType'/>         <element name='KeyReference' type='xenc:ReferenceType'/>       </choice>     </complexType>   </element> 

  <complexType name='ReferenceType'>     <sequence>       <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>     </sequence>     <attribute name='URI' type='anyURI' use='required'/>   </complexType> 

   <element name='EncryptionProperties' _  type='xenc:EncryptionPropertiesType'/>   <complexType name='EncryptionPropertiesType'>     <sequence>       <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/>     </sequence>     <attribute name='Id' type='ID' use='optional'/>   </complexType> 

    <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/>     <complexType name='EncryptionPropertyType' mixed='true'>       <choice maxOccurs='unbounded'>         <any namespace='##other' processContents='lax'/>       </choice>       <attribute name='Target' type='anyURI' use='optional'/>       <attribute name='Id' type='ID' use='optional'/>       <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/>     </complexType> </schema>

Figure 8.2: XML Encryption Schema

The XML encryption schema is quite involved in describing the means of encryption. The following elements are the most notable of the specification:

Tip 

Notice that the EncryptedKey and EncryptionMethod elements are optional. These elements need not be present if the recipient knows this information.

XML Encryption Process

The process of encryption and decryption is straightforward. The data object is encrypted using a symmetrical or asymmetrical algorithm and a key of choice. Each implementation of the XML encryption specification should implement a common set of algorithms to allow for interoperability. If the data object is an element within an XML document, remove the element along with its content and replace it with the pertinent EncryptedData element. If the data object for encryption encrypt is an external resource, create a new document with an EncryptedData root node that contains a reference to the external resource.

Decryption follows these steps in reverse: Parse the XML to obtain the algorithm, parameters, and key used; locate the data to be decrypted; and perform the data decryption operation. The result will be a UTF-8 encoded string representing the XML fragment that should replace the entire EncryptedData element. If the data object is an external resource, the unencrypted string is available for use by the application.

There are some nuances to encrypting XML documents. Encrypted XML instances are well-formed XML documents but might not appear valid when validated against their original schema. If schema validation is required of an encrypted XML document, create a new schema to account for those encrypted elements.

Tip 

If the recipient of the document or an entity to which the recipient passes the XML document never needs to know the sensitive data, consider removing the sensitive data entirely. You can remove the sensitive data using a simple XSL transformation. After all, removing data is even more secure than encrypting it.

XML Encryption Example

As an example, let’s assume that we work in a medical lab and are responsible for returning the results of lab tests to a hospital. The lab stores the results in an XML document that various hospital computers, analysis machines, and data systems can interpret and act on. However, only a few trusted systems should be able to identify the individual to which the lab results apply. Therefore, we encrypt the patientPersonalInformation element of the document with a key that only trusted systems can access. Figure 8.3 shows an example XML record the medical lab needs to submit to a hospital.

<?xml version="1.0"?> <medicalRecord> <patientPersonalInformation>      <name>Bryan Pitcher</name>      <SSN>555-55-5555</SSN>      </patientPersonalInformation>      <bloodTestResults>      <bloodType>A+</bloodType>      <redBloodCellCount>4200000/cmm</redBloodCellCount>      <whiteBloodCellCount>4500/mcl</whiteBloodCellCount> </bloodTestResults> </medicalRecord> 

Figure 8.3: XML Document to Encrypt

Figures 8.4 and 8.5 show sample code that can read the document shown in Figure 8.3 and produce an XML-encrypted document. The code will encrypt the patientPersonalInformation element. For simplicity, the code generates the encryption key and IV. Ordinarily, code should read these values from a secure location. We assume that our trusted recipients have this key and IV as well as know the encryption method.

public void encryptDocument(string xmlDocumentPlainTextFilename, 

string xmlDocumentCipherTextFilename)  {              // Generate the keys   TripleDESCryptoServiceProvider tripleDES =      new TripleDESCryptoServiceProvider();   tripleDES.GenerateIV();   tripleDES.GenerateKey(); 

  // Get the XML document from file   XmlDocument xmlDoc = new XmlDocument();     xmlDoc.Load(xmlDocumentPlainTextFilename); 

    // specify the element to encrypt     XmlElement patientPersonalInformation =          (XmlElement)xmlDoc.SelectSingleNode(             "medicalRecord/patientPersonalInformation");     byte[] patientPersonalInformationBytes =          Encoding.UTF8.GetBytes(patientPersonalInformation.OuterXml); 

    // Set up the CryptoStream for encryption with the key and IV     MemoryStream memoryStream = new MemoryStream();     CryptoStream cryptoStream = new CryptoStream(memoryStream,          tripleDES.CreateEncryptor(tripleDES.Key, tripleDES.IV),          CryptoStreamMode.Write); 

    // Write ciphertext to memory stream     cryptoStream.Write(patientPersonalInformationBytes, 0,        patientPersonalInformationBytes.Length);     cryptoStream.Close(); 

    // Convert ciphertext to a Base64 string     byte[] patientPersonalInformationEncryptedBytes =  memoryStream.ToArray();     string patientPersonalInformationCipherText =          Convert.ToBase64String(patientPersonalInformationEncryptedBytes);     memoryStream.Close(); 

    // Create and populate the necessary XML encryption elements                 XmlElement xmlEncryptedData =          xmlDoc.CreateElement("EncryptedData");     XmlAttribute xmlType =          xmlDoc.CreateAttribute("Type");     xmlType.Value =          "http://www.w3.org/2001/04/xmlenc#Element";     xmlEncryptedData.Attributes.Append(xmlType);     XmlElement xmlCipherData =          xmlDoc.CreateElement("CipherData");     xmlEncryptedData.AppendChild(xmlCipherData);     XmlElement xmlCipherValue =          xmlDoc.CreateElement("CipherValue");     xmlCipherValue.InnerText = patientPersonalInformationCipherText;     xmlCipherData.AppendChild(xmlCipherValue);     patientPersonalInformation.ParentNode.ReplaceChild(         xmlEncryptedData, patientPersonalInformation); 

    // Write XML encrypted document to file     xmlDoc.Save(xmlDocumentCipherTextFilename);          } 

Figure 8.4: XML Document Encryption C#

Public Function encryptDocument _(ByVal xmlDocumentPlainTextFilename,      ByVal xmlDocumentCipherTextFilename) 

    ' Generate the keys     tripleDES = New TripleDESCryptoServiceProvider     tripleDES.GenerateIV()     tripleDES.GenerateKey() 

    ' Get the XML document from file     Dim xmlDoc = New XmlDocument     xmlDoc.Load(xmlDocumentPlainTextFilename) 

    ' specify the element to encrypt     Dim patientPersonalInformation = _       xmlDoc.SelectSingleNode( _         "medicalRecord/patientPersonalInformation") 

    Dim patientPersonalInformationBytes As Byte()     patientPersonalInformationBytes = _       Encoding.UTF8.GetBytes(patientPersonalInformation.OuterXml) 

    ' Set up the CryptoStream for encryption with the key and IV     Dim memoryStream As MemoryStream = New MemoryStream     Dim cryptoStream = New CryptoStream(memoryStream, _         tripleDES.CreateEncryptor(tripleDES.Key, tripleDES.IV), _         CryptoStreamMode.Write) 

    ' Write ciphertext to memory stream     cryptoStream.Write( _       patientPersonalInformationBytes, 0, _         patientPersonalInformationBytes.Length)     cryptoStream.Close() 

    ' Convert ciphertext to a Base64 string     Dim patientPersonalInformationEncryptedBytes As Byte()     patientPersonalInformationEncryptedBytes = _       memoryStream.ToArray()     Dim patientPersonalInformationCipherText = _       Convert.ToBase64String( _         patientPersonalInformationEncryptedBytes)     memoryStream.Close() 

    ' Create and populate the necessary XML encryption elements              Dim xmlEncryptedData = xmlDoc.CreateElement("EncryptedData")     Dim xmlType = xmlDoc.CreateAttribute("Type")     xmlType.Value = "http://www.w3.org/2001/04/xmlenc#Element"     xmlEncryptedData.Attributes.Append(xmlType)     Dim xmlCipherData = xmlDoc.CreateElement("CipherData")     xmlEncryptedData.AppendChild(xmlCipherData)     Dim xmlCipherValue = xmlDoc.CreateElement("CipherValue")     xmlCipherValue.InnerText = _       patientPersonalInformationCipherText     xmlCipherData.AppendChild(xmlCipherValue)     patientPersonalInformation.ParentNode.ReplaceChild( _      xmlEncryptedData, patientPersonalInformation) 

    ' Write XML encrypted document to file     xmlDoc.Save(xmlDocumentCipherTextFilename) End Function 

Figure 8.5: XML Document Encryption: VB.NET

Figure 8.6 shows the XML document after the patientPersonalInformation element has been encrypted.

<?xml version="1.0"?> <medicalRecord> <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element">      <CipherData> <CipherValue>fcEijNQTn3TLRBEtXwAGH003v4Jt0eZ0Uukuf9IE0ruxN6NHQKWufrVw03xKTZa u8z7FMyEmxdZKbqLg2Fl/Ct8KphQwpDyTodtMmE+uJrvtNni3ZFxu+4lenVPBXUgrq8x0BgO0px7 RyOsFVdpogYh+CVioHtQq</CipherValue>           </CipherData>      </EncryptedData> <bloodTestResults>      <bloodType>A+</bloodType>      <redBloodCellCount>4200000/cmm</redBloodCellCount>      <whiteBloodCellCount>4500/mcl</whiteBloodCellCount> </bloodTestResults> </medicalRecord> 

Figure 8.6: XML Document After Encryption

Our sample code replaced the patientPersonalInformation element of the document with the EncryptedData element. The actual patient data is within the CipherData element. This instance of EncryptedData contains no descriptive information regarding the encryption key or algorithm, as noted previously.

Figures 8.7 and 8.8 show example code to demonstrate the decrypting of an XML-encrypted document. For simplicity, this code decrypts only the encrypted element and writes the decrypted element to a file.

public void decryptDocument(string xmlDocumentCipherTextFilename,     string xmlDocumentPlainTextFilename)  {     // Get the XML document from file     XmlDocument xmlDoc = new XmlDocument();     xmlDoc.Load(xmlDocumentCipherTextFilename); 

    // Retrieve the element to be decrypted     XmlElement patientPersonalInformationEncrypted =          (XmlElement)xmlDoc.SelectSingleNode(         "medicalRecord/EncryptedData");     XmlElement xmlCipherValue =          (XmlElement)patientPersonalInformationEncrypted.SelectSingleNode(         "CipherData/CipherValue");     byte[] patientPersonalInformationEncryptedBytes =          Convert.FromBase64String(         xmlCipherValue.InnerText);          // Set up the CryptoStream for decryption     MemoryStream memoryStream = new     MemoryStream(patientPersonalInformationEncryptedBytes);     CryptoStream cipherStream = new CryptoStream(memoryStream,         tripleDES.CreateDecryptor(),CryptoStreamMode.Read);          // Perform decryption     byte[] patientPersonalInformationBytes =          new Byte[patientPersonalInformationEncryptedBytes.Length];     cipherStream.Read(patientPersonalInformationBytes, 0,          patientPersonalInformationBytes.Length);     cipherStream.Close();     memoryStream.Close(); 

    // Write the decrypted information to disk     string patientPersonalInformationString =          Encoding.UTF8.GetString(patientPersonalInformationBytes);     StreamWriter fileplaintext = new _      StreamWriter(xmlDocumentPlainTextFilename);     fileplaintext.Write(patientPersonalInformationString);     fileplaintext.Close(); } 

Figure 8.7: XML Document Decryption C#

Public Function decryptDocument(ByVal xmlDocumentCipherTextFilename, _    ByVal xmlDocumentPlainTextFilename) 

    ' Get the XML document from file     Dim xmlDoc As XmlDocument = New XmlDocument     xmlDoc.Load(xmlDocumentCipherTextFilename) 

    ' Retrieve the element to be decrypted     Dim patientPersonalInformationEncrypted = _      xmlDoc.SelectSingleNode( _      "medicalRecord/EncryptedData")     Dim xmlCipherValue = _      patientPersonalInformationEncrypted.SelectSingleNode( _      "CipherData/CipherValue")     Dim patientPersonalInformationEncryptedBytes As Byte()     patientPersonalInformationEncryptedBytes = _       Convert.FromBase64String(xmlCipherValue.InnerText) 

    ' Set up the CryptoStream for decryption     Dim memoryStream = _       New MemoryStream(patientPersonalInformationEncryptedBytes)     Dim cipherStream = New CryptoStream(memoryStream, _       tripleDES.CreateDecryptor(), CryptoStreamMode.Read) 

    ' Perform decryption     Dim patientPersonalInformationBytes = _       New Byte( _         patientPersonalInformationEncryptedBytes.Length - 1) {}     cipherStream.Read(patientPersonalInformationBytes, 0, _      patientPersonalInformationBytes.Length)     cipherStream.Close()     memoryStream.Close() 

    ' Write the decrypted information to disk     Dim patientPersonalInformationString = _       Encoding.UTF8.GetString(patientPersonalInformationBytes)     Dim fileplaintext = _       New StreamWriter(xmlDocumentPlainTextFilename, False)     fileplaintext.Write(patientPersonalInformationString)     fileplaintext.Close() End Function 

Figure 8.8: XML Document Decryption VB.NET

Security Policies