Performing Your Own Padding

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 −−