Linux/dm-crypt
The device mapper can be used with different targets, in this case dm-crypt. Apart from taking the usual precautions when dealing with cryptography, we should decide for a fast, yet secure combination of cipher, keysize, hash algorithm.[1]
Preparation
We may want to remove any pre-existing signatures from the device:
DEV=/dev/sdX # Adjust as needed!
wipefs -a $DEV # Wipe any pre-existing file system signatures
pv < /dev/zero > $DEV # Wipe the device with zeros
shred -vn1 $DEV # Wipe the device with random data
Setup
LUKS
cryptsetup is really the way to go to use dm-crypt
devices and its setup is more intuitive that plain dm-crypt
.
Setup the LUKS container (this has to be done only once):
cryptsetup luksFormat --cipher=aes-xts-plain64 --hash sha256 --key-size 512 --iter-time=5000 ${DEV}
Or, when using key files:[2][3][4]
head -c 256 /dev/random > keyfile cryptsetup luksFormat --key-file keyfile ${DEV}
Open the newly created container:
$ cryptsetup open ${DEV} test Enter passphrase for /dev/sdx: $ cryptsetup status test /dev/mapper/test is active. type: LUKS1 cipher: aes-xts-plain64 keysize: 512 bits device: /dev/sdx offset: 4096 sectors size: 20967424 sectors mode: read/write $ file -Ls ${DEV} /dev/mapper/test /dev/sdx: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256] UUID: 235142f6-6d99-457e-a5b6-ddaed00a63ea /dev/mapper/test: data
For FDE setups, the name of the encrypted root disk can be changed[5]. In short:
Replace OLD_NAME
with NEW_NAME
in /etc/crypttab
, then:
dmsetup rename OLD_NAME NEW_NAME update-initramfs -c -t -k all update-grub reboot
mkinitrd --force /boot/initramfs-`uname -r`.img `uname -r` grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg # UEFI systems grub2-mkconfig -o /boot/grub2/grub.cfg # BIOS systems
GPG keys
It's possible to specify the key to cryptsetup
via stdin and we could use GPG encrypted key material instead of pass phrases.
FIXME: Find out about the security implications here! Also explain the relation between the GPG key size and the --key-size
argument from cryptsetup
!
Generate random key material and encrypt it with gpg
:
openssl rand -hex 4096 | \ gpg --armor --symmetric --cipher-algo aes256 --digest-algo sha512 > key.asc
Without openssl:
dd if=/dev/random bs=1024 count=6 2>/dev/null | base64 | \ gpg --armor --symmetric --cipher-algo aes256 --digest-algo sha512 > key.asc
Initialize the LUKS partition (once):
DEV=/dev/sdX # Adjust as needed!
gpg --decrypt key.asc | \
cryptsetup luksFormat --cipher=aes-xts-plain64 --hash sha256 --key-size 512 --iter-time=5000 $DEV
And open it:
gpg --decrypt key.asc | cryptsetup open $DEV test
Now the new mapping device should be active:
$ cryptsetup status test /dev/mapper/test is active. type: LUKS1 cipher: aes-xts-plain64 keysize: 512 bits device: /dev/sdx offset: 4096 sectors size: 20967424 sectors mode: read/write
Plain
While we could setup the dm-crypt
volume manually, one should really use cryptsetup instead. But just for posterity, this is how dm-crypt
can be initialized:[7]
0 <sector count> crypt <sector format> <key> <IV offset> <real device> <sector offset>
- The sector count can be determined with
blockdev
- The sector format is the name of the (symmetric) encryption cipher and an optional IV
- Hexadecimal representation of the encryption key; its size is bound to the selected cipher
- The IV offset is usually just "0".
Let's do this:
DEV=/dev/sdX # Adjust as needed! KEY=`openssl rand -hex 64` echo 0 `blockdev --getsize $DEV` crypt aes-xts-plain64 $KEY 0 $DEV 0 | dmsetup create test
And this worked:
$ dmsetup info test
Name: test
State: ACTIVE
Read Ahead: 256
Tables present: LIVE
Open count: 0
Event number: 0
Major, minor: 254, 0
Number of targets: 1
Test
A quick(!) test would be to write to the encrypted volume and search for the string on the block device:
mkfs.ext4 /dev/mapper/test mount -t ext4 /dev/mapper/test /mnt/disk echo "hey, it worked" > /mnt/disk/foo.txt
Let's see if we can find the string:
$ grep -Fa "hey, it worked" /dev/mapper/test | strings # Use --devices=read if necessary Hhey, it worked $ grep -Fa "hey, it worked" ${DEV} [should not return anything]
Backup
It's important to backup the LUKS header once in a while:
cryptsetup luksHeaderBackup $DEV --header-backup-file header_sdX.backup
With that, the LUKS header can be restored should it ever get corrupted:
cryptsetup luksHeaderRestore $DEV --header-backup-file header_sdX.backup
Benchmark
Every system is different, so let's use a quick benchmark to find out which cipher/hash combination is best (fastest) for a particular machine:
$ for i in {1..10}; do echo "i: ${i}"; cryptsetup benchmark; done 2>&1 | tee c.log $ grep -A5 Tests c.log | awk '!/^#/ {print $1}' | head -5 | while read h; do printf "hash: ${h} "; grep ${h} c.log | awk '{sum=+$2} END {print sum}'; done | sort -nk3 hash: PBKDF2-whirlpool 10369 hash: PBKDF2-sha512 21700 hash: PBKDF2-sha256 99296 hash: PBKDF2-ripemd160 137970 hash: PBKDF2-sha1 152409 *** $ grep -A12 Algorithm c.log | head -13 | awk '!/^#/ {print $1, $2}' | while read c s; do printf "cipher: ${c} size: ${b} "; grep -E "${c}.*${s}" c.log | awk '{enc+=$3; dec+=$5} END {print enc,dec}'; done | sort -nk5,6 cipher: serpent-cbc size: 128b 0 0 cipher: serpent-cbc size: 256b 0 0 cipher: serpent-xts size: 256b 0 0 cipher: serpent-xts size: 512b 0 0 cipher: twofish-cbc size: 128b 0 0 cipher: twofish-cbc size: 256b 0 0 cipher: twofish-xts size: 256b 0 0 cipher: twofish-xts size: 512b 0 0 cipher: aes-cbc size: 256b 216 229.2 cipher: aes-xts size: 512b 228.7 224.1 cipher: aes-cbc size: 128b 268.4 296.2 cipher: aes-xts size: 256b 287.6 287 ***
As a short comparison, here's what reading from an external (USB) disk looks like:
$ pv -Ss 2G < /dev/sda > /dev/null 2GiB 0:01:00 [33.6MiB/s] $ cryptsetup status test /dev/mapper/test is active and is in use. type: LUKS1 cipher: aes-cbc-essiv:sha256 keysize: 256 bits device: /dev/sda1 offset: 2056 sectors size: 1953519608 sectors mode: read/write $ pv -Ss 2G < /dev/mapper/test > /dev/null 2GiB 0:01:26 [23.8MiB/s]
Links
- TrueCrypt
- RAID
- Archlinux: dm-crypt
- Gentoo: DM-Crypt LUKS
- Archlinux: System encryption using LUKS and GPG encrypted keys for arch linux
References
- ↑ dm-crypt benchmarks
- ↑ How to add a passphrase, key, or keyfile to an existing LUKS device
- ↑ dm-crypt/Device encryption: Creating a keyfile with random characters
- ↑ 2.12 What are the security requirements for a key read from file?
- ↑ How to change the name an encrypted full-system partition is mapped to
- ↑ Equivalent to update-grub on Fedora 30?
- ↑ Documentation/device-mapper/dm-crypt.txt