dm-crypt (or Device Mapper crypt) is the Linux kernel's infrastructure for creating encrypted block devices. It works between the physical (or virtual disk) partition and the filesystem, transparently encrypting data as it's persisted to storage and decrypting it on recollection.
There are two configuration models:
- LUKS (strongly recommended) allows keys to be placed in up to 16 slots and provides convenient CLI tools for their management. This is what we deploy.
- Plain mode simply encrypts and decrypts data using the specified passphrase, without support for management of multiple keys.
cryptsetup command is used to manage encrypted volumes. Note that for all of the below commands that utilise key slots, the key slot will default to the first key (numbered from zero) where not specified.
Loss of the header means loss of the data
You must take care to not damage or, in the case of detached LUKS headers where the header is stored in a separate file outside of the partition, lose the header. Losing the header renders the contents of an encrypted volume unrecoverable.
Opening an encrypted container
To access the data within an encrypted container we need to open it:
$ sudo cryptsetup luksOpen test-disk.img my-test Enter passphrase for test-disk.img:
This will expose the device in
/dev, which we can then mount as usual:
$ sudo mkdir /mnt/test $ sudo mount /dev/mapper/my-test /mnt/test $ sudo ls /mnt/test lost+found
Closing an encrypted container
First ensure that any mounted volumes on it are unmounted. You can identify these with
lsblk to list the devices and
mount to list the active volumes:
$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 89.1M 1 loop /snap/core/8039 loop1 7:1 0 89.1M 1 loop /snap/core/8268 loop2 7:2 0 56.4M 1 loop /snap/powershell/39 loop3 7:3 0 56.4M 1 loop /snap/powershell/77 loop4 7:4 0 100M 0 loop └─my-test 253:3 0 84M 0 crypt /mnt/test nvme0n1 259:0 0 931.5G 0 disk ├─nvme0n1p1 259:1 0 512M 0 part /boot/efi ├─nvme0n1p2 259:2 0 732M 0 part /boot └─nvme0n1p3 259:3 0 930.3G 0 part └─nvme0n1p3_crypt 253:0 0 930.3G 0 crypt ├─ubuntu--vg-root 253:1 0 929.3G 0 lvm / └─ubuntu--vg-swap_1 253:2 0 976M 0 lvm [SWAP] $ mount | grep my-test /dev/mapper/my-test on /mnt/test type ext4 (rw,relatime) $ umount /dev/mapper/my-test $ rm -rf /mnt/test
Then close it:
sudo cryptsetup luksClose my-test
Listing enabled encrypted volumes
You can find a complete list of device mapper targets known to the system using
$ sudo dmsetup ls --target crypt my-encrypted-data-disk (253, 2) my-encrypted-os-disk (253, 1)
Note that the device names shown here will be the names of the decrypted devices -- the ones within the encrypted container. Most
cryptsetup commands operate on the container itself, so we'll need to know the names of the backing devices. The easiest way to visualise this is
lsblk -- just look at the line above the volume you're interested in:
$ sudo lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 30G 0 disk ├─sda1 8:1 0 29.7G 0 part │ └─my-encrypted-os-disk 253:1 0 29.7G 0 crypt / ├─sda2 8:2 0 256M 0 part /boot ├─sda14 8:14 0 4M 0 part └─sda15 8:15 0 106M 0 part /boot/efi sdb 8:16 0 40G 0 disk └─sdb1 8:17 0 40G 0 part /mnt sdc 8:32 0 48M 0 disk └─sdc1 8:49 0 30G 0 part └─my-lvm-lv 253:0 0 60G 0 lvm └─my-encrypted-data-disk 253:2 0 60G 0 crypt /mnt/data sde 8:64 0 30G 0 disk └─sde1 8:65 0 30G 0 part └─my-lvm-lv 253:0 0 60G 0 lvm └─my-encrypted-data-disk 253:2 0 60G 0 crypt /mnt/data
From the above we can deduce that our
dm-crypt backing devices are as follows:
You can drill down into the properties of an individual volume with
Decrypting filesystems at boot
Filesystems to be decrypted during boot will be listed in
# <target name> <source device> <key file> <options> my-encrypted-data-disk /dev/mapper/storage-data /mnt/azure_bek_disk/LinuxPassPhraseFileName_1_1 luks,nofail
The target names define the name of the mapped volume in
/dev, which can then be added to
/etc/fstab or similar for automatic mounting.
Using an encrypted root filesystem
Decrypting the root (
/root) filesystem requires some steps in addition to ordinary volumes. Because the root filesystem is not yet available, all tools required in the decryption chain must be available in the initrd, achieved in Ubuntu by installing
Formatting a new container
Don't run these commands on a system you don't have complete backups for -- there's a pretty good chance you'll lose data.
sudo cryptsetup luksFormat test-disk.img WARNING! ======== This will overwrite data on test-disk.img irrevocably. Are you sure? (Type uppercase yes): YES Enter passphrase for test-disk.img: Verify passphrase:
Backing up the LUKS header
When making changes (e.g. changing keys) it's advisable to take a backup of the volume's LUKS header data. If this becomes corrupted and no backup is available any data on the disk will not be recoverable.
sudo cryptsetup luksHeaderBackup --header-backup-file test-disk-header test-disk.img
Restoring the LUKS header
Use the same arguments as with
$ sudo cryptsetup luksHeaderRestore --header-backup-file test-disk-header test-disk.img WARNING! ======== Device test-disk.img already contains LUKS2 header. Replacing header will destroy existing keyslots. Are you sure? (Type uppercase yes): YES
To print the information contained in the header of the disk along with the status of the key slots for a given volume:
$ sudo cryptsetup luksDump test-disk.img LUKS header information Version: 2 Epoch: 3 Metadata area: 16384 [bytes] Keyslots area: 16744448 [bytes] UUID: 00000000-0000-0000-0000-000000000000 Label: (no label) Subsystem: (no subsystem) Flags: (no flags) Data segments: 0: crypt offset: 16777216 [bytes] length: (whole device) cipher: aes-xts-plain64 sector: 512 [bytes] Keyslots: 0: luks2 Key: 512 bits Priority: normal Cipher: aes-xts-plain64 Cipher key: 512 bits PBKDF: argon2i Time cost: 4 Memory: 1048576 Threads: 4 Salt: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AF stripes: 4000 AF hash: sha256 Area offset:32768 [bytes] Area length:258048 [bytes] Digest ID: 0 Tokens: Digests: 0: pbkdf2 Hash: sha256 Iterations: 147603 Salt: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Digest: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Adding a new key
In corporate environments it's often necessary for the organisation to be able to decrypt the contents of the disk as well as the user of the machine. LUKS allows us to do this by providing up to 16 key slots for us to fill. To add a new key:
$ sudo cryptsetup luksAddKey --key-slot 1 test-disk.img Enter any existing passphrase: Enter new passphrase for key slot: Verify passphrase:
Changing an existing key
To change a key in one of the slots you need to know any one of the existing keys:
$ sudo cryptsetup luksChangeKey test-disk.img Enter passphrase to be changed: Enter new passphrase: Verify passphrase:
Deleting a key
To delete a key, specify the volume path and the key slot number. Note that you don't use the
--key-slot option as the key slot number is required.
$ sudo cryptsetup luksRemoveKey test-disk.img Enter passphrase to be deleted: