73 65 6C 65 6E 65 🌜︎︎(blog)

home :: projects :: blog? :: contact

(re)encrypting in place: a LUKS story

posted Feb 01, 2024 02:30 UTC+02:00 by huskee

i like encryption. we all love encryption, because we all like our data to be safe from snoopers and evil-doers. so i decided to encrypt both of my partitions (~60GB root and ~120GB home, both btrfs), but there was one problem:

i didn't want to format anything!

it took a bit of looking around, but I found a (quasi)sane solution to my problem. and it goes like this (at least for openSUSE Tumbleweed):

preparations

BACKUP. YOUR. DATA. BEFORE. DOING. THIS. (i didn't, but do as i say, not as i do. ALWAYS backup stuff you want to keep)

you'll need a live usb of some kind. boot from it, open your terminal, say your prayers and:

btrfs check /dev/[root partition]
btrfs check /dev/[home partition]

make sure those partitions are squeaky clean. then, reduce their size by 32MB:

btrfs fi resize -32m /dev/[root partition]
btrfs fi resize -32m /dev/[home partition]

doing the deed

it's finally time to encrypt! this takes a surprisingly short time, but it works like a charm:

cryptsetup reencrypt --encrypt --type luks1 --reduce-device-size 32m /dev/[root partition]
cryptsetup reencrypt --encrypt --type luks2 --reduce-device-size 32m /dev/[home partition]

make sure you remember your passphrases.

IMPORTANT: if you're using GRUB2, the root partition encryption type must be LUKS1! otherwise, you won't be able to boot from it!

if you accidentally encrypt it as LUKS2, convert the key to PBKDF2 and then convert the encryption to LUKS1:

cryptsetup luksConvertKey --pbkdf=pbkdf2 /dev/[root partition]
cryptsetup convert /dev/[root partition] --type luks1

you have succesfully encrypted your partitions! now, on to:

setting up mounting & booting

if you reboot right now, both your bootloader and initrd will have multiple strokes. you have changed the partition structure of the drive, so now you gotta fix it up. start by opening both partitions and setting up a chroot:

cryptsetup open /dev/[root partition] cr_root
cryptsetup open /dev/[home partition] cr_home
mount /dev/mapper/cr_root /mnt
mount /dev/mapper/cr_home /mnt/home
mount --bind /dev /mnt/dev
mount --bind /sys /mnt/sys
mount --bind /proc /mnt/proc
mount /dev/[efi partition] /mnt/boot/efi
chroot /mnt

next, we're grabbing the UUIDs for the partitions we encrypted. you're looking for the entries with type crypto_LUKS. copy the UUIDs for both partitions, and edit /etc/crypttab with your favorite text editor (it better be nvim):

cr_root     [root partition UUID]   /etc/cryptsetup-keys.d/cr_root
cr_home     [home partition UUID]   /etc/cryptsetup-keys.d/cr_home

notice the files referenced after the UUIDs? later, we'll use those for auto decryption.

now, edit /etc/fstab, and replace all references to the partitions with their /dev/mapper counterparts:

/dev/mapper/cr_root 	/                       btrfs  defaults                      0  0
/dev/mapper/cr_root 	/var                    btrfs  subvol=/@/var                 0  0
/dev/mapper/cr_root     /usr/local              btrfs  subvol=/@/usr/local           0  0
/dev/mapper/cr_root     /srv                    btrfs  subvol=/@/srv                 0  0
/dev/mapper/cr_root     /root                   btrfs  subvol=/@/root                0  0
/dev/mapper/cr_root     /opt                    btrfs  subvol=/@/opt                 0  0
/dev/mapper/cr_home	    /home                   btrfs  defaults                      0  2
/dev/mapper/cr_root     /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
/dev/mapper/cr_root     /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
UUID=C914-6425          /boot/efi               vfat   utf8                          0  2
/dev/mapper/cr_root     /.snapshots             btrfs  subvol=/@/.snapshots          0  0

you're almost ready to reboot. the next step is to update both your bootloader and initrd to work with the encrypted partitions. edit /etc/default/grub and add the line

GRUB_ENABLE_CRYPTODISK=y

after that, reinstall and reconfigure GRUB:

grub2-install --target=x86_64-efi
grub2-mkconfig -o /boot/efi/EFI/opensuse/grub.cfg

and rebuild your initrd:

dracut -f

exit the chroot and reboot. if all went well, you should be greeted with this prompt:

Enter passphrase for hd0,gptx ([root partition UUID])

enter the passphrase you selected for the root partition. you'll now get to your familiar grub prompt. on this first boot, you'll be prompted for passwords for both encrypted partitions, but we'll fix this.

niceties: auto decryption

remember me?

cr_root     [root partition UUID]   /etc/cryptsetup-keys.d/cr_root
cr_home     [home partition UUID]   /etc/cryptsetup-keys.d/cr_home

time to create those files and add them as decryption keys:

openssl genrsa -out /etc/cryptsetup-keys.d/cr_root 4096
openssl genrsa -out /etc/cryptsetup-keys.d/cr_home 4096
cryptsetup luksAddKey /dev/[root partition] /etc/cryptsetup-keys.d/cr_root
cryptsetup luksAddKey /dev/[home partition] /etc/cryptsetup-keys.d/cr_home
chmod 600 /etc/cryptsetup-keys.d/cr_root
chmod 600 /etc/cryptsetup-keys.d/cr_home

you will be prompted for the passphrases you set for each partition.

the home partition is now set up for auto decryption! the root needs some more work. as we've encrypted /boot, you'll be asked for the passphrase twice: once when GRUB2 is loading, and once when initrd tries to open the drive. to avoid this, we need to add the /etc/cryptsetup-keys.d/cr_root keyfile to the initrd:

echo -e 'install_files+=" /etc/cryptsetup-keys.d/cr_root "' > /etc/dracut.conf.d/99-cryptsetup.conf
dracut -f

IMPORTANT: be careful to include the spaces inbetween the quotes and the path. dracut finds these really important.

time to reboot! now you should get only one password prompt from GRUB2, as all the others will be covered by the keys.

niceties 2: speeding up GRUB2 decryption times

IMPORTANT: this only works for LUKS2

LUKS uses key derivation to make your passphrases and keys even safer-er. however, key derivation is a rather costly (computingwise) operation, and GRUB2 especially struggles significantly, with load times going up to 50-60 seconds after entering the passphrase. you can mitigate this (at the expense of somewhat lowering the security of your encryption) by reducing the key derivation iterations for the passphrase:

cryptsetup luksConvertKey --pbkdf-force-iterations=1000 /dev/[root partition] --key-slot 0

1000 is the absolute minimum, so experiment a bit to find a middle ground between speed and safety (brute force resistance scales linearly with iterations).

non-niceties: troubleshooting

someone really needs to reimplement this. this is how you get out of the grub rescue> prison:

cryptomount (hd0,gptx) // your root partition, grab this identifier from the "enter passphrase" prompt
insmod normal
normal

check: