Thursday, October 22, 2009

Item 65: Use SealedObject to provide confidentiality of Serializable objects











 < Day Day Up > 





Item 65: Use SealedObject to provide confidentiality of Serializable objects



Not only do we need to make sure that serialized data isn't tampered with across an insecure medium (see Item 60), but frequently we need to ensure that nobody except the intended recipient can see the contents of the data. It is frequently more necessary to ensure confidentiality of the data than to ensure the integrity of the data in question. Ensuring confidentiality is the province of the javax.crypto.SealedObject class, and it functions in a manner similar to the SignedObject discussed in Item 64.



In this case, rather than using a PublicKey/PrivateKey pair, the SealedObject needs a SecretKey that is shared somehow between both parties. SealedObject uses a symmetric key to quickly encrypt and decrypt the data because asymmetric key cryptography (public-key/private-key cryptography) takes a huge amount of time to perform. Obtaining the SecretKey in such a way that both parties can safely exchange the key without Eve (the eavesdropper) or Mallory (the malicious in-betweener) subverting the key exchange is beyond the scope of this item, so for now we're going to assume that the SecretKey has been established somehow. (Note, however, that one way you could do this is to effectively replicate the mechanism SSL uses to establish a new session key between recipients on each SSL connection.[5] Another approach is documented in Appendix F of the Java Cryptography Extension Reference Guide, included as part of the standard JDK documentation set, using the KeyAgreement class and friends to negotiate the sharing of secret session keys between two parties.)

[5] In general, it's a Really Bad Idea to try to reimplement existing security infrastructure because it's very likely that you'll accidentally leave holes in the implementation that could be exploited by an attacker. Make sure your threat model is sufficiently covered if you consider rolling your own key-exchange protocol, and as a test for yourself, make sure you can describe how SSL works before even attempting this.



As with SignedObject, take any Serializable object (and in this case combine it with a Cipher, created from a SecretKey) and construct a SealedObject passing in both of those objects. The Serializable object is copied by value into the SealedObject and encrypted. Now the SealedObject can be itself serialized, in this case to a file on the local filesystem, and the data within is hidden from prying eyes, unless they happen to have the SecretKey as well.










String s = "Greetings";



KeyGenerator keyGen = KeyGenerator.getInstance("DES");

SecretKey key = keyGen.generateKey();

Cipher cipher = Cipher.getInstance("DES");

cipher.init(Cipher.ENCRYPT_MODE, key);



SealedObject sealedObj = new SealedObject(s, cipher);



ObjectOutputStream oos =

new ObjectOutputStream(new FileOutputStream(".secret"));

oos.writeObject(sealedObj);

oos.close();




Obtaining the data inside the SealedObject is a simple matter of calling the getObject method, passing in the SecretKey:










ObjectInputStream ois =

new ObjectInputStream(new FileInputStream(".secret"));

SealedObject sealedObj = (SealedObject)ois.readObject();

ois.close();



String data = (String)sealedObj.getObject(key);




While storing data to the filesystem is one use of the SealedObject type, a more common use is to pass SealedObject instances back and forth across JMS message queues, particularly if the data is at all sensitive or if system administrators can view messages residing in the queue. This is actually a more scalable way to achieve confidentiality of JMS messages, since now we don't have to rely on the messaging middleware encrypting the entirety of the traffic, which would most likely be overkill; instead, only the sensitive payload (the message itself) is protected. Just pass the SealedObject as the payload of an ObjectMessage.



As with its cousins SignedObject (see Item 64) and GuardedObject (see Item 66), SealedObject can be subclassed in order to introduce better strongly typed APIs for use by clients who wish to remain ignorant of the actual security mechanisms in place.



You may be wondering why you should bother with SealedObject when other mechanisms, like the CipherInputStream/CipherOutputStream pair, offer perhaps greater control over the actual encryption and decryption process. The short answer is that when security is involved, the less actual control you have over the implementation, the better�it's too easy to build a roll-your-own security stack that has exploitable flaws. Using SealedObject instead lets you focus on simply storing Serializable types into it; the implementation takes care of itself. This is one place you don't want to experiment.



Frequently, however, just the encrypted form isn't, by itself, enough. Encryption by itself doesn't ensure that the object wasn't somehow tampered with�if Mallory can somehow slip into the conversation stream, he can easily use a different secret key between himself and Bob than the one established by Alice in the first place. For this reason, SealedObject instances are often combined with a SignedObject and sent that way: create and sign the SignedObject, then use that to create a SealedObject.













     < Day Day Up > 



    No comments: