Steganography is the term given to the art of hiding a message, for example in a photograph, in such a way that unless you know it’s there you wouldn’t suspect it was there.

While this is, to some extent, security through obscurity, it can be handy in some situations. Since a cursory look at the files will show something relatively innocuous (holiday snaps for example), an attacker may not notice the presence of the hidden data, and so move on without even attempting to break it.

There are many sophisticated technologies for doing this, however you can do a basic version using fairly standard unix tools.

Preparing your files

The first step is to encrypt your data.

To some extent, this is optional, however should your ruse be rumbled you can be sure that your precious data doesn’t fall into the wrong hands.

gpg -e -u "you@example.com" -r "them@example.com" businessplan.doc

Then, you compress the output using Zip. This is important, since unzip will ignore anything it doesn’t recognise as zipped data, which we’ll get onto later.

zip businessplan.zip businessplan.doc.gpg

Hiding your file

Hiding your file in an image is relatively straightforward.

cat photo.jpg businessplan.zip > myholiday.jpg

What’s happening here is that we’ve combined a photo and your encrypted zip file together into one file (order is important). Your image viewers will only see the first image file, and anyone looking at the directory will just see a (somewhat large) jpeg. If thumbnails are enabled you’ll just see the contents of photo.jpg.

Retrieving your file

To retrieve your file, all your recipient needs to do is run unzip the image file. Unzip will skip over the jpg content with a warning, and then reveal the hidden file. They then need to unencrypted it using their secret key.

unzip myholiday.jpg
gpg -d businessplan.doc.gpg > businessplan.doc

In conclusion

This technique will allow you to hide an encrypted file in a jpeg image, which affords you a certain amount of extra protection. Unless you know a particular image contains encrypted data (or suspect it might and look a little harder) then chances are the presence of the encrypted data won’t be discovered. However, this technique is probably pretty easy to spot if an attacker is looking for it, or performing any kind of data analysis on the file (or even looking at the file size, which could be a give away depending on how much data you’re hiding).

If you are a journalist carrying evidence of war crimes or mass surveillance programs to Brazil, you are likely facing some highly skilled adversaries, so this technique is probably not suitable. But, if you’re a business person who wants to take your new business plan securely across a border without the hassle of possibly being detained and forced to decrypt the file, then this might be more useful.

In any case, I thought it was pretty cool, and I thought I’d share.

I have spent the last couple of hours grappling with this problem, and having finally got to the bottom of it I’d thought I’d share my solution.

Ok, so the problem was that a PHP script which prepared a download (in this case a .zip) from Elgg’s file store was working fine in Firefox but producing a corrupt archive in IE.

On examining the headers being sent and received I was able to establish that there were two main issues going on:

  1. The zip file was being compressed by mod_deflate, this was being incorrectly handled by Internet Explorer, and so was producing a file which was actually a gzipped .zip file. This is a known issue, and is why Elgg’s .htaccess file only compresses text and javascript.
  2. The code which only permits compression for text mime types was being ignored.

The reason, obvious with hindsight but not at the time, was this:

The file was being served by a script, this script modifies the mimetype via header. However, apache was determining whether to compress the file or not based on the initial mimetype of the script – which of course was text/html!

Once I figured that out, it was fairly simple to solve. I added the following lines to the mod_deflate settings in the .htaccess file.

SetEnvIfNoCase Request_URI action\/* no-gzip dont-vary
SetEnvIfNoCase Request_URI actions\/* no-gzip dont-vary

These lines turn off gzip compression for all actions, while leaving compression running for all other files. This solution is better than turning compression off altogether but it is not ideal, for one if you attempt a script download from anywhere but an Elgg action (which really you shouldn’t be), you will need to modify .htaccess yourself.

Any better solutions welcome!