Sealed Objects

The Java Cryptography Extension discussed in the last chapter provides a SealedObject class that can encrypt objects written onto an object output stream using any available cipher. Most of the time, I suspect, you'll either encrypt the entire object output stream by chaining it to a cipher output stream, or you won't encrypt anything at all. However, if there's some reason to encrypt only some of the objects you're writing to the stream, you can make them sealed objects.

The javax.crypto.SealedObject class wraps a serializable object in an encrypted digital lockbox. The sealed object is serializable so that it can be written onto object output streams and read from object input streams as normal. However, the object inside the sealed object can only be deserialized by someone who knows the key.

public class SealedObject extends Object implements Serializable

The big advantage to using sealed objects rather than encrypting the entire output stream is that the sealed objects contain all necessary parameters for decryption (algorithm used, initialization vector, salt, iteration count). All the receiver of the sealed object needs to know is the key; there doesn't necessarily have to be any prior agreement about these other aspects of encryption.

You seal an object with the SealedObject( ) constructor. The constructor takes as arguments the object to be sealed, which must be serializable, and the properly initialized Cipher object with which to encrypt the object:

Inside the constructor, the object is immediately serialized by an object output stream chained to a byte array output stream. The byte array is then stored in a private field that is encrypted using the Cipher object c. The cipher's algorithms and parameters are also stored. Thus, the state of the original object written onto the ultimate object output stream is the state of the object when it was sealed; subsequent changes it may undergo between being sealed and being written are not reflected in the sealed object. Since serialization takes place immediately inside the constructor, the constructor throws a NotSerializableException if the object argument cannot be serialized. It throws an IllegalBlockSizeException if c is a block cipher with no padding and the length of the serialized object's contents is not an integral multiple of the block size.

You unseal an object by first reading the sealed object from an object input stream and then invoking one of the three getObject( ) methods to return the original object. All of these methods require you to supply a key and an algorithm.

Example 13-8 is a very simple program that writes an encrypted java.awt.Point object into the file point.des. First a file output stream is opened to the file point.des and then chained to the ObjectOutputStream oin. As in the last chapter, a fixed DES key called desKey is built from a fixed array of bytes and used to construct a Cipher object called des. des is initialized in encryption mode with the key. Finally, both the des Cipher object and the Point object tdp are passed into the SealedObject( ) constructor to create a SealedObject so. Since SealedObject implements Serializable, this can be written on the ObjectOutputStream oout as any other serializable object. At this point, this program closes oout and exits. However, the same Cipher object des could be used to create more sealed objects from serializable objects, and these could also be written onto the stream if you had more objects to serialize.

The first variant is the most useful since it only requires the key. It does not require you to create and initialize a Cipher object. You will need to know the algorithm in order to know what kind of key to create, but that information is available from the getAlgorithm( ) method: