Initialization of a PBEWithMD5AndDES Cipher

The bulk of the work of any cipher engine will be in the engineUpdate method, which is responsible for actually providing the ciphertext or plaintext. In this case, weve simply XORed the key value with every byte, a process that works both for encryption as well as decryption. Because the work done by the engineUpdate method is so symmetrical, we dont need to keep track internally of whether were encrypting or decrypting; for us, the work is always the same. For some algorithms, you may need to keep track of the state of the cipher by setting an internal variable when the engineInit method is called. Similarly, because we can operate on individual bytes at a time, we didnt have to worry about padding and buffering internal data. Such an extension is easy using the code we showed earlier that uses the modulus operator to group the input arrays into blocks. To use this class, we would need to use the XYZProvider class we developed in Chapter 8. Then we simply instantiate the engine and create the cipher like this: Security.addProvidernew XYZProvider ; KeyGenerator kg = KeyGenerator.getInstanceXOR; Cipher c = Cipher.getInstanceXOR; Note that XOR is the valid algorithm name for this implementation since we do not support any modes or padding schemes. Note too that we no longer need an initialization vector to create the cipher. Finally, remember that the Cipher class is a JCE engine, which is why the constructor here calls the verifyForJCE method.

13.2 Cipher Streams

In the Cipher class we just examined, we had to provide the data to be encrypted or decrypted as multiple blocks of data. This is not necessarily the best interface for programmers: what if we want to send and receive arbitrary streams of data over the network? It would often be inconvenient to get all the data into buffers before it can be encrypted or decrypted. The solution to this problem is the ability to associate a cipher object with an input or output stream. When data is written to such an output stream, it is automatically encrypted, and when data is read from such an input stream, it is automatically decrypted. This allows a developer to use Javas normal semantics of nested filter streams to send and receive encrypted data.

13.2.1 The CipherOutputStream Class

The class that encrypts data on output to a stream is the CipherOutputStream class javax.crypto.CipherOutputStream : public class CipherOutputStream extends FilterOutputStream Provide a class that will encrypt data as it is written to the underlying stream. Like all classes that extend the FilterOutputStream class, constructing a cipher output stream requires that an existing output stream has already been created. This allows us to use the existing output stream from a socket or a file as the destination stream for the encrypted data: public CipherOutputStreamOutputStream outputStream, Cipher cipher Create a cipher output stream, associating the given cipher object with the existing output stream. The given cipher must already have been initialized, or an IllegalStateException will be thrown. The output stream may be operated on with any of the methods from the FilterOutputStream class −− 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;