Hidden Encrypted Volumes: keep data safe and secret

Use standard Linux tools to hide data so well that even Alan Turing would be stumped.

Why do this?

  • Create the ultimate device for hiding encrypted data
  • Keep some plausible deniability if your password gets coerced from you
  • Won’t somebody please think of the hamsters?

TrueCrypt development officially ended in May of 2014. It was good software and I was sad to see it go. Although there was controversy about alleged back doors in the software, the concepts it implemented are still valuable.

TrueCrypt had empowered users to secure their data with strong encryption, and even provided tools to create and use hidden volumes, which were especially useful in cases involving potential coercion. These hidden volumes provided any user with the ability to use an alternative password to attempt to fool a coercive party into thinking that the user had given them the information they believed to be hidden on the disk, while in reality exposing only decoy data.

This model relies on the ability to have two separate volumes hidden within an encrypted disk: one volume contains the actual sensitive information and the other contains the decoy information. TrueCrypt had a nice graphical interface to accomplish this, but we’ll be using command line tools. By the end we will have created a device that contains a working partition table and filesystem with normal data like movies or other media, as well as two hidden partitions: one with decoy data, and one with sensitive data. We will accomplish this using only standard Linux tools.


We write random data to the drive so that our encrypted partition will be perfectly camouflaged.

Find a device

Before you begin on this expedition you will need some kind of disposable device. The operations that we will perform on this disk will destroy all of the data that is currently contained within. Make sure that there is nothing that you have not backed up on the disk that you choose. I will be using a 2G flash drive for these experiments, though it should be noted that the way flash memory works poses challenges that will be addressed later on.

An alternative if you have no disks available for these purposes is to use a file. This is so easy that I will walk you through setting up a file for testing purposes. Those who are using a normal HDD or a flash drive may skip down to the next section.

Make a fake block device if you can’t find one

To make a file that will work for our purposes we’ll use dd. As I’m sure you are already aware, dd is a very powerful and deadly command that will smite any data in its path, so type carefully. First create the file:

$: dd if=/dev/zero of=/path/to/fake_disc bs=1024M count=2

We’ll make it into a block device using /dev/loop[0-7].

$: sudo losetup /dev/loop0 /path/to/fake_disc

Now that you have a fake disk to play with, treat it as you would any other block device, such as
/dev/sdb for the rest of this exercise.

Prepare the device

The first thing that we need to do is to randomise all of the data contained in our disc. There is some debate on how exactly to do this. The most popular methods are shred and /dev/urandom. No matter which method you use, what you need to know before you decide is how secure you need the data to be. These methods rely on using pseudo-random data from the kernel’s entropy pool. Using /dev/random is the most secure, however if the entropy pool gets empty or too low /dev/random will stop until the pool contains enough randomness for it to function. This means that it may take a very very long time to overwrite the disc, and so its usefulness is limited to only the most sensitive data and only small sizes. Shred and /dev/urandom are better options for our purposes, though some say that theoretically these are not completely invulnerable to a highly sophisticated attacker. This is often countered with a retort about paranoia and the assurance that /dev/urandom is a perfectly fine solution. I’ll let you land wherever you like on the issue.

No matter the method you choose, you can also augment your entropy pool and thus increase its effectiveness with some third-party tools that utilise noise from hardware devices to add additional entropy. One such tool is havaged (www.issihosts.com/haveged) another is aed and/or ved (www.vanheusden.com/aed). After you install any of these tools you can see how much entropy is currently available with:

$: watch cat /proc/sys/kernel/random/entropy_avail

For this exercise we’ll just use /dev/urandom.

$: sudo dd if=/dev/urandom of=/dev/sd* ## or /dev/loop0

Depending on the device you’re using this will take from a couple of minutes to a couple of days. Our 2G USB drive took about 12 minutes.

Set up the normal partition

First we’ll partition the drive.

$: fdisk /dev/sd*

Create a partition that takes up the whole drive. Feel free to use GParted or another GUI tool if you are more comfortable. The only thing that must be accomplished is the creation of a partition that utilises the entire drive. Once you are done with that, create a filesystem on the partition. Have a look in /dev/ and see if the partition is showing up before you try to create the filesystem. If you can’t find /dev/sd*1 or
/dev/loop*p1 try running:

$: sudo partprobe /dev/sda /dev/sda1 /dev/sda2 /dev/sda4 /dev/sda5 /dev/sda6 /dev/sdb /dev/sdb2 /dev/sdb3 /dev/sdc /dev/sdd /dev/sde /dev/sdf ## or /dev/loop0 if applicable

Once you’re able to see the partition in /dev/ you are ready to make your filesystem:

$: mkfs.ext4 /dev/sd*1

Now we’ll mount the partition so we can add some data.

$: mount /dev/sda1 /mnt/temp ## you can make your own test directory named whatever.

OK, now we need to put something in the filesystem like a movie or a folder full of photos or whatever you would plausibly use the partition for.

$: cp /path/to/something /mnt/temp/

Once whatever files you have chosen are done transferring, unmount the partition.

$: umount /dev/sd*1

Create the decoy

Now we get to the fun part: creating our first hidden encrypted partition. Remember when we wrote over the entire disk with random data? We did that because we want our hidden partition to be indistinguishable from the blank parts of the disk. We are going to use cryptsetup, which is a tool that lets us use the dmcrypt kernel module to create a plain hidden partition that is indistinguishable from empty disk space. Depending on your distribution you may need to install this tool yourself.

Normally when you create an encrypted partition it uses a Luks key. Luks in its default mode places a header at the beginning of the device or file that contains a hashed key in one of up to eight key slots and all of the cipher information as well. The problem is that if there is a Luks header present it proves that there is probably data hidden on the drive. What we will do is to forego this Luks header by using dmcrypt in plain mode. This mode enables us to take raw blocks from the drive and then apply a block cipher, an offset, and a passphrase to decrypt them.

There are two things to note about using the plain mode: Number one is that you must have an exceedingly long passphrase to protect your data, because instead of the passphrase unlocking a strong key and then using that key to unlock the disc, your passphrase acts as the entire key itself. I would recommend 14 random words, some special characters, and some numbers if you want military level security. However, seven random words should be just fine for a reasonable level of security. Make sure that you use a random word generator, as just coming up with seven random words from your head is not really very random. An easy way to do this is:

$: aspell dump master | shuf -n 7


$: cat /usr/share/dict/<your-lib-here> | shuf -n 7

Number two is that we also need to use the offset parameter to make sure that our hidden container doesn’t overwrite the filesystem and files that we have placed at the beginning of the drive.

We’ll use cryptsetup to open our encrypted block device. The offset parameter number represents 512 byte sectors. Use fdisk to determine the total size of the block device in 512-byte sectors; in this case we are using 2GB which is 4,194,304 512-byte sectors. We are going to put our secret partition about halfway through the drive, so our offset is going to be 2,100,000. You can also select your own cipher, but I’ll leave that to you to explore.

$: sudo cryptsetup --type=plain --cipher=twofish-xts-plain64 --offset=2100000 open /dev/sda /dev/sda1 /dev/sda2 /dev/sda4 /dev/sda5 /dev/sda6 /dev/sdb /dev/sdb2 /dev/sdb3 /dev/sdc /dev/sdd /dev/sde /dev/sdf secret

It’s important to note that what we’re actually doing is taking raw blocks off the device and running them through our encryption cipher in RAM. If you were to say, change the password that you use by even one character, you would be opening a completely new and different decrypted version of the same blocks. This also applies if your offset is off by even one 512-byte sector. This is why it is important that you save all the information in the above command, otherwise you will be unable to reopen the hidden partition. This also means that cryptsetup will never warn you if you enter the information incorrectly: it just opens the volume according to the given parameters. The passphrase, cipher, and offset are effectively replacing the Luks header that would normally exist to open the volume.

For additional security you might consider using a random offset number like 2187942 instead of 2100000, though this is certainly unnecessary since we are already employing tinfoil hat levels of security.

Now we have our first secret volume open and it will be available on /dev/mapper/secret. You can use whatever name you like for your hidden volume. All you’d need to do is change the last word of the above command. What we’ll do next is create a filesystem directly on our secret block device.

$: sudo mkfs.ext4 /dev/mapper/secret

Now that we have our hidden filesystem, let’s mount it somewhere.

$: sudo mount /dev/mapper/secret /mnt/temp

Go ahead and put some secrets in there! Once you’re finished, unmount the hidden filesystem and close the block cipher with:

$: sudo umount /mnt/temp $: sudo cryptsetup close /dev/mapper/secret

Unplug the USB or reboot and test to see if the first partition we set up is available. You should now have a disk that looks as though it has a normal working partition table with data in it. Now it’s important to remember that if you write to this device you risk destroying the encrypted data. This is especially true for solid state memory, so it’s important to place all of the top-level data that you want to use on the device before you create the hidden volumes. To open that hidden volume you need to first unmount the top level partition then run the same cryptsetup command we used earlier.

$: sudo umount /dev/sd*1 $: sudo cryptsetup --type=plain --cipher=twofish-xts-plain64 --offset=2100000 open /dev/sda /dev/sda1 /dev/sda2 /dev/sda4 /dev/sda5 /dev/sda6 /dev/sdb /dev/sdb2 /dev/sdb3 /dev/sdc /dev/sdd /dev/sde /dev/sdf secret

Enter your passphrase again and then mount the secret partition wherever you like.

$: sudo mount /dev/mapper/secret /mnt/temp

What we have created is a normal looking device with information on it that can be read and used normally, as well as a hidden volume that can not even be proven to exist at all.

Now I know some of you are thinking: “Isn’t it suspicious to have a device that has been completely randomly overwritten and only contains a little data at the beginning of the drive?” Well yes, it may be suspicious. Although it cannot be proven that any real data exists at the end of that drive, we can make it even more resistant to potential coercion.

Let’s say you have some powerful enemies and they’ve looked very hard at the device and decided that you do in fact have an encrypted volume on the end of your drive and they’re going to make you open it or they will drown your beloved hamster Leopold right before your very eyes. These guys are not going to take “uh, I forgot the password.” for an answer. What we can do in this case is nest another hidden volume within the previous volume “secret” that we created. We’ll call this the inception volume.


With a couple of Linux commands, we can use /dev/ mapper just like any ordinary block device.

Create the hidden, hidden partition

Let’s assume we have anticipated the above hamster hostage scenario as a possible outcome and prepared accordingly. For this scenario we’ll have a normal-looking drive with normal data on it, and we’ll have a hidden encrypted volume on the end of the drive containing yet another hidden encrypted volume within. What we are going to do is assume that we are going to have to give up the keys to our first hidden encrypted volume.

The first hidden volume will contain only decoy data. The decoy data should be convincing – after all, you need this coercive party to believe it was at least worth encrypting. We’ll assume you best know what plausible data you might want to hide but wouldn’t mind being revealed to an attacker in an emergency.

What we are going to do is treat /dev/mapper/secret the same way we previously treated /dev/sd*; as a plain block device. You’ll need to generate another password and calculate another offset. For this example we’ll just cut the last offset we used in half to 1050000, which should give us about 300MB of inception volume space.

Open the secret partition we previously created, and instead of secrets, place some decoy data into it. It should already be mounted on /mnt/temp from the previous step. I’d suggest that you use no more than 30% of the available space. After you have finished writing the decoy data, unmount the partition

$: sudo umount /dev/mapper/secret

Now create the inception partition using /dev/mapper/secret as the target block device. Remember to generate a new random password and use the new offset for this volume.

$: sudo cryptsetup --type=plain --cipher=twofish-xts-plain64 --offset=1050000 open /dev/mapper/secret inception

You should now see /dev/mapper/inception, which is the true hidden volume. Let’s make a filesystem on
/dev/mapper/inception as we did with our first hidden partition.

$: sudo mkfs.ext4 /dev/mapper/inception

We can now mount the inception volume.

$: sudo mount /dev/mapper/inception /mnt/temp

This is now where you would place your super secret sensitive data. Note that this setup is unstable when using any kind of solid state technology such as a USB flash drive. It can certainly be done if you are careful about not writing too much to the drive after its creation. After you have finished placing your sensitive data into the inception partition you can close the disk:

$: umount /dev/mapper/inception $: sudo cryptsetup close /dev/mapper/inception $: sudo cryptsetup close /dev/mapper/secret

Unplug the disk then plug it back in. You should see only the top-level partition containing the media we placed there in the beginning. To access your hidden, hidden data you must open both encrypted volumes after first unmounting the top level partition (if it was auto-mounted).

$: umount /dev/sda1 $: sudo cryptsetup --type=plain --cipher=twofish-xts-plain64 --offset=2100000 open /dev/sda /dev/sda1 /dev/sda2 /dev/sda4 /dev/sda5 /dev/sda6 /dev/sdb /dev/sdb2 /dev/sdb3 /dev/sdc /dev/sdd /dev/sde /dev/sdf secret $: sudo cryptsetup --type=plain ==cipher=twofish-xts-plain64 --offset=1050000 open /dev/mapper/secret inception $: mount /dev/mapper/inception /mnt/temp

This technique illustrates some of the powerful things that one can accomplish using standard Linux tools. The Linux ecosystem is set up in a way that promotes creativity by freely providing powerful tools that can be used in many different ways. I invite you to explore cryptsetup and dmcrypt more fully, as there are many more amazing things that you can accomplish with these tools.


You can never have enough levels of security. If you’re concerned, add more.


Flash memory isn’t allocated in contiguous blocks; blocks are instead allocated based on wear-levelling. There is a controller in every flash drive that keeps track of the pages in the drive and calls upon them in a manner that distributes writes evenly in order to maximise the drive’s life. For this reason if you are using a flash drive I would recommend that you keep the non-hidden partition mostly empty and to set the file attributes on any files contained therein to noatime. This can be done with the chattr command:

$: chattr -a /path/to/files/*

This will minimise the chance that accessing data in the top-level partition will destroy data in the decoy or inception volumes. Also while using solid state memory you should always avoid writing to the device after it is initially created, as every time you do you risk destroying your hidden data. Instead, it would be safer to build an entirely new set of hidden partitions each time you would like to add secret data to your device. This process could easily be scripted in Bash.

The partition scheme we created was tested 10 times on a single flash drive to determine if failures were likely to occur during the creation process. These tests were performed on a 2GB USB flash drive that was about 25% full on the top level. There were 15 decoy files totalling 151MB on the decoy volume and 8 inception files totalling 81MB on the hidden, hidden volume. There were zero failures out of 10, however you should always thoroughly test the volumes after creation and make backups of important data. The limit to how much you will be able to add to the drive after its initial creation will depend on the specific flash drive’s page size and the size and number of files you’ve added.

Jake Margason isn’t paranoid; he just knows that everyone really is out to get him.