My Profile Photo

AndrewCz


Using liberty-minded opensource tools, and using them well


Encrypting a Hibernating CarbonPad




Ultraportable laptops are meant to be taken places. But what gives them security? Disk encryption, of course! But what kind of setup is battery-efficient, secure, and convenient? Can't you only have two of those three?

New Laptop!

I recently purchased a newer gen Lenovo X1 Carbon that came with an 8th gen Intel i5, 14” 1920x1080 16:9 UHD screen, 256GB of NVMe PCIe SSD, and 16GB of RAM. Basically my dream machine. But, it came with Winbloze, so I had to fix that. But how could I make it cool? What could I do that I could brag about?

I figured, OK, let’s get to the point that every time I close the laptop’s lid, everything is re-encrypted at rest, and the computer shuts off to conserve battery, and opening the lid boots it up with a negligible amount of delay. That would be pretty cool to brag about, right?

Disk Encryption

Anyone who knows anything about security knows to encrypt literally everything. So when I got around to installing Manjaro, I found myself wanting to set up an encrypted space where I could store my stuff. That led me to the first of several decisions, namely, how much did I need to encrypt?

  • Everything including /boot
  • Everything except /boot
  • Only the contents of my home directory

To take a look at thread models, if I never wanted anyone to be able to boot the machine at all, and carry around a USB thumbdrive off which to boot everywhere, then my best bet would be the first option. Since I’m not crazy about having a single USB stick point-of-failure, that was out.

I had already figured out how to encrypt the contents of my home directory using ecryptfs. This was able to be unlocked by LightDM with my user’s password, and I could have individual passwords for any user on my machine. However, there were a couple of drawbacks here. The re-encrypt hook was reporting to not work when logging out, and impossible to configure when simply locking a session. Since I only had one user (me!) that would ever realistically require a persistent account on this device, the main benefit of this approach was a moot point to me. Lastly, this left my system files unencrypted and subject to some very trivial live-boot hacking.

The logical conclusion then, would be then to encrypt everything except /boot. In all setups, there needs to be a bit to /boot that is decrypted to at least initially prompt for the decryption password for everything else.

Sleepytime, or How Not to Drain the Battery

I’ve been working on a MacBook Air at work. It’s been fairly pleasant, and I don’t have many complains - other than that the butterfly keyboard sucks and the windows management is as terrible as ever. The really cool thing is that the opening and shutting of the lid is super intuitive. Now, I’m aware that is the case with most laptops, but that being the only other real exposure that I had to a high-class laptop, it struck me as notable.

I know that Linux has a “suspend-to-disk” functionality that will allow the RAM to be flushed to a swap partition/file in order to save the session during the next startup. This in turn uses no battery, as there is nothing to be kept in RAM and nothing for the computer to be using power for. If at all possible, I would prefer to be able to hibernate the laptop when I close the lid, as when it’s sitting in my backpack on my way to wherever, there is no reason for it to be sipping its precious battery life (which is purportedly spectacular, but I have yet to do a benchmark against it).

Implementation

So let’s skip down to the implementation, now that we know the requirements, which would be to have the system hibernate when closing the lid, and encrypt the disk when hibernating.

Pre-Installer

All of these steps were done pre-installer. Note the lack of mkfs, and anything else. Everything up until the “Installer” section needed to be done before ever installing Manjaro.

Partitioning

So I have two primary partitions on this disk, with one being /boot, and the other being a LUKS volume (see below) that holds an LVM partition (see below-er) with four partitions on it.

There is a concept of an $ESP partition in UEFI booting. Compared to GRUB, it is the place where the bootloader lives. The $ESP partition can be either /boot/efi or just /boot. Coming up later you’ll see the reason, but I chose to create the unencrypted partition as /boot. Also, keep in mind that this needs to be partitioned as VFAT (F32)

Also, don’t forget to mark the boot partition with the boot flag…

LUKS

I chose to use LVM on LUKS, which means that I had to make the second partition into a LUKS volume before anything. See the ArchWiki linked below for details.

