Chapter 17 Encrypting XML Documents
This chapter describes how to encrypt XML documents.
Tip: You find it useful to enable SOAP logging in this namespace so you can receive more information about any errors.
XML documents about encryption
An encrypted XML document contains the following elements:
<EncryptedData>
Element that contains encrypted data encrypted by a randomly generated symmetric key. (Encryption with a symmetric key is more efficient than encryption with a public key.)- At least one
<EncryptedKey>
Elements. each<EncryptedKey>
The element carries an encrypted copy of the symmetric key used to encrypt data; It also contains one with a public keyX.509
The certificate. A recipient with a matching private key can decrypt the symmetric key and then decrypt it<EncryptedData>
Elements. - (Optional) Other plaintext elements.
<Container xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptedKey>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
</EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIICnDCCAYQCAWUwDQYJKo... content omitted</X509Certificate>
</X509Data>
</KeyInfo>
<CipherData>
<CipherValue>J2DjVgcB8vQx3UCy5uejMB ... content omitted</CipherValue>
</CipherData>
<ReferenceList>
<DataReference URI="#Enc-E0624AEA-9598-4436-A154-F746B07A2C55"/>
</ReferenceList>
</EncryptedKey>
<EncryptedData Id="Enc-E0624AEA-9598-4436-A154-F746B07A2C55" Type="http://www.w3.org/2001/04/xmlenc#Content">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"></EncryptionMethod>
<CipherData>
<CipherValue>LmoBK7+nDelTOsC3 ... content omitted</CipherValue>
</CipherData>
</EncryptedData>
</Container>
Copy the code
To create encrypted files, please use the class % XML. The Security. The EncryptedData and % XML. The Security. The EncryptedKey. These XML-enabled classes project valid
and
elements into the appropriate namespace.
Create an encrypted XML document
The easiest way to create an encrypted XML document is as follows:
- Define and use generic container classes that can be directly projected onto the desired XML documents.
- Create a stream containing the XML to be encrypted.
- Encrypt the flow and write it to the corresponding property of the container class along with the corresponding encryption key.
- Generate XML output for container classes.
Prerequisites for encryption
Before encrypting a document, you must create an IRIS credential set that contains the certificate of the entity to which you want to send the encrypted document. In this case, the associated private key is not required (and should not be owned).
Container class requirements
A generic container class must contain the following:
- A type of
%XML.Security
Properties.
EncryptedData projected as a
element.
This property will carry encrypted data.
- At least one type is
%XML.Security
Properties. Is projected to<EncryptedKey>
Elements of theEncryptedKey
.
These attributes will carry the corresponding key information.
The following is an example:
Class XMLEncryption.Container Extends (%RegisteredObject, %XML.Adaptor)
{
Property Data As %XML.Security.EncryptedData(XMLNAME = "EncryptedData");
Property Key As %XML.Security.EncryptedKey(XMLNAME = "EncryptedKey");
Parameter NAMESPACE = "http://www.w3.org/2001/04/xmlenc#";
}
Copy the code
Generate an encrypted XML document
To generate and write an encrypted document, do the following:
- Create a flow that contains XML documents.
To do this, you typically use % xml.writer to write the output of xmL-enabled objects to the stream.
- create
%SYS.X509Credentials
At least one instance of, accesses the InterSystems IRIS credential set of the entity to which the encrypted document is to be supplied. To do this, call this classGetByAlias()
Class methods. Such as:
set credset=##class(%SYS.X509Credentials).GetByAlias("recipient")
Copy the code
To run this method, you must log in as the user contained in the OwnerList of the credential set, otherwise the OwnerList must be empty.
- Create at least
%XML.Security.EncryptedKey
Instance. To create an instance of this class, use theCreateX509()
Class methods. Such as:
set enckey=##class(%XML.Security.EncryptedKey).Createx509(credset.encryptionOptions.referenceOption)
Copy the code
credset
is%SYS
The instance.
The X509Credentials open in the new window you just created.
encryptionOptions
is$$$SOAPWSIncludeNone
(There are other options, but they don’t apply to this scenario).
This macro is defined in the %soap.inc include file.
referenceOption
Specifies the nature of a reference to an encrypted element.
The macros used here are defined in the %soap.inc include file.
- When creating a
%Library.ListOfObjects
Instance, and use itInsert()
Method just created the insert%XML.Security.EncryptedKey
Instance. - use
%New()
Method to create%XML.Security.EncryptedData
Instance. Such as:
set encdata=##class(%XML.Security.EncryptedData%).New(a)Copy the code
- use
% XML. Security. EncryptedData EncryptStream ()
The instance method encrypts the flow created in Step 2. Such as:
set status=encdata.EncryptStream(stream,encryptedKeys)
Copy the code
- Stream is the stream created in Step 1.
- EncryptedKeys is the list of keys created in Step 4.
- Create and update instances of the container class.
- Writes the list of keys to the corresponding property of this class.
- will
%XML.Security.EncryptedData
Writes the corresponding property of this class to an instance of.
- use
%XML.Writer
Generate output for the container class.
For example, the CONTAINER class shown earlier also includes the following methods:
/// w ##class(XMLEncryption.Container).Demo("E:\temp\SecurityXml.txt")
ClassMethod Demo(filename = "", obj = "")
{
#Include %soap
if (obj = "") {
s obj = ##class(MyApp.Person%).OpenId(1)} // enable from now onXMLObject creation flowset writer = # #class(%XML.Writer%).New(a)set stream = # #class(%GlobalCharacterStream%).New(a)set status = writer.OutputToStream(stream)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
set status = writer.RootObject(obj)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
dostream.Rewind() set container = .. %New() ; That's the object we're going to write set cred = ##class(%SYS.X509Credentials).GetByAlias("servercred")
set parts =$$$SOAPWSIncludeNone
set ref = $$$KeyInfoX509Certificate
set key = ##class(%XML.Security.EncryptedKey).CreateX509(cred.parts.ref)
set container.Key = key ; This detail depends on the class// You need to create a list of keys (only one in this case)
set keys = ##class(%Collection.ListOfObj%).New(a)do keys.Insert(key)
set encdata = # #class(%XML.Security.EncryptedData%).New(a)set status = encdata.EncryptStream(stream, keys) set container.Data = encdata ; This detail depends on the class// Write output for the container
set writer = ##class(%XML.Writer%).New(a)set writer.Indent = 1
if (filename'="") { set status = writer.OutputToFile(filename) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} } set status = writer.RootObject(container) if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit} }Copy the code
This method can accept OREF of any XML-enabled class; If none is provided, the default value is used.
Decrypt the encrypted XML file
Preconditions for decryption
Before decrypting an encrypted XML document, you must provide both of the following:
- Trusted certificate to be used by IRIS.
- IRIS set of credentials whose private key matches the public key used in encryption.
Declassified documents
To decrypt an encrypted XML document, do the following:
- create
%XML.Reader
The instance opens and uses it to open the document. - To obtain
Document
Properties,%XML.Reader
Instance.
It contains an XML document as a DOM. 3. Use the correlation of reader () method will < EncryptedKey > element or elements with the class % XML. The Security. The EncryptedKey associated. Such as:
do reader.Correlate("EncryptedKey"."%XML.Security.EncryptedKey")
Copy the code
- Traverse the document to read
<EncryptedKey>
Element or elements.
To do this, you can use the reader’s Next() method, which returns an imported object (if any) by reference. Such as:
if 'reader.Next(.ikey,.status) { write ! ,"Unable to import key",! do $system.OBJ.DisplayError(status) quit }Copy the code
The imported object is % XML. Security. EncryptedKey instance.
- create
%Library.ListOfObjects
The instance.
And use it to Insert () method inserts % XML. The Security. The EncryptedKey instance. Just got it from the documentation.
- Call the class
%XML.Security.EncryptedData
theValidateDocument()
methods
set status=##class(%XML.Security.EncryptedData).ValidateDocument(.doc.keys)
Copy the code
The first argument (returned by reference) is the modified version of the DOM retrieved in Step 2. The second argument is the list of keys from the previous step.
- Optional use
%XML.Writer
Generate output for the modified DOM.
For example, the CONTAINER class shown earlier contains the following class methods:
ClassMethod DecryptDoc(filename As %String)
{
#Include %soap
set reader = ##class(%XML.Reader%).New(a)set status = reader.OpenFile(filename)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
set doc = reader.Document
// Get
element
do reader.Correlate("EncryptedKey"."%XML.Security.EncryptedKey")
if 'reader.Next(.ikey,.status) { write ! Unable to import key. do $system.OBJ.DisplayError(status) quit } set keys = ##class(%Collection.ListOfObj).%New() do keys.Insert(ikey) // The following steps to return the declassified document set status = # # class (% XML. The Security. The EncryptedData). ValidateDocument (. Doc, keys) set writer = ##class(%XML.Writer).%New() set writer.Indent = 1 do writer.Document(doc) quit $$$OK }Copy the code