The CipherOutputStream Class

This class is a FilterOutputStream that encrypts or decrypts the data passing through it. It is composed of an OutputStream, or one of its subclasses, and a Cipher. CipherOutputStream represents a secure output stream into which a Cipher object has been interposed. The write methods of CipherOutputStream first process the data with the embedded Cipher object before writing it out to the underlying OutputStream. The Cipher object must be fully initialized before being used by a CipherOutputStream.

For example, if the embedded Cipher has been initialized for encryption, the CipherOutputStream will encrypt its data, before writing them out to the underlying output stream.

This class adheres strictly to the semantics, especially the failure semantics, of its ancestor classes java.io.OutputStream and java.io.FilterOutputStream. This class has exactly those methods specified in its ancestor classes, and overrides them all, so that all data is additionally processed by the embedded cipher. Moreover, this class catches all exceptions that are not thrown by its ancestor classes.

If you use this class, do not to use methods that are not defined or that are overridden in this class (such as a new method or constructor that is later added to one of the super classes), because the design and implementation of those methods are unlikely to have considered security impact with regard to CipherOutputStream.

As an example of its usage, suppose cipher1 has been initialized for encryption. The following code demonstrates how to use a CipherOutputStream containing that cipher and a FileOutputStream to encrypt data to be written to an output stream:

 FileInputStream fis;
 FileOutputStream fos;
 CipherOutputStream cos;

 fis = new FileInputStream("/tmp/a.txt");
 fos = new FileOutputStream("/tmp/b.txt");
 cos = new CipherOutputStream(fos, cipher1);
 byte[] b = new byte[8];
 int i = fis.read(b);
 while (i != -1) {
 cos.write(b, 0, i);
 i = fis.read(b);
 }
 cos.flush();

This program reads the content from the file /tmp/a.txt, then encrypts and stores the result (the encrypted bytes) in /tmp/b.txt.

The following example demonstrates how to easily connect several instances of CipherOutputStream and FileOutputStream. In this example, assume that cipher1 and cipher2 have been initialized for decryption and encryption (with corresponding keys), respectively:

 FileInputStream fis;
 FileOutputStream fos;
 CipherOutputStream cos1, cos2;

 fis = new FileInputStream("/tmp/a.txt");
 fos = new FileOutputStream("/tmp/b.txt");
 cos1 = new CipherOutputStream(fos, cipher1);
 cos2 = new CipherOutputStream(cos1, cipher2);
 byte[] b = new byte[8];
 int i = fis.read(b);
 while (i != -1) {
 cos2.write(b, 0, i);
 i = fis.read(b);
 }
 cos2.flush();

This program copies the content from file /tmp/a.txt to /tmp/b.txt, except that the content is first encrypted and then decrypted back before it is written to /tmp/b.txt.

There is one important difference between the flush and close methods of this class, which becomes even more relevant if the encapsulated Cipher object implements a block cipher algorithm with padding turned on:

  • flush flushes the underlying OutputStream by forcing any buffered output bytes that have already been processed by the encapsulated Cipher object to be written out. Any bytes buffered by the encapsulated Cipher object and waiting to be processed by it will not be written out.
  • close closes the underlying OutputStream and releases any system resources associated with it. It invokes the doFinal method of the encapsulated Cipher object, causing any bytes buffered by it to be processed and written out to the underlying stream by calling its flush method.