When it comes to block device encryption on Linux,
dm-crypt in combination
with a LUKS header is
the de facto standard.
While the setup procedure is well documented in the arch wiki, I couldn't find a straightforward explanation on how to move an existing installation to an encrypted partition. Here is what I did to save me the trouble of reinstalling and setting up my system.
Let's be clear, disk encryption is not a silver bullet against every possible kind of attack. In particular, as the arch wiki mentions, you will still be vulnerable to:
Attackers who can break into your system after you have already unlocked the encrypted parts of the disk.
Attackers who are able to gain physical access to the computer while it is running, or very shortly after it was running, if they have the resources to perform a cold boot attack
My thread-model though is quite simple in this case: I will be using this drive in a notebook and carrying it around a lot. I might lose it or have it stolen by random thieves. If they are able to perform any of the attacks above, I'm sure they will also be able to force me to give them the key, so I won't bother considering those. The setup above should be good enough, that I will be quietly weeping over my trusty X230 instead of the private data on the drive, if forget it on the train.
You will need a few basics. I moved the installation to a new SSD of the same size and used a SATA to USB adapter to connect them both at once.
- The new drive
- SATA-USB adapter
- Bootable live media, I used the arch install USB
- A working installation
I'll also assume you have a backup of your data, since you could easily lose it if something goes wrong (you should have those anyway).
Create the partitions
My setup has only two partitions: a small EFI partition (
/boot) and the root
file system (
/). You can get this information e.g. form
print the partitions.
Disk /dev/sda: 223.58 GiB, 240057409536 bytes, 468862128 sectors Disk model: KINGSTON SA400S3 Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: BF841FB1-0634-4826-A240-2D70832E3D5C Device Start End Sectors Size Type /dev/sda1 2048 1128447 1126400 550M EFI System /dev/sda2 1128448 468860927 467732480 223G Linux filesystem
There are valid reasons to encrypt the
/boot, but it makes the setup more
complicated and not necessary for what I want to accomplish. My goah is to
/, which especially also contains my
/home folder with private
data. The bootloader will remain installed in the unencrypted
and unlock the encrypted partition on boot.
Armed with this information you can plug in the drive using the adapter and
recreate the partition table like you would normally. I won't go into detail on
how to create the
partitions, as there is
nothing special it, the encryption step comes later. I used
don't forget to set the
esp flags for the boot partition and set
the correct filesystem types.
At this point you can boot into your previously created live media. I'll assume
in the following, that the existing (unencrypted) installation is located on
your internal drive
/dev/sda and the new, to be encrypted drive is located at
/dev/sdb. This is the right moment to create the filesystem on your new
mkfs.fat -F32 /dev/sdb1
/boot partition (
/dev/sdb1) requires nothing else for
now, we now need to set up the encryption on the new root partition at
cryptsetup we initialize the LUKS partition and set the initial
passphrase on key-slot 0. LUKS allows for multiple key-slots, which may be used
for other forms of authentication, e.g. a hardware security token. The following
initializes the LUKS partition, unlocks it and creates an ext4 filesystem inside.
cryptsetup -y -v luksFormat /dev/sdb2 cryptsetup open /dev/sdb2 cryptroot mkfs.ext4 /dev/mapper/cryptroot
Before continuing it might be a good idea to verify that everything went well and the LUKS partition works as expected. You should be able to close and re-open it, we will try mounting it in the next step too.
cryptsetup close cryptroot cryptsetup open /dev/sda2 cryptroot
Copy the data
We will now mount everything and copy over the data. Assuming you are booted
into a live media and have all necessary privileges create two folders: one for
the “old” drive (
/dev/sda) and one for the “new” one (
/dev/sdb). It wont
matter where you create them as they are ephemeral. For simplicity, I created two
folders in the root home directory.
mkdir /root/old_rootfs mkdir /root/new_rootfs
You can mount the existing installation to
/root/old_rootfs. This also
includes mounting the
/boot partition located on
/dev/sda inside the
mounted root filesystem of the old drive.
mount /dev/sda2 /root/old_roofts mount /dev/sda1 /root/old_rootfs/boot
You can mount the new, encrypted, drive in the same manner, the only difference
being that you will mount
/dev/mapper/cryptroot instead of mounting
cryptsetup open /dev/sdb2 cryptroot # not necessary if you didn't close it mount /dev/mapper/cryptroot /root/new_rootfs mount /dev/sdb1 /root/new_rootfs/boot
While you could have copied the partitions one after the other, with the setup
above you now only have to copy everything from
/root/new_rootfs, taking care to preserve file attributes.
rsync command should be available or can be easily installed on most
platforms and will do the job nicely. Adding the
--info=progress2 flag, gives
an estimate of the total progress instead of the single files being copied.
Watch out for the slashes in the command though, as
rsync will copy the folder
itself instead of the contents if you omit them.
rsync -aAXv --info=progress2 /root/old_rootfs/ /root/new_rootfs/
Depending on the amount of used storage this might take a while. Let it run
until it finishes. When it's finished,
/root/new_rootfs should list the same
At this point, you can unmount the old drive to prevent any mistakes that might mess it up. This is not strictly necessary, but gives you an additional backup in case you want to revert to it or start over. I even went one step further, taking the old drive out physically and rebooting into the live system with only the new drive now build in. If you do so, you will need to mount everything again, also watch out for changed device descriptors.
umount /root/old_rootfs/boot umount /root/old_rootfs
Congrats, your data is now on an encrypted partition! There are a few more steps to make it boot though.
Chroot into new system
The following steps need to be done from inside the new system. It is not
bootable yet, but we can
arch-chroot on Linux arch) into it. With
/dev/sdb2 still mounted, use
Execute the rest of these instructions in the chroot.
Depending on your setup, you might need to update your
lsblk -f you should see something similar to this:
$ lsblk -f NAME FSTYPE UUID FSAVAIL FSUSE% MOUNTPOINT sda ├─sda1 vfat A319-9DF9 476.4M 13% /boot └─sda2 crypto_LUKS 424372e4-ac1d-4925-83ba-baa6d5ec6117 └─cryptroot ext4 9b2863ce-ed0b-41de-a96e-b02a02f3bada 81.9G 57% /
Use the shown
UUIDs to write your
/etc/fstab. Warning: Don't confuse
UUID of your root partition itself (e.g.
/dev/sda2) with the
the encrypted volume! In my case my
/etc/fstab file looks like this:
UUID=9b2863ce-ed0b-41de-a96e-b02a02f3bada / ext4 rw,relatime,stripe=8191 0 1 UUID=A319-9DF9 /boot vfat nosuid,nodev,noexec,noatime,fmask=0133 0 0
Once again: Use the
UUID of cryptroot for
/, not the one from
It is now time to configure the kernel to work with the encryption. For this we
need to add some hooks to
/etc/mkinitcpio.conf. There are different hooks that
can be used here, I will be using the default
encrypt hook. For more detailed
information the arch
is again a great reference.
In particular, we need to add the
keymap and finally the
HOOKS=(..). You can leave out the
keymap hook, if you are you use
the default US keymap. In my case the
look like this:
HOOKS=(base udev autodetect keyboard keymap modconf block encrypt filesystems keyboard fsck)
After saving the file, regenerate the initramfs with all presets
mkinitcpio -P #That is a captial -P!
The last step is to configure the bootloader. We need to pass this kernel parameter:
device-UUID is here
/dev/sdb2, not the one from the
encrypted volume like before.
For grub this means editing
/etc/default/grub like this:
GRUB_DISTRIBUTOR="Arch" GRUB_CMDLINE_LINUX_DEFAULT="quiet cryptdevice=UUID=424372e4-ac1d-4925-83ba-baa6d5ec6117:cryptroot root=/dev/mapper/cryptroot" GRUB_CMDLINE_LINUX=
With the file in place, regenerate the
grub.cfg file with:
grub-mkconfig -o /boot/grub/grub.cfg
That's it, you're done! If everything went well, you can now reboot into the
system. Before doing so, leave the
chroot, then unmount the partitions for
good measure and throw a
sync in there to be sure everything is written.
umount /root/new_rootfs/boot umount /root/new_rootfs sync reboot
At this point your system should reboot into grub and then ask you for a passphrase along the boot process. If you experience problems, it might help to reinstall the bootloader.
I later added my Yubikey to the setup, allowing it to be used to unlock the encrypted volume. I will be detailing how that was done in a separate post.