For the password, I chose the password that I used for my user account. Just for clarity’s sake, this is the same password for my LUKS device, for my user account, and for my user account’s sudo access. The threat model here is to encrypt data at rest, as I would lose even my head much more often if it wasn’t screwed on, much less my laptop. I don’t necessarily care about my user password other than it is just as hidden as my LUKS device’s decryption password. It does not make LUKS cryptographically insecure, which is as far as I care for now. This also buys me auto-login, as we’ll see in the LightDM section.

LVM

So now that the cryptdevice was open, I had to create the physical volume and the volume group to hold the partitions. I then created the partitions inside of the LVM with the appropriate size like so:

  • /
  • /var
  • /home
  • swap

The only requirement was that swap be a comparable size to the size of RAM so that it can hibernate well. In this case, I set it to 16GB.

Once again, the ArchWiki is your friend.

Installer

For this, we are going to use Manjaro-Architect, since it is able to do all the custom stuff that we need it to do.

Mount Partitions

Here is where we start, having created everything else beforehand. It’s not clear to me whether or not the installer would have been able to handle this yet, but this is a good jumping off point. Here you will select the mountpoints for all of the partitions, and format their filesystems. The only one that is probably not going to be ext4 is the /boot partition as specified above. DO NOT SELECT THIS ONE FOR A REGULAR MOUNTPOINT – after all of the other mountpoints have been specified and “Done” has been selected, you will be prompted on which device with the UEFI partition be mounted. It is at this point that you can specify your /boot partition to be mounted.

Repo and Desktop

This part isn’t as interesting to a disk-layout discussion as the first step. This should pretty much just walk its way through up until the next step.

However, make sure to install plymouth here, as we’ll be using it later. Take a look at the themes and see if you want one of Manjaro’s custom ones. To select multiple packages, hit the TAB key when the package you want is highlighted.

Install Bootloader

The UEFI bootloader can now be installed via systemd-boot as selectable on the installer.

Config Files

Once you get to the config file section, we have to address the following issues:

  • lightdm

The final piece of the puzzle here is where plymouth leaves off, at the display manager, LightDM. LightDM can be used to auto-login a user, and if I am the only user to login to the laptop, then I will just have LightDM open up a session for my user. This way I can bypass the need for a login password again after I’ve already decrypted the drive with Plymouth.

There’s a bug that I have to address upstream, but when you choose to autologin your user in the installer, it adds the username with a space at the end of it to the [Seat:*] section for the option autologin-user. This has the effect of considering your user invalid, and continually dropping your user to a login prompt. Get rid of this trailing newline for an auto-login.

  • mkinitcpio

There are a couple of notable hooks that have to be added to the configuration that is used when mkinitcpio is called to generate the kernel image. These are most notably the ones that use the systemd hooks to boot the system, and to call plymouth and decrypt the drives. I added the i915 module to load just for good measure. Many of these are in a specific order, so be cognizant of how this entry is set up.

MODULES=(i915)
HOOKS=(base systemd sd-plymouth autodetect sd-vconsole modconf block sd-encrypt sd-lvm2 filesystems resume keyboard)

If you’re sharp, you’ll notice that there are several parameters in there prepended with sd-. These are typically replacements for other parameters for when the systemd hook specifically is being used.

Chroot into system

DO NOT DO THIS it is the very end of the installer, and will actually break the installer, forcing you to start over from scratch. You’ve been warned.

If you really need to chroot into the install, do it later, with manjaro-chroot, which acts the same as arch-chroot. Do I even have to mention the Wiki?

Post-Installer

systemd-boot

Since we live in the future, we don’t have to interact with BIOS anymore, and can use UEFI to boot our machines. And while GRUB can take advantage of that, it’s largely unnecessary. The utility called systemd-boot can take care of setting us up with an EFI image and entries in our $ESP partition.

Manjaro has a helper tool called sdboot-manage, which is a shell script to handle the setting up of entry configuration files and other settings for systemd-boot. This gets run every time the kernel gets updated. However, that will throw a little wrench into our works as the setup described here is not supported yet, as you will see below. But if we can get this supported, it’ll be great.

Before I move on, I do want to talk about what this allows us to avoid. There is hardly any delay in booting since there is no bootloader to take precious seconds from boot time, or a bootloader screen to choose any options from. It just boots, and that’s all I ever needed it to do.

