Implementing XML Encryption in Java
April 21, 2004
In the first column of this series, we presented a high-level WSS4J API, which we wish to implement in this series of columns. In the second column, we discussed the various Java components we are going to use in implementing the WSS4J API. The most important component is XML Security Suite for Java (XSS4J) from IBM alphaWorks. The second column also demonstrated how to use XSS4J for XML encryption.
In this column, we will use the XSS4J concepts discussed in the previous column to implement the XML encryption features in our WSS4J API.
Before we start the discussion, we would like to point out a name clash issue. There's an open source Web Services Security project at SourceForge.net (recently moved to Apache's web site) that shares the same WSS4J name. The WSS4J API we are developing in this series of columns is purely for educational purposes and aims at demonstrating the use of WSS in Java applications. The WSS4J open source project at SourceForge (now at Apache) is an independent project and is not part of our effort.
A WSS Message Before and After XML Encryption
We are going to add support for both symmetric and asymmetric keys in our WSS4J API. Listing 1 shows a simple SOAP message we will use as sample input to our XML encryption process. We will encrypt a portion of Listing 1 to demonstrate the working of our WSS4J API.
We are going to perform three types of XML encryption. Listings 2, 3, and 4 are three WSS messages that show the outcome of our encryption process. Listings 2, 3, and 4 are slightly different from each other. As we have already covered the details of WSS format in our Web Services Security series (especially in Part 4), we will not go into the details of WSS format. Here we will only highlight the differences between Listings 2, 3, and 4:
Listing 2 shows the following:
- If you look at the contents of the SOAP body in Listings 1 and 2, you will see that the first
Parameterelement of Listing 1 has been replaced by an
EncryptedDataelement in Listing 2. The
EncryptedDataelement contains the encrypted form of the
Parameterelement. The encryption algorithm used for this XML encryption is triple DES as specified by the
EncryptionMethodchild of the
EncryptedDataelement in Listing 2 does not contain any key information. The corresponding key information resides inside the
wsse:Securityelement in the SOAP header, which contains an
EncryptedKeyelement wraps a symmetric triple DES secret key in encrypted form. Notice from Listing 2 that the
EncryptionMethodused to produce the
EncryptedKeyis RSA and the key used for this RSA encryption is the tour operator's public key. We covered the details of such encrypted keys in Step 2 of the Using XSS4J for XML Encryption section in the second column.
- How do we relate an
EncryptedDataelement with its corresponding key used for encryption? Look at the
ReferenceListelement inside the
EncryptedKeyelement of Listing 2. The
ReferenceListelement has a child element named
URIattribute points to the
EncryptedDataelement we produced using the encrypted key.
EncryptedKey element is a security token in WSS terms. Although the XML
encryption specification simply calls it an encryption key, the WSS specification
about abstract (or more general) tokens. This means we can treat cryptographic keys
type of security token. Therefore, while implementing WSS, we will treat an
EncryptedKey structure as a type of token and call it an encrypted key
Now look at Listing 3, which is a very
slightly modified form of Listing 2. The
only difference between Listings 2 and 3 is that the
EncryptedData element in
Listing 3 contains a
element, which wraps a
SecurityTokenReference element. The
ecurityTokenReference element has a
Reference child element,
URI attribute refers to the
wsu:Id of the
EncryptedKey that was used to produce the
If there are more than one
elements in a WSS message, then it is computationally more expensive to find the
EncryptedKey corresponding to a particular
structure in Listing 2 as compared to Listing 3. That's because in Listing 2 you
have to look into the
ReferenceList elements of several
EncryptedKey structures until you find the required
structure. On the other hand, if you have to find the
corresponding to a particular
EncryptedKey Listing 3, you can read the
URI attribute value of the
Reference element and jump directly
to the required
We will call Listing 3 as an encrypted key token with cross reference.
Now look at Listing 4, which shows the following:
EncryptedDataelement in Listing 4 contains a
KeyNameelement, which specifies the name of the key used for encryption. Here we are assuming that the recipient of this message can locate the actual key corresponding to this name. Therefore, we are not concerned about how an application will map a key name to the actual key.
- There's no
EncryptedKeyelement inside the
wsse:Securityheader. Instead we just have a
ReferenceListelement that refers to the
EncryptedDataelement inside the SOAP body. This type of
ReferenceListelement does not specify the key used for producing the
ReferenceListonly specifies the order in which different actions take place in the header (e.g. if you encrypt and then sign a portion of a message, the
ds:Signatureelement will appear before the
ReferenceListelement. For details please refer to the discussion accompanying Listings 7 and 8 in the fourth article of my Web Services Security series).
We will call this
ReferenceList element a reference list only
We will implement the first two types of tokens (encrypted key token and encrypted key token with cross reference) in this column and the third type (reference list only token) in the next column of this series.
Implementing the Encrypted Key Token
Now let's see how to implement and use an encrypted key token. In order to implement and use an encrypted key token, we'll need to do the following:
- Implement the
Tokeninterface we presented in Listing 3 of the first column of this series. The
Tokeninterface contains several methods and we'll need to implement each of them in a Java class named
- Implement the constructor of the
WSSMessageclass we introduced in Listing 2 of the first column of this series.
- Implement the
encryptElementWithXPath()methods of the
Let's do these steps one by one.
Implementing the Token Interface
Have a look at the
EncryptedKeyToken class shown in Listing 5. This class implements the
Token interface and is responsible for performing the second, third, and
fourth steps of using XSS4J for XML encryption that we described in the second column of this
series. The final result of using an encrypted key token is what we have already seen
in Listing 2.
Have a look at the
EncryptedKeyToken constructor, which takes the following
keyStoreFileNameis the full path name of a Java key store file. The key store file contains the public key of the recipient of the WSS message.
keyStorePasswordis the string representation of the password that we need in order to access the key store.
KeyNameis the string representing the name of the recipient's public key that is stored in the key store.
wsu:Idof the encrypted key token. The token will author this
IDin the token's XML format.
wssMessageis the parent
WSSMessageobject that wraps this token.
The constructor first stores the parent
WSSMessage object, the key token ID,
and the key name in their corresponding fields. It then loads the encryption template
DOM object. We demonstrated the use of an encryption template in Listing 3 of the second
column. Listing 6 shows the
encryption template that our
EncryptedKeyToken will use. Listing 6 is slightly
different from the encryption template we introduced in Listing 3 of the second
column. We will explain the difference between the two templates later.
EncryptedKeyToken constructor then opens the key store file, loads it into
an input stream, and loads the input stream into a Java
KeyStore object. It
then instantiates a
KeyStoreKeyInfoResolver object and calls its
setAlgorithmFactory() method to set the algorithm factory to be used during
XML encryption. Recall that we have covered the details of these steps in the Using XSS4J for XML
Encryption section of the second column of this series.
Notice that the
EncryptedKeyToken constructor cannot access the key in the key
store. That's because we have not supplied the password required to access the key
inside the Java
KeyStore object. The application that instantiates the
EncryptedKeyToken object will also call the
EncryptedKeyToken.setSecret() method to specify the password to access the
setSecret() method (Listing
5) takes the key access password in byte array form, converts the byte array to a
character array, and supplies the character array to the
internally fetch the required key.
Now have a look at the
encrypt() method in Listing 5. This method authors the encrypted
EncryptedData structure) of the plain text element that we want to
encrypt() method takes three parameters:
EncryptedDatastructure that the
encrypt()method will author.
encryptionAlgo:The algorithm to be sued for encryption.
elementWantToEncrypt:The DOM element representation of the XML element that we want to encrypt.
encrypt() method performs the following eight steps (marked with comments
in Listing 5):
KeyStoreKeyInfoResolver can do both encryption and decryption. So the first
step is to set the mode of operation of the key resolver to "encryption."
Step 2: If you look at the encryption template we are using (Listing 6), you will find that there is a
ReferenceList child of the
EncryptedKey element. This
ReferenceList element was not present in the encryption template we
introduced in Listing 3
of the second column. We need this
ReferenceList element in the
EncryptedKey because the final objective of implementing the
EncryptedKeyToken class is to author the structure shown in Listing 2 (which contains a
Notice from Listing 2 that the
DataReference child of the
ReferenceList element refers to the
wsu:Id of the
EncryptedKey that was produced using the
EncryptedKey. Therefore, our second step is to add a
attribute to the
DataReference element. The
URI attribute refers
wsu:Id of the
EncryptedData that we are about to
Step 3: The third step is to author the
wsu:Id of the
EncryptedData that we will shortly author. At this moment the encryption
template looks like as shown in Listing
Step 4: We also need to tell that it is the encryption algorithm that we want to
use. For this purpose, our fourth step is to set the value of the Algorithm attribute
EncryptionMethod element in Listing 7.
Step 5: The
EncryptedKey element has its own
the fifth step is to author the
wsu:Id of the
Now our template is all set and looks like what's shown in Listing 8.
Step 6: The next step is to XML encrypt the input
DOM element using the
procedure we described while discussing step 4 of
KeyInfo and encrypt it using
the Using XSS4J for XML
Encryption section of the second article of this series.
Step 7: Assuming we encrypted the first
Parameter element of Listing 1, it will look like Listing 9 after encryption. If you compare
Listing 2 and Listing 9, you will find that the
EncryptedData element in Listing 9 is not the required form that we were
trying to author (see
EncryptedData in Listing 2).
The main difference between the
EncryptedData elements in Listing 2 and
Listing 9 is that the
EncryptedData element in Listing 9 contains a
element, which in turn contains the
EncryptedKey element. In Listing 2, the same
EncryptedKey element resides in the SOAP header.
Therefore, the seventh step is to copy the
EncryptedKey element and store it
DOM element object named
EncryptedKeyToken class contains another public method named
getXMLString(), which returns the string form of the encrypted key token.
Notice that in step 7 above we stored the
EncryptedKey in an object named
getXMLString() method simply returns the
string form of the
Now let's see how the
WSSMessage class will use the
EncryptedKeyToken class to author a WSS message containing an encrypted key
Listing 11 shows the
WSSMessage implementation. Have a look at the
constructor. The constructor is very simple. It just takes a plain text SOAP message
loads it into a
DOM object. For the moment, our
constructor is very humble. It will become more complex in later columns as our
WSSMessage class grows in functionality.
Implementing Encryption Methods in the
Note that the
WSSMessage class, as described in the first column of this
series, represents the whole WSS message (as opposed to the
EncryptedKeyToken class, which represents only a single token). Therefore,
encrypt() method of the
EncryptedKeyToken class only handles
one type of token, while the encryption methods in the
WSSMessage class should
be able to handle different types of tokens.
Look at the
methods in Listing 11. Each method takes
four parameters as already described in the first column. Each of
the two methods first locates the element to be encrypted and then calls a method
encrypt() method is private and performs the
- It checks what type of token is being used. In our case, we are using an encrypted key token.
- If the token being used is an encrypted key token, the
encrypt()element simply calls the
encrypt()method works according to the eight-step procedure described above and encrypts the plain text element.
- Next, the
WSSMessage.encrypt()method calls the
getXMLString()method of the
getXMLString()method returns the string representation of the encrypted key token.
- After fetching the string representation of the token, the
WSSMessage.encrypt()method places the token inside the
Securityheader, which resides inside the SOAP header.
In a similar manner the
WSSMessage.encrypt() method will handle different
types of tokens.
WSSMessage Class in an XML Encryption Application
The final question is how an application will use our
EncryptedKeyToken classes. Have a look at Listing 13, which shows the
main() method of a
WSSEncryptionSample class. You can see the
following steps in the
main() method of Listing 13, which demonstrates how easy and
simple it is to use our WSS4J API for encryption:
main()method first instantiates a
WSSMessageobject, passing a plain text SOAP message string to the
- It then instantiates an
EncryptedKeyTokenobject and then calls its
setSecret()method passing the key access password along with the method invocation call.
- The third step is to call the
encryptElement()method of the
WSSMessageobject, passing the token as well as the
wsu:Idof the plain text element to be encrypted.
Implementing the Encrypted Key Token with a Cross Reference
This section demonstrates how we can easily enhance our
implement support for the encrypted key token with cross reference that we introduced
in Listing 3. This needs the following
- Write a Java class named
EncryptedKeyTokenWithCrossReference, which extends the
EncryptedKeyTokenclass. We have shown the
EncryptedKeyTokenWithCrossReferenceclass in Listing 14.
EncryptedKeyTokenWithCrossReferenceconstructor takes the same parameters as the
EncryptedKeyTokenconstructor. Since we don't need any additional functionality in the
EncryptedKeyTokenWithCrossReferenceconstructor simply calls the super's constructor.
encrypt()method in the
EncryptedKeyTokenWithCrossReferenceclass needs just one extra step as compared to the
encrypt()method in the
EncryptedKeyTokenclass. The extra step is to add the
SecurityTokenReferencestructure (that we described in Listing 3) wrapped inside a
KeyInfoelement. Therefore, in the
encrypt()method of the
EncryptedKeyTokenWithCrossReferenceclass, we simply call the super's
encrypt()method and then add a
We have demonstrated the use of
EncryptedKey structure in WSS messages. Next
time, we will start by implementing the reference list token that we introduced in
Listing 3. We will also discuss the use of
XSS4J for XML digital signatures in the next column of this series.
Download the source code zip of this article. The zip contains the source as well as the compiled form of the code. The zip also contains a readme.txt file that will help you compile and run the code of this article.
Read the first and second column of this series, which introduced the WSS4J API. Also check out the first, second, third, and fourth parts of the series of article on Web Services Security from the same author.
Visit BouncyCastle.org to download the latest version of their
provider. We tested the code of this article with the
Download your copy of XSS4J from IBM alphaWorks web site.
Download ICU4J from here.
This tutorial at IBM developerWorks will help you learn the basics of cryptography in Java.