LUKS hidden volume with plausible deniability

There is an option --header <device or file storing the LUKS header>to 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. 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: 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).

Initialize device /dev/sdb1: dd if=/dev/urandom of=/dev/sdb1 bs=16M 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 Encrypt volume using brand new key: cryptsetup luksFormat /dev/sdb1 /etc/keys/secret.key Open encrypted device and set up mapping secretdata: cryptsetup luksOpen --key-file /etc/keys/secret.key /dev/sdb1 secretdata Create filesystem on encrypted volume (e.g., btrfs): mkfs.btrfs -L SecretData /dev/mapper/secretdata mount it: mount /dev/mapper/secretdata /var/secretdata/ Remember about 5G limit, so enable subvolume quota: btrfs quota enable /var/secretdata/ As btrfs quotas can be applied to subvolumes only, let’s create a subvolume: brfs subvolume create /var/secretdata/workingvolume 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 Fill it up with some data: debootstrap --variant=buildd testing /var/secretdata/workingvolume Now we can forget about this part: umount /var/secretdata cryptsetup luksClose secretdata 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 And now is the very moment, when real magic begins. 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 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 Make any filesystem you want: mkfs.btrfs /dev/mapper/realsecretdata