Using the Cipher Class for Key Wrapping

the write methods, the available method, and the close method, which all provide the semantics you would expect. Often, of course, these methods are never used directly −− for example, if youre sending text data over a socket, you will wrap a cipher output stream around the sockets output stream, but then you will wrap a print writer around that; the programming interface then becomes a series of calls to the print and println methods. You can use any similar output stream to get a different interface. It does not matter if the cipher object that was passed to the constructor does automatic padding or not −− the CipherOutputStream class itself does not make that restriction. As a practical matter, however, youll want to use a padding cipher object, since otherwise youll be responsible for keeping track of the amount of data passed to the output stream and tacking on your own padding. Usually, the better alternative is to use a byte−oriented mode such as CFB8. This is particularly true in streams that are going to be used conversationally: a message is sent, a response received, and then another message is sent, etc. In this case, you want to make sure that the entire message is sent; you cannot allow the cipher to buffer any data internally while it waits for a full block to arrive. And, for reasons were just about to describe, you cannot call the flush method in this case either. Hence, you need to use a streaming cipher or, technically, a block cipher in streaming mode in this case. When the flush method is called on a CipherOutputStream either directly or because the stream is being closed, the padding of the stream comes into play. If the cipher is automatically padding, the padding bytes are generated in the flush method. If the cipher is not automatically padding and the number of bytes that have been sent through the stream is not a multiple of the ciphers block size, then the flush method or indirectly the close method throws an IllegalBlockSizeException note that this requires that the IllegalBlockSizeException be a runtime exception. If the cipher is performing padding, it is very important not to call the flush method unless it is immediately followed by a call to the close method. If the flush method is called in the middle of processing data, padding is added in the middle of the data. This means the data does not decrypt correctly. Remember that certain output streams especially some types of PrintWriter streams flush automatically; if youre using a padding cipher, dont use one of those output streams. We can use this class to write some encrypted data to a file like this: package javasec.samples.ch13; import java.io.; import java.security.; import javax.crypto.; import javax.crypto.spec.; public class Send { public static void mainString args[] { try { KeyGenerator kg = KeyGenerator.getInstanceDES; kg.initnew SecureRandom ; SecretKey key = kg.generateKey ; SecretKeyFactory skf = SecretKeyFactory.getInstanceDES; Class spec = Class.forNamejavax.crypto.spec.DESKeySpec; DESKeySpec ks = DESKeySpec skf.getKeySpeckey, spec; ObjectOutputStream oos = new ObjectOutputStream new FileOutputStreamkeyfile; oos.writeObjectks.getKey ; Cipher c = Cipher.getInstanceDESCFB8NoPadding; c.initCipher.ENCRYPT_MODE, key; CipherOutputStream cos = new CipherOutputStream new FileOutputStreamciphertext, c; PrintWriter pw = new PrintWriter new OutputStreamWritercos; pw.printlnStand and unfold yourself; pw.close ; oos.writeObjectc.getIV ; oos.close ; } catch Exception e { System.out.printlne; } } } There are two steps involved here. First, we must create the cipher object, which means that we must have a secret key available. Bypassing the secret key management examples weve used before, were just going to save the key object to a file that can later be read by whomever needs the key. Note that weve gone through the usual steps of writing the data produced by the secret key factory so that the recipient of the key need not use the same provider we use. After we generate the key, we must create the cipher object, initialize it with that key, and then use that cipher object to construct our output stream. Once the data is sent to the stream, we close the stream, which flushes the cipher object, performs any necessary padding, and completes the encryption. In this case, weve chosen to use CFB8 mode, so there is no need for padding. But in general, this last step is important: if we dont explicitly close the PrintWriter stream, when the program exits, data that is buffered in the cipher object itself will not get flushed to the file. The resulting encrypted file will be unreadable, as it wont have the correct amount of data in its last block. [1] [1] Closing the output stream is necessary whenever the stream performs buffering, but it is particularly important to remember in this context.

13.2.2 The CipherInputStream Class

The output stream is only half the battle; in order to read that data, we must use the CipherInputStream class javax.crypto.CipherInputStream : public class CipherInputStream extends FilterInputStream Create a filter stream capable of decrypting data as it is read from the underlying input stream. A cipher input stream is constructed with this method: public CipherInputStreamInputStream is, Cipher c Create a cipher input stream that associates the existing input stream with the given cipher. The cipher must previously have been initialized. All the points we made about the CipherOutputStream class are equally valid for the CipherInputStream class. You can operate on it with any of the methods in its superclass, although youll typically want to wrap it in something like a buffered reader, and the cipher object that is associated with the input stream needs to perform automatic padding or use a mode that does not require padding in fact, it must use the same padding scheme and mode that the output stream that is sending it data used. The CipherInputStream class does not directly support the notion of a mark. The markSupported method returns false unless youve wrapped the cipher input stream around another class that supports a mark.