Plausible Deniability With LUKS

Posted:   |   Прочесть по-русски   |   Leer en español   |   More posts about LUKS security software

In this article I'll tell you how to set up hidden crypto-container using regular means of Linux OS (LUKS and cryptsetup). Standard features of LUKS (such as using external headers and placing actual data by predefined offset) allow user to access hidden data within existing container and deny existence of such data.

UPD[31/05/2014]: This post was ready more than a month ago, and those days I could not even imagine such strange sudden death of TrueCrypt. Well, maybe this project isn't completely dead, let's see… Nevertheless in the following text I leave references to TrueCrypt as is.

What is “plausible deniability”?

You can find very long and detailed definition of this term in Wikipedia: In short it means that you can do or have something and nobody can suspect and prove that (if you don't admit it, of course). And then you can deny having or doing that thing, if someone want to accuse you, because (let's repeat it) nobody can prove it. E.g., if a kid kicks his little brother's ass while nobody see and the brother goes for seeking justice to their parents, then what happens?

Well... Nothing. Because the kid will deny that he kicked his brother and the parents can't catch him this time (there are no witnesses and the brother himself could play his dirty game). So nobody will be punished. Or, what's worse, the both will be punished just in case. So this is an example of plausible deniability for such kid prone to violence. But all we are, of course, well-behaved people, and use hidden container only to protect our personal data from bad guys. Who's good and who's bad in such case is big question, but… Let's get down to the business.

General idea of realization

Suppose we want to save some sensible data inside encrypted file. In general we'll use some cryptographic software, which does the most job for us. Maybe we want to work with an encrypted file such as with virtual disk, this significantly narrows a number of candidates. But the main property of all such programs is that they operate with the file as with one big chunk of encrypted data. That is user supplies one password (maybe adding some “spare” passwords) for all the data in the container. It means that there is just one weak point: the container password. I don't want to mention that the password must be cryptographically robust, as it's obvious. I mean that if a user of such software has to reveal the password (e.g. under the pressure), all the data will be revealed as well. And this is sad and wrong, I think…

Well, there is a hope, though. :) For example, there is such program as TrueCrypt, which is rather clever. User can create two containers in one file: the first is a fake with several “improper”, but relatively safe files, and the second is real one with the data, which should not be found in neither case. Hence TrueCrypt asks two different passwords, when a user wants to create such “double” container. Later user enters only one password for “real” part and works only with it. When and if under pressure of external circumstance the user is to show contents of the encrypted disk to third party, he just enters the second password, and TrueCrypt opens fake part of the container. It should be stressed (as it's very important), that there is no ability to prove the existence of “hidden” part, if investigator doesn't know corresponding password.

And now let's see, how it works… In reality things are very simple. Software divides a file by two (generally speaking, uneven) parts. The first part, that may be rather small, contains fake data; the second part contains real data. So the program must maintain two different headers (configurations) for two different parts and choose which part to decrypt depending on a password supplied by user. And this is not the most trivial part of the work. Just because “officially” only fake configuration should be visible: if there is a standard header in the container, it should be fake header, if decryption parameters are in separate config file, such parameters should allow to decrypt only fake part. No clues about real part of the container should appear after decryption of the fake part. They must be completely independent. Moreover, when the fake part is opened, software must show full capacity of encrypted drive, even though real capacity of the fake part is much smaller.

So, what about LUKS?

There are good news and... Well... And better news.

The good news are that cryptsetup can decrypt and mount volumes created with TrueCrypt. Read-only, though, but it doesn't matter. Because of better news. Namely, we can create “hidden” container using just cryptsetup. Moreover, this utility allows create any number of “hidden” parts. Of course, within reasonable limits. And that's how to do this.

But before we continue,


  • All described below can cause irrecoverable damage to your data.
  • Using strong cryptography can be prohibited in your region, so you may be thrown in jail not for real information, but just for crypto-container, which have been found on your hard drive.
  • Cryptography can protect your data, but can't protect you from torture. Hidden container can save your valuable information, but you can't deny its existence in case of betrayal or denunciation.
  • Guys who are interested in your encrypted data can be found not so dumb as you thought. Even if they could not prove existence of hidden part of the container, they can leave you in a ward with inveterate criminals, and in a couple of days you'll remember all your passwords to all your hidden data.
  • If you have significant other and/or close relatives or friends, they also can become a target for pressure. And such fact can make significantly easier for you to remember all, even what you didn't know.

Hence, think twice if your information is worth your life and life of your loved ones. And backup your data. Just in case.

OK, you've been warned, let's go further.

man cryptsetup can tell us about some interesting command-line parameters of this utility. For example, let's see --header option:

--header <device or file storing the LUKS header>
  Use a detached (separated) metadata device or file where the LUKS header is stored. This options allows to store ciphertext and LUKS header on different devices.

Good. It means that we can have volume full of random crap without any determinate signature. Description of this option contains a bit more information, precautions and warnings, but the essential is just that. Yet I earnestly recommend you to read that fine manual.

Another very useful option is --align-payload, which allows to place actual data by some offset apart of the beginning of the volume:

--align-payload <number of 512 byte sectors>

Align payload at a boundary of value 512-byte sectors. This option is relevant for luksFormat.

If not specified, cryptsetup tries to use the topology info provided by kernel for the underlying device to get optimal alignment. If not available (or the calculated value is a multiple of the default) data is by default aligned to a 1MiB boundary (i.e. 2048 512-byte sectors).

For a detached LUKS header this option specifies the offset on the data device. See also the --header option.

And this is nice too, because now we are free to move our data to any part of the volume. You get the idea, don't you?


  1. Initialize the volume you want to encrypt: overwrite it entirely with random data.
  2. Make “official” encrypted volume and save to it some infected warez, pirated music, porn useful freeware utilities, your amateur garage-rock band records, love-story movies etc., i.e. some content for which you'll be sentenced no more than a couple of years conditionally.
  3. Using mentioned earlier esoteric options of cryptsetup make hidden volume (within the “official” one) saving its header to external medium. There you can keep really dangerous data (such as your photos from your kindergarten or your plans to conquer the world).

That's all, folks! There is no magic. Obviously, you should not stuff your “official” encrypted disk with crap up to the hilt, because the space is shared between it and hidden one. And as I said at the beginning, you can, if you want, create several hidden disks following the same logic.

Well… If you still need more information, specially for you there is

Step by step guide


The following commands will destroy your data, if you execute them mindlessly. Damage will be irrecoverable, because utilities such dd work at low level (i.e. below filesystem layer). So it will be impossible roll back or undo it, even if you cancelled that command just after it has been started.

Don't do it, if you can't cleanly explain how every step relates to your goal. And make backup. Now.

Suppose we have some drive with several partitions. Let it be, for example, /dev/sdb. And let /dev/sdb1 be relatively small (8Gb) partition assigned for encryption. We'll divide it 5 to 3, where 5Gb piece will be “official” part and 3Gb — hidden part. Suppose also that we want to keep a secret storage key on our hard drive in /etc/keys and hidden container header on external usb stick mounted in /media/user/ExtUSBStick. I assume you know how to set permissions on your key storage, how to setup encfs/ecryptfs to securely keep secret files on unsecure devices and that really secret keys should be copied and keeped in two or three different vaults in different locations.

Okay, it's enough of grumbling. Come to the point.

  1. Initialize device /dev/sdb1:

    dd if=/dev/urandom of=/dev/sdb1 bs=16M
  2. Make a key for encrypted volume. 512 bits (64 bytes) random key is more than enough:

    dd if=/dev/urandom bs=64 count=1 >/etc/keys/secret.key 2>/dev/null
  3. Encrypt volume using brand new key:

    cryptsetup luksFormat /dev/sdb1 /etc/keys/secret.key
  4. Open encrypted device and set up mapping secretdata:

    cryptsetup luksOpen --key-file /etc/keys/secret.key \
    /dev/sdb1 secretdata
  5. Create filesystem on encrypted volume (e.g., btrfs):

    mkfs.btrfs -L SecretData /dev/mapper/secretdata
  6. … and mount it:

    mount /dev/mapper/secretdata /var/secretdata/
  7. We remember about 5G limit, so enable subvolume quota:

    btrfs quota enable /var/secretdata/
  8. As btrfs quotas can be applied to subvolumes only, let's create a subvolume:

    brfs subvolume create /var/secretdata/workingvolume
  9. … and apply the mentioned quota (note that btrfs subvolume can be mounted as usual filesystens, so in the future you probably want mount this subvolume instead whole fs):

    btrfs qgroup limit 5G /var/secretdata/workingvolume
  10. Fill it up with some data:

    debootstrap --variant=buildd testing /var/secretdata/workingvolume
  11. That's all, now we can forget about this part:

    umount /var/secretdata
    cryptsetup luksClose secretdata
  12. Now create dummy file for header and pack it with some random crap:

    dd if=/dev/urandom of=/media/user/ExtUSBStick/hidden.head bs=4M count=1
  13. And now is the very moment, when real magic begins. (What? I said, there's no magic? I lied.) We use the same key, but not entire file, just half of it (32-byte offset). Nevertheless 256 bits of random data is still good enough for encryption key. Then we detach the header and place it on the external flash-drive. And finally we tell cryptsetup that we want displace our hidden container by 5Gb (i.e. 10485760 512-byte blocks) from the beginning of the volume:

    cryptsetup --keyfile-offset 32 --header /media/user/ExtUSBStick/hidden.head \
    --align-payload 10485760 luksFormat /dev/sdb1 /etc/keys/secret.key
  14. Yes, it's all so simple. Now open new encrypted device:

    cryptsetup luksOpen --key-file /etc/keys/secret.key --keyfile-offset 32 \
    --header /media/user/ExtUSBStick/hidden.head /dev/sdb1 realsecretdata
  15. Make any filesystem you want:

    mkfs.btrfs /dev/mapper/realsecretdata

And so on…