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:
EncryptedData The crux of the specification. This element replaces the encrypted data, whether the data being encrypted is within an XML document or the XML document itself. In the latter case, the EncryptedData element actually becomes the document root.
EncryptedKey An optional element containing information about the key that was used during the encryption process.
EncryptionMethod An optional element describing the algorithm applied during the encryption process.
CipherData A mandatory element that provides the encrypted data.
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
Use strong ciphers to ensure the privacy of data.
Only encrypt sensitive data in the XML document.
Instead of encrypting it, remove sensitive data that the recipient doesn’t need.