Tango
Tango

Reputation: 669

Encrypting Zip Entries but not the entire Zip File in Java

I know if I'm creating and writing to a zip file, I wrap the ZipOutputStream around an OutputStream (or subclass), like this:

fos = new FileOutputStream(fileName)
zOut = new ZipOutputStream(fos);

I also know how to create a zip file and the need to specify when I'm adding a new entry and to close an entry. What I'd like to do is encrypt the files within the archive, but leave the archive unencrypted so the entries are still easily found. (Part of the reason for this is because different entries will be read at different times - and if I encrypt the entire zip file, then I'll have to start reading it at the start every time, even if the zip entry I need is the 99th one. I won't have random access to entries if the entire file is encrypted.)

I know normally to encrypt (or decrypt), I wrap one stream around the other like this:

fos = new FileOutputStream("ciphertext");
CipherOutputStream cos = new CipherOutputStream(fos, key);

And I presume if I'm writing to a ZipOutputStream and want to encrypt the entry, to create the ZipOutputStream, I could do what I did above in the first example, and then when it's time to write the data for a zip entry, I wrap the ZipOutputStream within the CipherOutputStream, like this:

fos = new FileOutputStream(fileName)
zOut = new ZipOutputStream(fos);
...
CipherOutputStream cos = new CipherOutputStream(zOut, key);

But that raises a few questions:

  1. With something like this, in general, does the order of the stream matter? Would it matter if I wrapped the CipherOutputStream within the ZipOutputStream or could I do it the other way around? In other words, if the whole file were encrypted, would it matter which stream were wrapped around which one?
  2. If I do it as above, and use the CipherOutputScream for the data in each entry, what do I do when I need to close that entry and move on to the next? Can I destroy the CipherOutputStream without effecting the stream it's wrapped around?
  3. Is there a better way to encrypt just the zip entries and not the catalog and other data in the zip file?

Upvotes: 3

Views: 2997

Answers (2)

Péter Radics
Péter Radics

Reputation: 1

I'm new here, thus I can't write comment to Aaron Digulla's post. This is a supplement to his post.

The encryption decreases the data redundancy to the minimum, therefore the compression after encryption is ineffective. The compressed output usually bigger than the uncompressed input. To prevent a bigger output, use 0 compression level. This solution is good only if the zip file just a container.

Upvotes: 0

Aaron Digulla
Aaron Digulla

Reputation: 328584

Don't get confused with the streams. There is a stream which creates/updates the archive file on disk (ZipOutputStream). This stream isn't encoded, so you must leave this code alone.

What you want is to encrypt the data of the individual entries. So when you add a new entry to the archive, add a new entry with putNextEntry() as usual.

Now load the data to encrypt and create a CipherOutputStream that writes to a ByteArrayOutputStream. Encode all the data this way and then append the bytes from the ByteArrayOutputStream to the archive:

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

CipherOutputStream cos = new CipherOutputStream(buffer, key);
... encode data ...

byte[] data = buffer.toByteArray();
zOut.write( data, 0, data.length );

Note that you probably want to read the archive using ZipFile because it gives you an individual InputStream for each entry that you can wrap.

Upvotes: 3

Related Questions