What’s more, it boots fast. That NVMe is no joke. Loading and unloading the OS has never been faster. In fact, that is really the pivotal point where I determined that all of the components were ready for this kind of paradigm shift. Lock screens are so last year.

Kernel boot options

Here’s where everything gets snarled up, and if a boot fails is 99% the likelihood of the problem. Like we said above, the Manjaro-specific helper script overwrites the kernel boot options, which incorrectly points to the wrong partitions, using the old grub way of specifying them. Below is my entire kernel options line, which I will explain in sections:

$ grep 'options' /boot/loader/entries/manjarolinux5.4.conf
options quiet splash rd.luks.name=5f1b8b64-9739-4f87-8493-2fd8ea47f760=crypt root=/dev/system/lv_root rw resume=/dev/system/lv_swap loglevel=3 rd.udev.log_priority=3 vt.global_cursor_default=0 fbcon=nodefer i915.fastboot=1 vga=current

NOTE: Sometimes it will try to boot the fallback conf instead of the regular one that I fixed. When that happens I just delete the fallback and everything works just fine. I’ll try to get this fixed upstream soon.

In order to avoid having this overwritten at boot time, it’s best to have this line present in /etc/sdboot-manage.conf:

NO_AUTOGEN="yes"

This ensures that our custom config won’t get overwritten whenever we install a new kernel.

Plymouth hooks

Plymouth functionality is talked about below, but the quiet splash parameters tell the kernel to use the splash screen - in this case plymouth - to display when booting.

LUKS Device

The next entry is for the LUKS device:

rd.luks.name=5f1b8b64-9739-4f87-8493-2fd8ea47f760=crypt

This tells the kernel which device is encrypted, and what its decrypted volume name is. You can find this UUID using the blkid command as root.

This is not the root partition like is automatically generated for you.

Root and Resume

The next section tells the kernel where to load stuff once the decryption happens:

root=/dev/system/lv_root rw resume=/dev/system/lv_swap

Note that this is using their LVM names. THIS IS ABSOLUTELY NECESSARY WHEN DECRYPTING AT BOOT TIME. If these two parameters are specified as UUIDs, the kernel will attempt to decrypt these as well at boot before decrypting the LUKS device. Obviously that would cause the boot to fail and you’re stuck getting your live USB drive once again.

And the rest

loglevel=3 rd.udev.log_priority=3 vt.global_cursor_default=0 fbcon=nodefer i915.fastboot=1 vga=current

These parameters are all here to either suppress output or to make boot faster or prettier.

Plymouth

Lastly, plymouth was fairly easy to set up. It’s in the repos, and given that the correct hooks are present in the mkinitcpio configuration, just works. I even went a step further and set it up to use Manjaro Cinnamon’s theme (since that is the DE that I use).

The best thing about it just working is that it prompts me for the password automatically. I didn’t have to configure anything additionally, although there is plenty to play around with in the configuration file.

End Result

What does this look like in my day-to-day usage?

In the morning, I open my laptop and am greeted with the manufacturer’s LENOVO banner for a couple seconds, and then am dropped to a password prompt. I enter in my password, and seconds later, my desktop appears exactly as I had left it the night before. I write these kinds of posts, and use that same password for any sudo access required (while all of my online passwords are randomly generated using Bitwarden - more on that in another post). When I’m done writing, I simply close the lid, assured that not only is everything still there and waiting for me when I get back, but that in the meanwhile all of the bits and bytes floating around in RAM or elsewhere has now been stored and encrypted at rest. The cherry on top of all of this is that my battery lasts virtually forever, as there is no power being used whatsoever after I close the lid and start travelling to my next great adventure.

Pretty cool, huh?

Update 2020-05-27

Using these steps I’ve set up my desktop in a similar way. However, I had a two-disk RAID 1 array that I used in the same manner. I encrypted it using the same password, but without including it in the LVM setup. With the appropriate entries in the kernel boot options (mdadm and an additional rd.luks.name entry) it booted up in the same manner and hibernated similarly. It seems to be working fine.


References: