Encrypted swap is at least as important as encrypted data. This is because the contents of nearly anything in memory can be swapped to disk, at any time, and for any length of time. That includes passwords and like, en claire. Encrypting the system swap volume cannot be overlooked.

During our migration process we have cloned drives in part one, switched to an encrypted root in part two, and moved partitions around to make room for home data encryption in part three. Now we will encrypt the swap partition.

Goals

We are free of many of the concerns with which we dealt when dealing with the encrypted root in part two, but we have two key goals:

  1. Support for hibernate
  2. Avoid multiple passphrase entry at boot without compromising security

The first is a property unique to swap, that being the place were the contents of RAM are copied when a machine is put into hibernation. Our encryption setup should support that. The second is an artifact of our disk layout, this being a second encrypted volume to be encountered during boot. There are more than a few ways to meet both of these goals, and some shortcuts that can be taken should one or the other not be desired.

Suspend vs Hibernate

Imprecision characterizes the names and labels for “hardware sleep” as it does many areas of technology, even after the ideas and processes have been codified. It is worth stating a couple of definitions:

  • Suspend: Processes paused, most parts of the computer turned off except for RAM in order to save and resume machine state (aka “Sleep” or “Standby”)
  • Hibernate: Processes paused, memory flushed to swap area of the disk before complete shutdown in order to save and resume machine state from full poweroff/poweron (aka “Suspend-to-disk”)

We pursue the latter, as that is all that is relevant for a swap change.

Possibilities

There are a number approaches for volume encryption, most of which we did not explore in parts two and three. All boot-time decryption is handled by systemd-cryptsetup-generator, which understands /etc/crypttab entries as well as the rd.luks kernel command-line arguments we used previously.

  1. encrypted physical volume (not available with our chosen volume layout)
  2. crypttab swap entry with random key
  3. crypttab volume entry assuming passphrase
  4. crypttab volume entry specifying key stored on some device
  5. kernel rd.luks argument assuming passphrase entry
  6. kernel rd.luks argument specifying key stored on some device

Option #1 is not available without redoing this particular storage layout from scratch, but would offer the advantage that all logical volumes atop a crypto-pv are implicitly encrypted: root, swap, whatever. This route was not chosen simply because it did not seem to align with install-time Fedora defaults.

Options #2, #3, #4 make use of /etc/crypttab, something we did not explore when setting up encrypted root and home, and entries here are generally set up by systemd later in the boot process after initrd. In the entries below, the first is the simplest means of encrypting swap, and a facility unique to crypttab: recreating it with random key at each boot, leaving a plain-crypt (not LUKS) device mapper entry named crypt-swap. The latter two point to a LUKS volume that would need to be cryptsetup manually ahead of time, with masochistically named device-mapper entries in the form luks-UUID:

crypt-swap	/dev/mapper/Volume00-swap	/dev/urandom	swap
luks-XXX-YYY-ZZZ-AAA-BBB-CCC	/dev/mapper/Volume00-swap
luks-XXX-YYY-ZZZ-AAA-BBB-CCC	/dev/mapper/Volume00-swap	/etc/luks/swap.key

Out of this bunch, the first does not support hibernate by nature of its use of random key. But #2 and #3 are viable, with concerns about key storage for the latter assuaged by its location within the encrypted root.

Options #5 and #6 are the way we handled root in part two, for decryption by the initial ram disk. This would add another rd.luks.uuid kernel argument in grub.conf pointing to the device in question:

rd.luks.uuid=XXX-YYY-ZZZ-AAA-BBB-CCC
rd.luks.uuid=XXX-YYY-ZZZ-AAA-BBB-CCC rd.luks.key=/path/to/swap.key

Out of these two, the second seems to succumb to problems with systemd within the initial ramdisk being able to make use of the argument, exacerbated by myriad documentation conflicts between the use of this option beneath the init/upstart and systemd regimes. This post contains a good explanation and possible workaround, but even should it work, there is the problem of where to store a key, since the encrypted root would not yet be available. That leaves #5 viable.

With some of our options relying on passphrase entry, entering multiple phrases one after another could be a problem. It turns out that this is not a concern as long as we adhere to one condition: use of the same passphrase. Though it is not documented well (or at all), passphrases and keys are cached during systemd cryptsetup (by plymouth) for attempt against every encrypted volume. With the same one in use on both, the end result is one prompt at boot time.

Three options meet our two goals: #2, #3, #5. All work, but we select #5. Because we already have the initial ramdisk decrypting root by passphrase, it makes some bit of sense to do the same for swap at the same stage. Also, this approach means there are no concerns about key storage. And lastly, specifying UUIDs on the kernel command line for luks means that it could still work in the event a default ramdisk is used.

Setup Encrypted Swap

Our disk layout is as follows:

/dev/sda (150GB)
     sda1: ext3 /boot (300MB)
     sda2: lvm Volume00 (150GB)
          Volume00-swap: swap (2GB)
          Volume00-root: LUKS (127GB)
               luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 ext3 (127GB)
          unallocated: (19GB)

We will simply re-use the existing swap logical volume. Though encrypting an existing volume destroys data, that of the swap partition is normally of no lasting consequence.

First we need to disable swap:

swapoff -a

Write random data to the volume for best results:

dd if=/dev/urandom of=/dev/mapper/Volume00-swap
dd: writing to ‘/dev/mapper/Volume00-swap’: No space left on device
4194305+0 records in
4194304+0 records out
2147483648 bytes (2.1 GB) copied, 567.601 s, 3.8 MB/s

Encrypt the volume:

cryptsetup --verbose --verify-passphrase luksFormat /dev/mapper/Volume00-swap

WARNING!
========
This will overwrite data on /dev/mapper/Volume00-swap irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Command successful.

Grab the volume UUID:

cryptsetup luksDump /dev/mapper/Volume00-swap | grep UUID
UUID:           8f747652-3e73-4297-9721-9e8cdd8d89b1

Masochistically open the volume at name reflective of the UUID:

cryptsetup luksOpen /dev/mapper/Volume00-swap luks-8f747652-3e73-4297-9721-9e8cdd8d89b1
Enter passphrase for /dev/mapper/Volume00-swap:

Make swap:

mkswap /dev/mapper/luks-8f747652-3e73-4297-9721-9e8cdd8d89b1
Setting up swapspace version 1, size = 2095100 KiB
no label, UUID=35d0810f-accb-4fc8-ad9c-3c88a28429ad

Edit /etc/fstab to reflect the new swap location:

/dev/mapper/luks-8f747652-3e73-4297-9721-9e8cdd8d89b1   none    swap    defaults        0 0

Turn on swap to ensure all is well:

swapon -a
swapon -s
Filename				Type		Size	Used	Priority
/dev/dm-2                              	partition	2095100	0	-1

With working swap, we need to ensure it comes up on boot.

Edit /etc/default/grub to add this new rd.luks.uuid and make config:

GRUB_CMDLINE_LINUX="quiet rd.luks.uuid=cc7e78ee-87a9-4ad0-9c82-31de01389b34 rd.luks.uuid=luks-8f747652-3e73-4297-9721-9e8cdd8d89b1"

grub2-mkconfig -o /boot/grub2/grub.cfg

Create new ramdisk so it can find the new volume:

cd /boot
cp -a initramfs-3.12.8-300.fc20.i686.img initramfs-3.12.8-300.fc20.i686.img.20140817

dracut -f /boot/initramfs-3.12.8-300.fc20.i686.img 3.12.8-300.fc20.i686

Boot with New Swap

At this point, we can boot with the new crypto swap in place, and our system disk is as follows:

/dev/sda (150GB)
     sda1: ext3 /boot (300MB)
     sda2: lvm Volume00 (150GB)
          Volume00-swap: swap (2GB)
               luks-8f747652-3e73-4297-9721-9e8cdd8d89b1 swap (2GB)
          Volume00-root: LUKS (127GB)
               luks-cc7e78ee-87a9-4ad0-9c82-31de01389b34 ext3 (127GB)
          unallocated: (19GB)

Now everything is truly encrypted.