You probably know TrueCrypt, the perhaps most popular tool for encrypting filesystems. As an alternative to full filesystem or even full disk encryption, TrueCrypt can also work with filesystems inside encrypted container files. These are files that look like they’re full of purely random data, but when provided the correct decryption key, they reveal their true contents: A FAT or NTFS filesystem full of your secret data.
In addition to this basic functionality, TrueCrypt also offers a simple form of steganography. For the uninformed, steganography is the term for techniques that conceal the existence of secret data. This means that the secret information is hidden inside another unsuspicious piece of data. TrueCrypt does support this with its »hidden volume« feature. If this is used, a container can be opened with two different keys: The first not-so-secret key opens the »outer volume« with not-so-secret data and a second really secret key opens the hidden volume with the real secrets. There are two problems with this approach, though: First, it’s very simple to destroy the hidden volume since it’s embedded in the outer volume’s data area without proper marking in the outer volume filesystem’s meta-data (otherwise they would give away the presence of the hidden volume). This means that you can overwrite the hidden volume just by putting enough files inside the outer volume. TrueCrypt can protect the hidden volume when mounting the outer volume, but for this to work, you need to provide the hidden volume’s key.
The second issue with TrueCrypt’s approach to steganography is that TrueCrypt container files are just large files with random data and as such, they’re easily detectable. You can disguise them by giving them unsuspicious filenames –
hiberfil.sys in a drive’s root directory are good candidates on Windows systems, for example. But then again, even these filenames are highly suspicious when found on removable media. So let’s use the next best thing: video files. These also tend to be very large and offer a good disguise for hidden data, but unfortunately, they are very easy to detect: Just try to play such a pseudo-video file and whatever player you use, it will tell you that something’s wrong.
So what we really want to call it proper steganography is a usable file that can be opened with standard software so it doesn’t raise any suspicion, but when opened in TrueCrypt with the right key, it should reveal the real payload – a filesystem full of secrets. Video files are the natural choice as for this kind of hack: Multi-gigabyte videos are completely common nowadays and encoders are so good that even large differences in bitrate don’t necessarily mean large differences in quality. In other words: A well-encoded fifteen-minute HD video clip of 1 gigabyte can look just as good as a not-quite-as-well encoded 4 gigabyte version. So let’s put the 3 gigs we can save to good use and store secret data there.
Unfortunately, this can’t be done using TrueCrypt directly. However, with a little bit of file format tweaking, it turns out to be possible anyway. In this blog post, I will describe a method of hiding TrueCrypt containers inside QuickTime / MP4 video files.
In fact, construction of such a »hybrid« steganographic file is just an application of a common discipline in esoteric computing: It’s all about generating a file that is valid in multiple formats. For example, you can create PDF files that are also ZIP files (see here). In this case, we want TrueCrypt container files that are also usable in some other common format. I decided to go for the QuickTime or MP4 format here, because it’s common, useful and easy to understand.
The TrueCrypt format
Let’s see how a TrueCrypt container file is organized. Obviously, there’s no structure that is easily detectable, e.g. with a hex editor. All headers are encrypted and can only be decrypted with the proper key. This is by design, because it’s a stated goal that TrueCrypt containers shall look like random garbage and thus must not have any unencrypted headers in them. However, the location and size of the headers is well-defined and documented: The main header of the outer volume is located at offset 0 in the file and can be up to 65,535 bytes in size (of which usually just a few hundred are used). This means that we can’t create a hybrid file with a format that requires header data within the first 64k bytes without sacrificing the volume header. The bad news is that there’s no format I know of that fulfills this constraint. But the good news is that we don’t need it anyway: As it turns out, the hidden volume header, located at offsets 65,536 to 131,072, is sufficient to mount a hidden volume. So we can overwrite the first 64k bytes of a TrueCrypt file with anything we want – file headers of another format in our case – and still have access to the hidden volume. The outer volume will be lost then, but this is an acceptable trade-off. After all, we can make the hidden volume as large as possible when creating the container and the only space we lose is the filesystem overhead of the outer volume, which is typically less than 5 percent of the volume size.
In addition to the two volume headers, there are backups of both starting at 128k before the end of the file. Since we’re going to append data to the TrueCrypt file to store the data of our video file, we are going to lose those, too. (Strictly speaking we’re not necessarily losing them, it’s just that TrueCrypt won’t find them any longer.) However, TrueCrypt will only resort to the backups if the main headers are damaged, so this is no issue.
So the task is clear: We can create a hybrid file with a hidden TrueCrypt volume out of an existing TrueCrypt container file by appending data and rewriting the first 64k of the file at will. We now need to re-construct our disguise file to meet these requirements. In particular, we need a way to create some empty space between the 64k mark and the end of the TrueCrypt volume that is ignored by applications reading the file in the format that it claims to be.
The QuickTime format
The QuickTime format and the MPEG-4 file format (ISO 14496-14), which is based on it, consists of so-called »atoms«. These are chunks of data consisting of a 4-byte length value, a 4-byte ASCII type identifier and an arbitrary amount of payload which may be composed of sub-atoms again. We’re (almost) only interested in top-level atoms here, though.
There are three top-level atoms that are required in every proper QuickTime or MP4 file: The main file header (atom ID ‘
ftyp‘), which is just a few bytes; the media header (»movie« header, atom ID ‘
moov‘) which is in the range from a few kilobytes to a few megabytes; and finally the main media data (atom ID ‘
mdat‘). Regarding the file layout, the only restriction enforced by the file format specification is that the
ftyp atom must start at the beginning of the file, all other atoms may be reordered at will. In particular, it is not required that
moov (the media header) precedes
mdat (the media data).
There are some additional atom types that are common, but are not required to make a file playable, so we can remove these without risk of damage. The most prominent one is ‘
free‘: Such atoms are just placeholders and don’t contain any useful data. Think of these as the QuickTime equivalent of comments.
One interesting thing to note about
mdat is that it doesn’t have any proper enforced structure. From the file format’s point of view,
mdat is just a big blob of data that happens to contain media samples (i.e. audio and video frames). Where these samples can be found is specified in so-called »chunk offset tables« (atom ID ‘
stco‘) inside the
moov atom. These tables contain file offsets for each chunk of samples of the movie. The nice thing is that all parts of the file that are inside
mdat but are not referenced by the
stcos are ignored by a player and thus usable for our steganographic hacks.
Creating an innocent-looking QuickTime/TrueCrypt hybrid
In practice, I found all MOV and MP4 files follow one of two different structures: The most common one is simply
mdia, sometimes with a
free at the end containing version information about the tool used to generate the file. The other common pattern is
moov (often with a very small 8-byte
mdat as a placeholder for 64-bit offsets should the file grow above 4 GiB later on). This is a very useful layout for our purposes: We can fake this one easily and still maintain the illusion of a perfectly legitimate QuickTime file. We just put the real
mdat right after the end of the TrueCrypt volume, followed by the
moov header. Then we generate a new
mdat that spans both the TrueCrypt volume and the real media data. Since we change the file offsets of the media samples in this process, we need to adjust the chunk offset tables, but this is manageable. For maximum credibility, we copy the first kilobytes of the original
mdat to the front of the file. This way, the file looks innocuous even when viewed in a hex editor – for example, if the file was encoded with x264, the encoder’s SEI message is still visible.
Here’s a figure that illustrates the embedding process (not to scale):
There are only four ways to detect the presence of the hidden volume, all of which are unlikely to be checked even by a knowledgeable person. The easiest way to tell about the manipulation would be bitrate monitoring: If a player tells you that the stream has a bitrate of 1 Mbps, but by analyzing the file size, you can compute that it must have at least 5 Mbps, you can tell something is amiss. But who looks at bitrates this detailed? The only other ways would be (1) a sophisticated packet-by-packet analysis of the
mdat data that would find out that from offset 65,536 on, there’s not only random-looking compressed data, but random-looking garbage; (2) checking for a repetition of the first 64k of
mdat somewhere later in the file and (3) seeing that there’s much unused space in the
mdat that isn’t referenced by any chunk offset table. I can imagine, in theory, that there might be tools to do the latter, but until someone shows me such a tool, I boldly declare my method as safe :)
I implemented this approach in a Python 2.x script (not compatible with Python 3.x!):
To generate a steganographic TrueCrypt/QuickTime hybrid using the script, do the following:
- Find a good candidate QuickTime or MP4 file to use as a disguise, let’s say
SomeVideo.mp4. The file should be encoded in a very efficient way so that an increase in filesize is believable in relation to the length and quality of the video. Estimate how much larger the file may become without becoming suspicious.
- Use TrueCrypt’s Volume Creating Wizard to create a new hidden(!) TrueCrypt volume.
- Use the name of the final hybrid file as the container file name, e.g.
- As the outer volume size, enter the estimated maximum enlargment from step 1.
- Don’t bother entering a good password for the outer volume, it will be destroyed anyway.
- Use the maximum possible size for the hidden volume. Enter the size in KB instead of MB and do a bit of number guessing – the »Next« button in the wizard is disabled when the size is too large. Find the maximum size where the button is still clickable. (Technically, you could enter lower values, but why should you? Every byte left to the outer volume is a wasted byte!)
- Use your real ultra-secret password or keyfile for the hidden volume.
- Do not mount the outer volume! You will likely destroy the hidden volume otherwise.
- Use the name of the final hybrid file as the container file name, e.g.
- Use the script:
python tcsteg.py SomeVideo.mp4 InnocentLookingVideo.mp4
This will modify the TrueCrypt container file in-place. It might still take a while to process, since the disguise file is basically copied over into the container file.
- If everything worked, you will now have a file that
- looks like a video file in every way
- can be played as a video file using normal video player applications
- can still be mounted in TrueCrypt as a hidden volume
- is very hard to detect as a hybrid file
Sounds neat, eh? ;)
The script currently has one major caveat: It only supports files with a total output size of 4 GiB at a maximum. This is mainly due to laziness – it is left as an exercise to the reader to extend the script to larger files. (This task even comes in two complexity levels: If the input QuickTime file is already larger than 4 GiB, it’s a walk in the park. However, if the original QuickTime file was smaller and only grows above the limit because of the TrueCrypt volume hidden in it, good luck replacing the
co64s and adjusting all the atom hierarchy in the
moov to accomodate for the change ;) And while we’re speaking of interesting homework: if somebody feels like adding other formats, I’d be happy to update the script as well.
Update (2012-02-18): Vladimir Ivanov has contributed an updated version of the script – it now handles 64-bit QuickTime files properly and can also extend 32-bit files to 64-bit if they grow above the limit because of the hidden container. There’s also a new option to temporarily modify the hybrid file in a way that makes it possible to change the TrueCrypt password of the encrypted volume.