Skip to Content »

Tech Life of Recht » archive for May, 2008

 Scrum and the Public Sector

  • May 18th, 2008
  • 2:36 pm

Projects for the public sector have, for a long time, had a reputation of being overspecified, tightly controlled, contract-focused, and in many cases badly managed. Some call them waterfall projects. Luckily, it’s been a while since I was on a project like that – the projects I’ve worked on, also for NITA have been run as Scrum projects with a good amount of success. It has, however, mostly been smaller projects – a month or two, and without any real focus on the process from the customer’s side. Now it looks like we’re finally heading away from the classic waterfall approach, as NITA has openly confessed to Scrum (in Danish only). Just as important, Trifork is helping both with Scrum and doing the implementation. I’m not on the project at the moment (still busy with OIOSAML and REST), but I’d be surprised if I didn’t get involved at some point.

 OpenSAML and XML Encryption

  • May 14th, 2008
  • 9:08 am

This topic is probably not relevant for many people, but I figured it warranted a post anyways since it's taken so much of my time. The basic problem: Encrypting and decrypting XML using the OpenSAML APIs for XML Encryption. OpenSAML is a SAML api supporting SAML 2.0, where some elements can be encrypted. One example is the Assertion element in a Response. Instead of transmitting a regular Assertion element, it is possible to transmit an EncryptedAssertion element instead. This element then contains the encrypted assertion.

The API contains two classes of particular interest in this case: org.opensaml.saml2.encryption.Encrypter and org.opensaml.saml2.encryption.Decrypter for encrypting and decrypting. Before using them, it's probably necessary to explain how XML encryption works with asymmetric keys (public key encryption).
The usual way of doing public key encryption is that the sender encrypts data with the receiver's public key. The receiver can then decrypt it with the private key, thus ensuring privacy. However, encrypting an entire data stream using asymmetric keys is very expensive, so instead a symmetric (shared) key is generated by the sender. This key is then encrypted with the receiver's public key, and the data stream is then encrypted with the symmetric key.

The asymmetric keys are usually created with the RSA algorithm while a popular choice for symmetric keys is 128 bit AES. In an encrypted XML structure, the data looks like this:

CODE:
  1. <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
  2.   <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
  3.   <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  4.     <xenc:EncryptedKey>
  5.       <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
  6.       <xenc:CipherData>
  7.         <xenc:CipherValue>
  8.              W6U2DRN11Y/dbIMCEP....
  9.         </xenc:CipherValue>
  10.       </xenc:CipherData>
  11.     </xenc:EncryptedKey>
  12.   </ds:KeyInfo>
  13.   <xenc:CipherData>
  14.     <xenc:CipherValue>
  15.        uK3fL7fFC/Y6GbXLwmFmLZcla8...
  16.     </xenc:CipherValue>
  17.   </xenc:CipherData>
  18. </xenc:EncryptedData>

In other words, the EncryptedData element (which is a standard XML encryption element) contains a KeyInfo which holds the encrypted symmetric key and a CipherData element which contains data encrypted with the symmetric key. The first element tells us that the symmetric data is encrypted with 128 bit AES, and EncryptedData/KeyInfo/EncryptedKey/EncryptionMethod says that the key itself is encrypted with RSA.

All this means that when encrypting an XML element, two keys must be used: A randomly generated, and the receiver's public key. In OpenSAML, it looks like this:

CODE:
  1. package test;
  2.  
  3.  
  4. import org.opensaml.saml2.core.EncryptedAssertion;
  5. import org.opensaml.saml2.core.Response;
  6. import org.opensaml.saml2.encryption.Encrypter;
  7. import org.opensaml.saml2.encryption.Encrypter.KeyPlacement;
  8. import org.opensaml.xml.encryption.EncryptionConstants;
  9. import org.opensaml.xml.encryption.EncryptionParameters;
  10. import org.opensaml.xml.encryption.KeyEncryptionParameters;
  11. import org.opensaml.xml.security.SecurityHelper;
  12. import org.opensaml.xml.security.credential.Credential;
  13.  
  14.  
  15. public class EncryptTest throws Exception {
  16.   public void encrypt(Response response, Credential receiverCredential) {
  17.     Credential symmetricCredential = SecurityHelper.getSimpleCredential(
  18.       SecurityHelper.generateSymmetricKey(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128));
  19.    
  20.     EncryptionParameters encParams = new EncryptionParameters();
  21.     encParams.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128);
  22.     encParams.setEncryptionCredential(symmetricCredential);
  23.        
  24.     KeyEncryptionParameters kek = new KeyEncryptionParameters();
  25.     kek.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15);
  26.     kek.setEncryptionCredential(receiverCredential);
  27.        
  28.     Encrypter encrypter = new Encrypter(encParams, kek);
  29.     encrypter.setKeyPlacement(KeyPlacement.INLINE);
  30.        
  31.     EncryptedAssertion encrypted = encrypter.encrypt(response.getAssertions().get(0));
  32.     response.getEncryptedAssertions().add(encrypted);
  33.        
  34.     response.getAssertions().clear();
  35.   }
  36. }

This code replaces an unencrypted Assertion with an encrypted. The Encrypter is instantiated with two arguments: The EncryptionParameters and the KeyEncryptionParameters. The EncryptionParameters contain a reference to the shared key and the algorithm to use, and the KeyEncryptionParameters contain the receiver's public key.

Decrypting an encrypted element is then a question of first decrypting the key and then decrypting the data. In code it can look something like this:

CODE:
  1. public class DecryptTest throws Exception {
  2.   public Assertion decrypt(EncryptedAssertion enc, Credential credential) {
  3.     KeyInfoCredentialResolver keyResolver = new StaticKeyInfoCredentialResolver(credential);
  4.     EncryptedKey key = enc.getEncryptedData().getKeyInfo().getEncryptedKeys().get(0);
  5.  
  6.     Decrypter decrypter = new Decrypter(null, keyResolver, null);
  7.     SecretKey dkey = (SecretKey) decrypter.decryptKey(
  8.       key, enc.getEncryptedData().getEncryptionMethod().getAlgorithm());
  9.  
  10.     Credential shared = SecurityHelper.getSimpleCredential(dkey);
  11.     decrypter = new Decrypter(new StaticKeyInfoCredentialResolver(scred), null, null);
  12.     return decrypter.decrypt(enc);
  13.   }
  14. }

The credentials in the arguments list must contain the receiver's private key, and is used to decrypt the shard key. When the shared key has been decrypted, the rest of the message can be decrypted.

All of this looks pretty simple, but the APIs are not very forgiving. If you try to encrypt or decrypt with the wrong algorithm or with the wrong keys (or key types), strange things will happen. Most likely, you'll get a stacktrace teling you that the padding is wrong, which is not exactly helpful. However, the examples above show one way of doing encryption and decryption which works, and I hope it can help a little if you're also unable to escape from XML/web services.

 JMX: Overlooked technology?

  • May 13th, 2008
  • 10:16 pm

I've been somewhat busy lately, primarily with courses and our SAML project. Last week, we held a 5 day course on Java EE 5, and I had been blessed with the task of talking about WS-Security and SAML. Not strictly JEE5, but the customer wanted to hear something about it, so somebody had to do it. Naturally, the BlackHole(tm) effect kicked in, and I was chosen as the most competent. Enough about that, in a later post I'll probably write something about my experiences with OpenSAML and XML Encryption.

One of the other topics in the course was JMX, and it hit me that even though people knew JMX, they didn't quite know the available tools. The technology itself hasn't changed in quite a long time, but it still seems to somewhat overlooked. JMX is nice because it's so easy to add monitoring capabilities to your application. Of course, there are limits as to how much functionality you can (and want) to expose through JMX, but common cases are statistics, logging configuration, job scheduling, and other things which you don't necessarily want to build a dedicated interface for. This makes even more sense when you're not developing a web application but some sort of server.

For those who don't know it, JMX is pretty simple, especially since Java5:

CODE:
  1. public interface TestMBean {
  2.   public void restartServer();
  3. }
  4.  
  5. public class Test implements TestMBean {
  6.   public void restartServer() {
  7.     System.out.println("Restarting server");
  8.   }
  9. }
  10.  
  11.  
  12. MBeanServer server = ManagementFactory.getPlatformMBeanServer();
  13. ObjectName name = new ObjectName("appname", "type", "server");
  14. server.registerMBean(new Test(), name);

That's more or less it. Now the TestMBean can be monitored through JMX using a JMX console - which brings me to one of the overlooked programs in the JDK: JConsole. With JConsole, which is a part of the standard JDK, it's possible to monitor any JMX MBean server, including the JDK itself. Simply fire up JConsole and connect to a process. Under the MBeans tab, you can see all the registered MBeans. The other tabs contain VM information - The threads tab can also be quite useful for looking at stack traces for individual threads without attaching a debugger.