While reviewing an encryption scheme, I came accross the following code:
@Override
public OutputStream encrypt(OutputStream outputStream) throws Exception {
// generate the IV for encryption
final byte[] encryptionIV = KeyFileUtil.randomBytes(16);
outputStream.write(encryptionIV);
// now create the encryption cipher
final Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, getKey(), new GCMParameterSpec(128, encryptionIV));
// The CipherOutputStream shouldn't close the underlying stream
outputStream = new FilterOutputStream(outputStream) {
@Override
public void close() throws IOException {
// Do nothing
}
};
final CipherOutputStream cos = new CipherOutputStream(outputStream, cipher);
if (useZip) {
final ZipOutputStream zipOutputStream = new ZipOutputStream(cos) {
@Override
public void finish() throws IOException {
super.finish();
def.end();
}
@Override
public void flush() {
// Do nothing.
}
@Override
public void close() throws IOException {
try {
super.flush();
} catch (final IOException exception) {
// Continue and try to close.
}
super.close();
}
};
zipOutputStream.putNextEntry(new ZipEntry("ResourceContents"));
return zipOutputStream;
}
return cos;
}
As far as I understand the ordering of the streams is such that data is being encrypted first then (uselessly) compressed. Is this correct or am I misunderstanding how ordering works on OutputStreams?
Thanks
Yes, you're misunderstanding (or reading) how ordering works.
At new ZipOutputStream(cos)
the CipherOutputStream
is wrapped by the ZOS
, therefore data is first zipped, then passed on to the wrapped stream, which will encrypt the data, and then pass it on to the next wrapped stream, and so on.
The outermost stream gets first go at the data, and if compression is enabled, return zipOutputStream;
is called, with the zipstream being the outermost stream. It's idiomatic use of FilterOutputStream.