dm-crypt/Specialties - ArchWiki
Packages
Forums
Wiki
GitLab
Security
AUR
Jump to content
From ArchWiki
Dm-crypt
Securing the unencrypted boot partition
The
/boot
partition and the
Master Boot Record
are the two areas of the disk that are not encrypted, even in an
encrypted root
configuration. They cannot usually be encrypted because the
boot loader
and BIOS (respectively) are unable to unlock a dm-crypt container in order to continue the boot process. An exception is
GRUB
, which gained a feature to unlock a LUKS encrypted
/boot
- see
dm-crypt/Encrypting an entire system#Encrypted boot partition (GRUB)
This section describes steps that can be taken to make the boot process more secure.
Warning
Note that securing the
/boot
partition and MBR can mitigate numerous attacks that occur during the boot process, but systems configured this way may still be vulnerable to BIOS/UEFI/firmware tampering, hardware keyloggers, cold boot attacks, and many other threats that are beyond the scope of this article. For an overview of system-trust issues and how these relate to full-disk encryption, refer to
[1]
Note
When using
UEFI
, only an
ESP
needs to remain unencrypted, if using
Unified kernel images
for example. You can then use
Secure Boot
to make sure the boot chain has not been tampered with, which is an easy way to achieve the same result as the below methods. See
dm-crypt/Encrypting an entire system#LUKS on a partition with TPM2 and Secure Boot
Booting from a removable device
Using a separate device to boot a system is a fairly straightforward procedure, and offers a significant security improvement against some kinds of attacks. Two vulnerable parts of a system employing an
encrypted root filesystem
are
the
Master Boot Record
, and
the
/boot
partition.
These must be stored unencrypted in order for the system to boot. In order to protect these from tampering, it is advisable to store them on a removable medium, such as a USB drive, and boot from that drive instead of the hard disk. As long as you keep the drive with you at all times, you can be certain that those components have not been tampered with, making authentication far more secure when unlocking your system.
It is assumed that you already have your system configured with a dedicated partition mounted at
/boot
. If you do not, please follow the steps in
dm-crypt/System configuration#Kernel parameters
, substituting your hard disk for a removable drive.
Note
You must make sure your system supports booting from the chosen medium, be it a USB drive, an external hard drive, an SD card, or anything else.
Prepare the removable drive (
/dev/sdx
).
# gdisk /dev/sdx #format if necessary. Alternatively, cgdisk, fdisk, cfdisk, gparted...
# mkfs.ext2 /dev/sdx1 #for BIOS systems
# mkfs.fat -F 32 /dev/sdx1 #for UEFI systems
# mount /dev/sdx1 /mnt
Copy your existing
/boot
contents to the new one.
# cp -ai /boot/* /mnt/
Mount the new partition. Do not forget to update your
fstab
file accordingly.
# umount /boot
# umount /mnt
# mount /dev/sdx1 /boot
# genfstab -p -U / > /etc/fstab
Update
GRUB
grub-mkconfig
should detect the new partition UUID automatically, but custom menu entries may need to be updated manually.
# grub-mkconfig -o /boot/grub/grub.cfg
# grub-install /dev/sdx #install to the removable device, not the hard disk. for BIOS systems
# grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub #for UEFI systems
Reboot and test the new configuration. Remember to set your device boot order accordingly in your BIOS or
UEFI
. If the system fails to boot, you should still be able to boot from the hard drive in order to correct the problem.
chkboot
Warning
chkboot makes a
/boot
partition
tamper-evident
, not
tamper-proof
. By the time the chkboot script is run, you have already typed your password into a potentially compromised boot loader, kernel, or initramfs. If your system fails the chkboot integrity test, no assumptions can be made about the security of your data.
Referring to an article from the ct-magazine (Issue 3/12, page 146, 01.16.2012,
[2]
) the following script checks files under
/boot
for changes of SHA-1 hash, inode, and occupied blocks on the hard drive. It also checks the
Master Boot Record
. The script cannot prevent certain type of attacks, but a lot are made harder. No configuration of the script itself is stored in unencrypted
/boot
. With a locked/powered-off encrypted system, this makes it harder for some attackers because it is not apparent that an automatic checksum comparison of the partition is done upon boot. However, an attacker who anticipates these precautions can manipulate the firmware to run their own code on top of your kernel and intercept file system access, e.g. to
boot
, and present the untampered files. Generally, no security measures below the level of the firmware are able to guarantee trust and tamper evidence.
The script with installation instructions is
available
(Author: Juergen Schmidt, ju at heisec.de; License: GPLv2). There is also package
chkboot
AUR
to
install
. The AUR package is recommended, as it has additional helpful scripts.
Juergen Schmidt's script
As
/usr/local/bin/chkboot_user.sh
needs to be executed right after login, you need to add it to the
autostart
(e.g. under KDE ->
System Settings -> Startup and Shutdown -> Autostart
; GNOME 3:
gnome-session-properties
).
With Arch Linux, changes to
/boot
are pretty frequent, for example by new kernels rolling-in. Therefore it may be helpful to use the scripts with every full system update. One way to do so:
#!/bin/sh
# Note: Insert your
and execute it with sudo for pacman & chkboot to work automagically
echo "Pacman update [1] Quickcheck before updating" &
sudo -u
/usr/local/bin/chkboot_user.sh
/usr/local/bin/chkboot.sh
sudo -u
/usr/local/bin/chkboot_user.sh
echo "Pacman update [2] Syncing repos for pacman"
pacman -Syu
/usr/local/bin/chkboot.sh
sudo -u
/usr/local/bin/chkboot_user.sh
echo "Pacman update [3] All done, let us roll on ..."
AUR package
After installing,
enable
chkboot.service
You may want to add
chkboot
to the end of your
mkinitcpio hooks
, so that your chkboot hashes get updated every time mkinitcpio regenerates your initramfs. You can do this by adding
chkboot
to the end of the
HOOKS
array in
/etc/mkinitcpio.conf
The AUR package also comes with an
chkboot-desktopalert
script, which will cause a graphical window to pop up with a warning if
/boot
changes are detected. You can make use of this script by adding it to the startup scripts of your graphical environment.
mkinitcpio-chkcryptoboot
Warning
This hook does
not
encrypt
GRUB
's core (MBR) code or EFI stub, nor does it protect against situations where an attacker is able to modify the behaviour of the boot loader to compromise the kernel and/or initramfs at run-time.
mkinitcpio-chkcryptoboot
AUR
is a
mkinitcpio
hook that performs integrity checks during early-userspace and advises the user not to enter their root partition password if the system appears to have been compromised. Security is achieved through an
encrypted boot partition
, which is unlocked using
GRUB
's
cryptodisk.mod
module, and a root filesystem partition, which is encrypted with a password different from the former. This way, the
initramfs
and
kernel
are secured against offline tampering, and the root partition can remain secure even if the
/boot
partition password is entered on a compromised machine (provided that the chkcryptoboot hook detects the compromise, and is not itself compromised at run-time).
This hook requires
grub
release >=2.00 to function, and a dedicated, LUKS encrypted
/boot
partition with its own password in order to be secure.
Installation
Install
mkinitcpio-chkcryptoboot
AUR
and edit
/etc/default/chkcryptoboot.conf
. If you want the ability of detecting if your boot partition was bypassed, edit the
CMDLINE_NAME
and
CMDLINE_VALUE
variables, with values known only to you. You can follow the advice of using two hashes as is suggested right after the installation. Also, be sure to make the appropriate changes to the
kernel command line
in
/etc/default/grub
. Edit the
HOOKS=
line in
/etc/mkinitcpio.conf
, and insert the
chkcryptoboot
hook
before
encrypt
. When finished,
regenerate the initramfs
Technical overview
mkinitcpio-chkcryptoboot
AUR
consists of an install hook and a run-time hook for mkinitcpio. The install hook runs every time the initramfs is rebuilt, and hashes the GRUB
EFI
stub (
$esp/EFI/grub_uefi/grubx64.efi
) (in the case of
UEFI
systems) or the first 446 bytes of the disk on which GRUB is installed (in the case of BIOS systems), and stores that hash inside the initramfs located inside the encrypted
/boot
partition. When the system is booted, GRUB prompts for the
/boot
password, then the run-time hook performs the same hashing operation and compares the resulting hashes before prompting for the root partition password. If they do not match, the hook will print an error like this:
CHKCRYPTOBOOT ALERT!
CHANGES HAVE BEEN DETECTED IN YOUR BOOT LOADER EFISTUB!
YOU ARE STRONGLY ADVISED NOT TO ENTER YOUR ROOT CONTAINER PASSWORD!
Please type uppercase yes to continue:
In addition to hashing the boot loader, the hook also checks the parameters of the running kernel against those configured in
/etc/default/chkcryptoboot.conf
. This is checked both at run-time and after the boot process is done. This allows the hook to detect if GRUB's configuration was not bypassed at run-time and afterwards to detect if the entire
/boot
partition was not bypassed.
For BIOS systems the hook creates a hash of GRUB's first stage boot loader (installed to the first 446 bytes of the bootdevice) to compare at the later boot processes. The main second-stage GRUB boot loader
core.img
is not checked.
AIDE
Alternatively to above scripts, a hash check can be set up with
AIDE
which can be customized via a very flexible configuration file.
Using GPG, LUKS, or OpenSSL encrypted keyfiles
The following forum posts give instructions to use two factor authentication, gpg or openssl encrypted keyfiles, instead of a plaintext keyfile described earlier in this wiki article
System Encryption using LUKS with GPG encrypted keys
GnuPG:
Post regarding GPG encrypted keys
This post has the generic instructions.
OpenSSL:
Post regarding OpenSSL encrypted keys
This post only has the
ssldec
hooks.
OpenSSL:
Post regarding OpenSSL salted bf-cbc encrypted keys
This post has the
bfkf
initcpio hooks, install, and encrypted keyfile generator scripts.
LUKS:
Post regarding LUKS encrypted keys
with a
lukskey
initcpio hook. Or
#Encrypted /boot and a detached LUKS header on USB
below with a custom encrypt hook for initcpio.
Note that:
You can follow the above instructions with only two primary partitions, one boot partition (required because of encryption) and one primary LVM partition. Within the LVM partition you can have as many partitions as you need, but most importantly it should contain at least root, swap, and home logical volume partitions. This has the added benefit of having only one keyfile for all your partitions, and having the ability to hibernate your computer (suspend to disk) where the swap partition is encrypted. If you decide to do so your hooks in
/etc/mkinitcpio.conf
should look like this:
HOOKS=( ... usb usbinput (etwo or ssldec) encrypt (if using openssl) lvm2 resume ... )
and you should add
resume=/dev/
to your
kernel parameters
If you need to temporarily store the unencrypted keyfile somewhere, do not store them on an unencrypted disk. Even better make sure to store them to RAM such as
/dev/shm
If you want to use a GPG encrypted keyfile, you need to use a statically compiled GnuPG version 1.4 or you could edit the hooks and use
gnupg1
AUR
It is possible that an update to OpenSSL could break the custom
ssldec
mentioned in the second forum post.
Remote unlocking of root (or other) partition
Imagine a headless system or a system not physically accessible. Additionally, one or more LUKS encrypted partitions (root or others) or volumes need to be unlocked during startup. In this case you need to be able to connect via network and provide a password during early boot (initramfs) phase. This can be achieved by using one or more
mkinitcpio
hook(s) that configure a network interface and start some kind of SSH server. Some packages listed below contribute various
mkinitcpio build hooks
to ease the configuration. The following tutorials add a remote unlocking method in addition to the existing local console password prompt.
systemd based initramfs (built with mkinitcpio)
For systemd based initramfs the AUR package
mkinitcpio-systemd-extras
AUR
provides a collection of build hooks (aka install hooks) to achieve network connectivity and SSH login during early boot. Depending on the concrete setup this either gives you access to the initramfs environment via busybox' dash or just a password prompt.
A minimal setup:
/etc/mkinitcpio.conf
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block
sd-network
sd-tinyssh
sd-encrypt filesystems fsck)
SD_TINYSSH_COMMAND="systemd-tty-ask-password-agent --query"
When building the initramfs with
mkinitcpio
this setup copies the already existing configuration of
systemd-networkd
from the main system and also tries to copy / convert existing SSH server keys from an existing TinySSH or OpenSSH installation.
tinyssh
needs to be installed (but not necessarily enabled) on the main system. There are some more configuration parameters to cover more use cases. See the
documentation
of
mkinitcpio-systemd-extras
AUR
for further details.
Warning
By default you have 90 seconds to unlock the device containing your root filesystem. After that systemd will give up waiting for this device and enter some emergency mode. You are then effectively locked out! To avoid this painful situation define the kernel parameter
rootflags=x-systemd.device-timeout=0
in the configuration of your
boot loader
. With this setting systemd will wait forever.
Note
Predictable network interface names
such as
enp2s0
are not present during initramfs phase by default, so many
systemd-networkd
configuration files will not work during initramfs phase. See the
mkinitcpio-systemd-extras wiki
for workarounds.
This section used to mention
mkinitcpio-systemd-tool
as another alternative to achieve remote login and LUKS unlocking during early startup. The approach is completely different as it requires only one additional hook
systemd-tool
and all further setup is done in special
[X-SystemdTool]
sections in systemd service files. Unfortunately, documentation about this approach and how to use the tool itself is very limited.
Busybox based initramfs (built with mkinitcpio)
Note
This section used to recommend the
mkinitcpio-netconf
mkinitcpio-dropbear
and
mkinitcpio-tinyssh
packages but no longer does so as they are unmaintained. See
this discussion
for more info.
For busybox based initramfs the
mkinitcpio-extras
AUR
package provides the
dropbear
tinyssh
and
netconf
hooks needed for network connectivity and SSH access during the boot process. After installing the package, check its optional dependencies and manually
install
those required by the hooks you plan to use. E.g. to use the
netconf
and
dropbear
hooks, you have to install
mkinitcpio-nfs-utils
and
dropbear
. You also need to install the
mkinitcpio-utils
package which provides the
encryptssh
hook, a drop-in replacement for the
encrypt
hook that prompts for the passphrase upon SSH login.
If you don't have an SSH key pair yet,
generate one
on the client system (the one which will be used to unlock the remote machine).
Note
tinyssh
only supports
Ed25519
and
ECDSA
key types without passphrase.
Add your SSH public key(s) or copy an existing
~/.ssh/authorized_keys
file to the remote machine's
/etc/dropbear/root_key
or
/etc/tinyssh/root_key
file.
Tip
Remember to
regenerate the initramfs
whenever you add or remove keys from the
root_key
file.
Add the
hooks to the
HOOKS
array in
/etc/mkinitcpio.conf
, before
filesystems
, and
regenerate the initramfs
. The
encryptssh
hook replaces the
encrypt
hook.
HOOKS=(... netconf
Configure the required
cryptdevice=
parameter
and add the
ip=
kernel parameter
to your boot loader configuration. E.g. if you use DHCP for network configuration:
ip=dhcp
The hook will wait up to 120 seconds for a response from the DHCP server. This can be adjusted with the
netconf_timeout=
kernel parameter
. Alternatively, configure a static IP:
ip=192.168.1.1:::::eth0:none
You can also specify the subnet mask and gateway if necessary:
ip=192.168.1.1::192.168.1.254:255.255.255.0::eth0:none
The
ip=
parameter supports many more options, e.g configuring multiple interfaces, etc. For more info see the hook's documentation:
mkinitcpio -H netconf
The examples above assume an Ethernet connection. If using Wi-Fi instead,
install
the
mkinitcpio-wifi
AUR
package and create a
wpa_supplicant
configuration:
wpa_passphrase "ESSID" "passphrase" > /etc/wpa_supplicant/initcpio.conf
Then add the
wifi
hook before
netconf
in
/etc/mkinitcpio.conf
, make sure your Wi-Fi related modules are in the
MODULES
array, and use
ip=:::::wlan0:dhcp
as the kernel parameter.
Note
Keep in mind to use kernel device names for the network interface (e.g.
eth0
) and not
udev
's names (e.g.
enp1s0
), as those aren't available during early userspace. Use
dmesg
to find the kernel device name.
It may be necessary to add the module for your
ethernet
or
wireless
network card to the
MODULES
array.
Don't forget to update the configuration of your
boot loader
after making any changes to kernel parameters.
Restart the remote system and
ssh to it
on port 222 as the
root
user. The SSH server in the initramfs generates its own set of host keys and listens on a non-standard port by default to allow your SSH client to verify a separate set of host keys for the initramfs and the main SSH server. Reusing host keys from the main SSH server isn't recommended as the initramfs image may be world-readable which would expose them and make the system vulnerable to MITM attacks. Both the listening port and the host key types can be configured, see the hook documentation for details (
mkinitcpio -H dropbear
or
mkinitcpio -H tinyssh
). You will be prompted for the passphrase to unlock the encrypted device. After unlocking, the system will complete its boot process and you can ssh to it
as you normally would
systemd based initramfs (built with dracut)
If you are using
dracut
instead of
mkinitcpio
, you might want to check out
dracut-sshd
as an alternative to the above options.
One-time password-less reboot
Another method that can be used to reboot a remote, headless or otherwise inaccessible system whilst not needing to be at the terminal to type the encrypted root drive password, is to use a temporary
keyfile
. This will need to be placed in a location that is accessible to the kernel at boot, the
cryptkey
boot parameter will be needed, and that particular keyfile will need to be registered as a valid key by way of the "cryptsetup luksAddKey" command.
This can be done conveniently with the help of
passless-boot
AUR
. The procedure described to setup that tool on
the script's readme file
might serve as a template for setting up a home-made solution also. Do take a look at the discussion in the
Security considerations
section.
Discard/TRIM support for solid state drives (SSD)
Solid state drive
users should be aware that, by default, TRIM commands are not enabled by the device-mapper, i.e. block-devices are mounted without the
discard
option unless you override the default.
The device-mapper maintainers have made it clear that TRIM support will never be enabled by default on dm-crypt devices because of the potential security implications.
[3]
[4]
Minimal data leakage in the form of freed block information, perhaps sufficient to determine the filesystem in use, may occur on devices with TRIM enabled. An illustration and discussion of the issues arising from activating TRIM is available in the
blog
of a
cryptsetup
developer. If you are worried about such factors, keep also in mind that threats may add up: for example, if your device is still encrypted with the previous (cryptsetup <1.6.0) default cipher
--cipher aes-cbc-essiv
, more information leakage may occur from trimmed sector observation than with the current
default
The following cases can be distinguished:
The device is encrypted with default dm-crypt LUKS mode:
By default the LUKS header is stored at the beginning of the device and using TRIM is useful to protect header modifications. If for example a compromised LUKS password is revoked, without TRIM the old header will in general still be available for reading until overwritten by another operation; if the drive is stolen in the meanwhile, the attackers could in theory find a way to locate the old header and use it to decrypt the content with the compromised password. See
cryptsetup FAQ, section 5.19 What about SSDs, Flash and Hybrid Drives?
and
Full disk encryption on an ssd
TRIM can be left disabled if the security issues stated at the top of this section are considered a worse threat than the above bullet. See also
Securely wipe disk#Flash memory
The device is encrypted with dm-crypt plain mode, or the LUKS header is stored
separately
If plausible deniability is required, TRIM should
never
be used because of the considerations at the top of this section, or the use of encryption will be given away.
If plausible deniability is not required, TRIM can be used for its performance gains, provided that the security dangers described at the top of this section are not of concern.
Warning
Before enabling TRIM on a drive, make sure the device fully supports TRIM commands, or data loss can occur. See
Solid state drive#TRIM
Besides enabling discard support in dm-crypt, it is also required to periodically run
fstrim(8)
or mount the filesystem (e.g.
/dev/mapper/root
in this example) with the
discard
option in
/etc/fstab
. For details, please refer to the
TRIM
page.
LUKS2
For a LUKS2 device, TRIM support can be enabled by using the
--allow-discards --persistent
options when opening it. The
allow-discards
flag will be written into the LUKS2 header and the option will be automatically used whenever the LUKS2 device is opened.
Note
Setting new persistent flags via
cryptsetup --persistent
replaces old flags with new ones instead of adding a new flag to the already set flags. This means if you want to enable other flags too, you have to set them all at once.
When using OPAL encryption without dm-crypt (
cryptsetup-luksFormat(8)
option
--hw-opal-only
), discard support does not need to be enabled since there is no dm-crypt layer between the file system and the disk. The mapped device will always pass through discard requests.
# cryptsetup --allow-discards --persistent open /dev/sdaX root
If the device is already opened, the
open
action will raise an error, in which case, use the
cryptsetup-refresh(8)
command instead:
# cryptsetup --allow-discards --persistent refresh root
You can confirm the flag is persistently set in the LUKS2 header by looking at the
cryptsetup luksDump
output:
# cryptsetup luksDump /dev/sdaX | grep Flags
Flags: allow-discards
LUKS1 and plain dm-crypt
For LUKS1 and plain dm-crypt, TRIM support needs to be explicitly enabled when opening the device.
To enable TRIM support during boot, set the following
kernel parameters
If using the
encrypt
hook:
cryptdevice=/dev/sdaX:root:allow-discards
If using the
sd-encrypt
hook with systemd-based initramfs:
rd.luks.options=discard
Note
The
rd.luks.options=discard
kernel option does not have any effect on devices included in the initramfs image's
/etc/crypttab
file (
/etc/crypttab.initramfs
on real root). You must specify option
discard
in
/etc/crypttab.initramfs
For devices unlocked via
/etc/crypttab
use option
discard
, e.g.:
/etc/crypttab
luks-123abcdef-etc UUID=123abcdef-etc none discard
When manually unlocking devices on the console use
--allow-discards
For example, you can open a device with the
--allow-discards
option to execute a manual
fstrim
command:
# cryptsetup --allow-discards open /dev/sdaX root
In any case, you can verify whether the device actually was opened with discards by inspecting the
dmsetup table
output:
# dmsetup table
luks-123abcdef-etc: 0 1234567 crypt aes-xts-plain64 000etc000 0 8:2 4096 1 allow_discards
Disable workqueue for increased solid state drive (SSD) performance
Solid state drive
users should be aware that, by default, discarding internal read and write workqueue commands are not enabled by the device-mapper, i.e. block-devices are mounted without the
no_read_workqueue
and
no_write_workqueue
option unless you override the default.
The
no_read_workqueue
and
no_write_workqueue
flags were introduced by internal Cloudflare research
Speeding up Linux disk encryption
made while investigating overall encryption performance. One of the conclusions is that internal dm-crypt read and write queues decrease performance for SSD drives. While queuing disk operations makes sense for spinning drives, bypassing the queue and writing data synchronously doubled the throughput and cut the SSD drives' IO await operations latency in half. The patches were upstreamed and are available since
linux
5.9 and up
[5]
To disable workqueue for LUKS devices unlocked via
crypttab
use one or more of the desired
no-read-workqueue
or
no-write-workqueue
options. E.g.:
/etc/crypttab
luks-123abcdef-etc UUID=123abcdef-etc none no-read-workqueue
To disable both read and write workqueue add both flags:
/etc/crypttab
luks-123abcdef-etc UUID=123abcdef-etc none no-read-workqueue,no-write-workqueue
With LUKS2 you can set
--perf-no_read_workqueue
and
--perf-no_write_workqueue
as default flags for a device by opening it once with the option
--persistent
. For example:
# cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue --persistent open /dev/
sdaX
root
When the device is already opened, the
open
action will raise an error. You can use the
refresh
option in these cases, e.g.:
# cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue --persistent refresh root
You can confirm which flags are persistently set in the LUKS2 header by looking at the
cryptsetup luksDump
output:
# cryptsetup luksDump /dev/sdaX | grep Flags
Flags: no-read-workqueue
In any case, you can verify whether the device actually was opened with these flags by inspecting the
dmsetup table
output:
# dmsetup table
luks-123abcdef-etc: 0 1234567 crypt aes-xts-plain64 000etc000 0 8:2 4096 1 no_read_workqueue
Note
Setting new persistent flags via
cryptsetup --persistent
replaces old flags with new ones instead of adding a new flag to the already set flags. This means if you want to enable both
--perf-no_read_workqueue
and
--perf-no_write_workqueue
(or more) you have to set them all at once.
Example for setting both
no_read_workqueue
and
no_write_workqueue
with
cryptsetup
# cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue --persistent refresh root
You can confirm both flags being set by inspecting the LUKS2
cryptsetup luksDump
output:
# cryptsetup luksDump /dev/sdaX | grep Flags
Flags: no-read-workqueue no-write-workqueue
The encrypt hook and multiple disks
Note
This section only concerns unlocking in early userspace (in the initramfs phase). For unlocking devices in late userspace (after switch root), see
dm-crypt/System configuration#Unlocking in late userspace
Tip
sd-encrypt
hook supports unlocking multiple devices. They can be specified on the kernel command line or in
/etc/crypttab.initramfs
. See
dm-crypt/System configuration#Using systemd-cryptsetup-generator
The
encrypt
hook only allows for a
single
cryptdevice=
entry (
archlinux/mkinitcpio/mkinitcpio#231
). In system setups with multiple drives this may be limiting, because
dm-crypt
has no feature to exceed the physical device. For example, take "LVM on LUKS": The entire LVM exists inside a LUKS mapper. This is perfectly fine for a single-drive system, since there is only one device to decrypt. But what happens when you want to increase the size of the LVM? You cannot, at least not without modifying the
encrypt
hook.
The following sections briefly show alternatives to overcome the limitation. The first deals with how to expand a
LUKS on LVM
setup to a new disk. The second with modifying the
encrypt
hook to unlock multiple disks in LUKS setups without LVM.
Expanding LVM on multiple disks
The management of multiple disks is a basic
LVM
feature and a major reason for its partitioning flexibility. It can also be used with
dm-crypt
, but only if LVM is employed as the first mapper. In such a
LUKS on LVM
setup the encrypted devices are created inside the logical volumes (with a separate passphrase/key per volume). The following covers the steps to expand that setup to another disk.
Warning
Back up! While resizing filesystems may be standard, keep in mind that operations
may
go wrong and the following might not apply to a particular setup. Generally, extending a filesystem to free disk space is less problematic than shrinking one. This in particular applies when stacked mappers are used, as it is the case in the following example.
Adding a new drive
First, it may be desired to prepare a new disk according to
dm-crypt/Drive preparation
Second, it is partitioned as a LVM, e.g. all space is allocated to
/dev/sdY1
with partition type
8E00
(Linux LVM).
Third, the new disk/partition is attached to the existing LVM volume group, e.g.:
# pvcreate /dev/sdY1
# vgextend MyStorage /dev/sdY1
Extending the logical volume
For the next step, the final allocation of the new diskspace, the logical volume to be extended has to be unmounted. It can be performed for the
cryptdevice
root partition, but in this case the procedure has to be performed from an Arch Install ISO.
In this example, it is assumed that the logical volume for
/home
(lv-name
homevol
) is going to be expanded with the fresh disk space:
# umount /home
# fsck /dev/mapper/home
# cryptsetup close /dev/mapper/home
# lvextend -l +100%FREE MyStorage/homevol
Now the logical volume is extended and the LUKS container comes next:
# cryptsetup open /dev/MyStorage/homevol home
# umount /home # as a safety, in case it was automatically remounted
# cryptsetup --verbose resize home
Finally, the filesystem itself is resized:
# e2fsck -f /dev/mapper/home
# resize2fs /dev/mapper/home
Done! If it went to plan,
/home
can be remounted and now includes the span to the new disk:
# mount /dev/mapper/home /home
Note that the
cryptsetup resize
action does not affect encryption keys, and these have not changed.
Modifying the encrypt hook for multiple partitions
Note that
sd-encrypt
supports multiple partitions out of the box. If several (or all) partitions opened this way share the same passphrase, sd-encrypt will try it for each and not ask for it multiple times. This may be an easier alternative to the following.
Root filesystem spanning multiple partitions
It is possible to modify the encrypt hook to allow multiple hard drive decrypt root (
) at boot. One way:
# cp /usr/lib/initcpio/install/encrypt /etc/initcpio/install/encrypt2
# cp /usr/lib/initcpio/hooks/encrypt /etc/initcpio/hooks/encrypt2
# sed -i "s/cryptdevice/cryptdevice2/" /etc/initcpio/hooks/encrypt2
# sed -i "s/cryptkey/cryptkey2/" /etc/initcpio/hooks/encrypt2
Add
cryptdevice2=
to your boot options (and
cryptkey2=
if needed), and add the
encrypt2
hook to your
mkinitcpio.conf
before rebuilding it. See
dm-crypt/System configuration
Multiple non-root partitions
Maybe you have a requirement for using the
encrypt
hook on a non-root partition. Arch does not support this out of the box, however, you can easily change the cryptdev and cryptname values in
/lib/initcpio/hooks/encrypt
(the first one to your
/dev/sd*
partition, the second to the name you want to attribute). That should be enough.
The big advantage is you can have everything automated, while setting up
/etc/crypttab
with an external key file (i.e. the keyfile is not on any internal hard drive partition) can be a pain - you need to make sure the USB/FireWire/... device gets mounted before the encrypted partition, which means you have to change the order of
/etc/fstab
(at least).
Of course, if the
cryptsetup
package gets upgraded, you will have to change this script again. Unlike
/etc/crypttab
, only one partition is supported, but with some further hacking one should be able to have multiple partitions unlocked.
The factual accuracy of this article or section is disputed.
Reason:
Why not use the supported Grub2 right away? See also
mkinitcpio#Using RAID
(Discuss in
Talk:Dm-crypt/Specialties
If you want to do this on a software RAID partition, there is one more thing you need to do. Just setting the
/dev/mdX
device in
/lib/initcpio/hooks/encrypt
is not enough; the
encrypt
hook will fail to find the key for some reason, and not prompt for a passphrase either. It looks like the RAID devices are not brought up until after the
encrypt
hook is run. You can solve this by putting the RAID array in
/boot/grub/menu.lst
, like
kernel /boot/vmlinuz-linux md=1,/dev/hda5,/dev/hdb5
If you set up your root partition as a RAID, you will notice the similarities with that setup.
GRUB
can handle multiple array definitions just fine:
kernel /boot/vmlinuz-linux root=/dev/md0 ro md=0,/dev/sda1,/dev/sdb1 md=1,/dev/sda5,/dev/sdb5,/dev/sdc5
Encrypted system using a detached LUKS header
This example follows the same setup as in
dm-crypt/Encrypting an entire system#Plain dm-crypt
, which should be read first before following this guide.
By using a detached header the encrypted blockdevice itself only carries encrypted data, which gives
deniable encryption
as long as the existence of a header is unknown to the attackers. It is similar to using
plain dm-crypt
, but with the LUKS advantages such as multiple passphrases for the masterkey and key derivation. Further, using a detached header offers a form of two factor authentication with an easier setup than
using GPG or OpenSSL encrypted keyfiles
, while still having a built-in password prompt for multiple retries. See
Data-at-rest encryption#Cryptographic metadata
for more information.
See
dm-crypt/Device encryption#Encryption options for LUKS mode
for encryption options before performing the first step to setup the encrypted system partition and creating a header file to use with
cryptsetup
# dd if=/dev/zero of=header.img bs=16M count=1
# cryptsetup luksFormat --offset 32768 --header header.img /dev/sdX
Tip
The
--offset
option allows specifying the start of encrypted data on a device. By reserving a space at the beginning of device you have the option of later
reattaching the LUKS header
. The value is specified in 512-byte sectors, see
cryptsetup-luksFormat(8)
for more details.
Open the container:
# cryptsetup open --header header.img /dev/sdX enc
Now follow the
LVM on LUKS setup
to your requirements. The same applies for
preparing the boot partition
on the removable device (because if not, there is no point in having a separate header file for unlocking the encrypted disk).
Next move the
header.img
onto it:
# mv header.img /mnt/boot
Follow the installation procedure up to the mkinitcpio step (you should now be
arch-chroot
ed inside the encrypted system).
Tip
You will notice that since the system partition only has "random" data, it does not have a partition table and by that an
UUID
or a
LABEL
. But you can still have a consistent mapping using the
Persistent block device naming#by-id and by-path
. E.g. using disk id from
/dev/disk/by-id/
There are two options for initramfs to support a detached LUKS header.
Using systemd hook
Set the following
kernel parameters
rd.luks.name=
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
=enc rd.luks.options=
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
=header=/header.img:
UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ
rd.luks.data=
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
=/dev/disk/by-id/
your-disk_id
Replace
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
with the LUKS super block UUID. It can be acquired with
cryptsetup luksDump header.img
or
blkid -s UUID -o value header.img
Replace
UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ
with the block device of volume in which the header file is located.
Alternatively, instead of using the
rd.luks
kernel parameters, the options can be specified in a
/etc/crypttab.initramfs
file:
/etc/crypttab.initramfs
enc /dev/disk/by-id/
your-disk_id
none header=/header.img:
UUID=ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ
Next, modify
/etc/mkinitcpio.conf
to use systemd
and to include the
file system
module for the volume in which the header is located. For example, if it is a
FAT
volume:
/etc/mkinitcpio.conf
...
MODULES=(
vfat
...
HOOKS=(base
systemd
autodetect microcode modconf kms
keyboard
sd-vconsole
block
sd-encrypt
lvm2 filesystems fsck)
...
Regenerate the initramfs
and you are done.
Note
When using
/etc/crypttab.initramfs
, no cryptsetup parameters need to be passed to the kernel command line, since
/etc/crypttab.initramfs
will be added as
/etc/crypttab
in the initramfs.
Refrain from using the
rd.luks
kernel parameters together with
/etc/crypttab.initramfs
as it can cause conflicts. See the warning in
dm-crypt/System configuration#Using systemd-cryptsetup-generator
for details.
Modifying encrypt hook
This method shows how to modify the
encrypt
hook in order to use a detached LUKS header.
Now the
encrypt
hook has to be modified to let
cryptsetup
use the separate header (
archlinux/mkinitcpio/mkinitcpio#234
; base source and idea for these changes
published on the BBS
). Make a copy so it is not overwritten on a
mkinitcpio
update:
# cp /usr/lib/initcpio/hooks/encrypt /etc/initcpio/hooks/encrypt2
# cp /usr/lib/initcpio/install/encrypt /etc/initcpio/install/encrypt2
/etc/initcpio/hooks/encrypt2 (around line 52)
warn_deprecated() {
echo "The syntax 'root=${root}' where '${root}' is an encrypted volume is deprecated"
echo "Use 'cryptdevice=${root}:root root=/dev/mapper/root' instead."
local headerFlag=false
for cryptopt in ${cryptoptions//,/ }; do
case ${cryptopt} in
allow-discards)
cryptargs="${cryptargs} --allow-discards"
;;
header)
cryptargs="${cryptargs} --header /boot/header.img"
headerFlag=true
;;
*)
echo "Encryption option '${cryptopt}' not known, ignoring." >&2
;;
esac
done
if resolved=$(resolve_device "${cryptdev}" ${rootdelay}); then
if
$headerFlag ||
cryptsetup isLuks ${resolved} >/dev/null 2>&1; then
[ ${DEPRECATED_CRYPT} -eq 1 ] && warn_deprecated
dopassphrase=1
Now edit the
mkinitcpio.conf
to add the
encrypt2
and
lvm2
hooks, the
header.img
to
FILES
and the
loop
to
MODULES
, apart from other configuration the system requires:
/etc/mkinitcpio.conf
...
MODULES=(
loop
...
FILES=(
/boot/header.img
...
HOOKS=(base udev autodetect microcode modconf kms
keyboard
keymap
consolefont block
encrypt2
lvm2
filesystems fsck)
...
This is required so the LUKS header is available on boot allowing the decryption of the system, exempting us from a more complicated setup to mount another separate USB device in order to access the header. After this set up
the initramfs
is created.
Next the
boot loader is configured
to specify the
cryptdevice=
also passing the new
header
option for this setup:
cryptdevice=/dev/disk/by-id/
your-disk_id
:enc:header
To finish, following
dm-crypt/Encrypting an entire system#Post-installation
is particularly useful with a
/boot
partition on an USB storage medium.
Encrypted /boot and a detached LUKS header on USB
This article or section is being considered for removal.
Reason:
This scenario was based on
[6]
, whose structure was then changed with
[7]
. (Discuss in
Talk:Dm-crypt/Specialties#Encrypted /boot and a detached LUKS header on USB
Rather than embedding the
header.img
and keyfile into the
initramfs
image, this setup will make your system depend entirely on the usb key rather than just the image to boot, and on the encrypted keyfile inside of the encrypted boot partition. Since the header and keyfile are not included in the
initramfs
image and the custom encrypt hook is specifically for the usb's
by-id
, you will literally need the usb key to boot.
For the usb drive, since you are encrypting the drive and the keyfile inside, it is preferred to cascade the ciphers as to not use the same one twice. Whether a
meet-in-the-middle
attack would actually be feasible is debatable. You can do twofish-serpent or serpent-twofish.
Preparing the disk devices
sdb
will be assumed to be the USB drive,
sda
will be assumed to be the main hard drive.
Prepare the devices according to
dm-crypt/Drive preparation
Preparing the USB key
Use
gdisk
to partition the disk according to the layout
shown here
, with the exception that it should only include the first two partitions. So as follows:
# gdisk /dev/sdb
Number Start (sector) End (sector) Size Code Name
1 2048 1050623 512.0 MiB EF00 EFI System
2 1050624 1460223 200.0 MiB 8300 Linux filesystem
Before running
cryptsetup
, look at the
Encryption options for LUKS mode
and
Ciphers and modes of operation
first to select your desired settings.
Prepare the boot partition
but do not
mount
any partition yet and
Format the EFI system partition
# mount /dev/mapper/cryptboot /mnt
# dd if=/dev/urandom of=/mnt/key.img bs=
filesize
count=1 iflag=fullblock
# cryptsetup luksFormat /mnt/key.img
# cryptsetup open /mnt/key.img lukskey
filesize
is in bytes but can be followed by a suffix such as
. Having too small of a file will get you a nasty
Requested offset is beyond real size of device /dev/loop0
error. As a rough reference, creating a 4M file will encrypt it successfully. You should make the file larger than the space needed since the encrypted loop device will be a little smaller than the file's size.
With a big file, you can use
--keyfile-offset=
offset
and
--keyfile-size=
size
to navigate to the correct position (see
Gentoo:Custom Initramfs#Encrypted keyfile
).
Now you should have
lukskey
opened in a loop device (underneath
/dev/loop1
), mapped as
/dev/mapper/lukskey
The main drive
# truncate -s 16M /mnt/header.img
# cryptsetup --key-file=/dev/mapper/lukskey --keyfile-offset=
offset
--keyfile-size=
size
luksFormat /dev/sda --offset 32768 --header /mnt/header.img
Pick an
offset
and
size
in bytes (8192 KiB is the maximum keyfile size for
cryptsetup
).
# cryptsetup open --header /mnt/header.img --key-file=/dev/mapper/lukskey --keyfile-offset=
offset
--keyfile-size=
size
/dev/sda enc
# cryptsetup close lukskey
# umount /mnt
Follow
Preparing the logical volumes
to set up LVM on LUKS.
See
Partitioning#Discrete partitions
for recommendations on the size of your partitions.
Once your root partition is mounted,
mount
your encrypted boot partition as
/mnt/boot
and your EFI system partition as
/mnt/efi
Installation procedure and custom encrypt hook
Follow the
installation guide
up to the
mkinitcpio
step but do not do it yet, and skip the partitioning, formatting, and mounting steps as they have already been done.
In order to get the encrypted setup to work, you need to build your own hook, which is thankfully easy to do and here is the code you need. You will have to follow
Persistent block device naming#by-id and by-path
to figure out your own
by-id
values for the usb and main hard drive (they are linked -> to
sda
or
sdb
).
You should be using the
by-id
instead of just
sda
or
sdb
because
sdX
can change and this ensures it is the correct device.
You can name
customencrypthook
anything you want, and custom build hooks can be placed in the
hooks
and
install
folders of
/etc/initcpio
. Keep a backup of both files (
cp
them over to the
/home
partition or your user's
/home
directory after you make one).
/usr/bin/ash
is not a typo.
/etc/initcpio/hooks/customencrypthook
#!/usr/bin/ash
run_hook() {
modprobe -a -q dm-crypt >/dev/null 2>&1
modprobe loop
[ "${quiet}" = "y" ] && CSQUIET=">/dev/null"
while [ ! -L '/dev/disk/by-id/
usbdrive
-part2' ]; do
echo 'Waiting for USB'
sleep 1
done
cryptsetup open /dev/disk/by-id/
usbdrive
-part2 cryptboot
mount --mkdir /dev/mapper/cryptboot /mnt
cryptsetup open /mnt/key.img lukskey
cryptsetup --header /mnt/header.img --key-file=/dev/mapper/lukskey --keyfile-offset=''offset'' --keyfile-size=''size'' open /dev/disk/by-id/
harddrive
enc
cryptsetup close lukskey
umount /mnt
usbdrive
is your USB drive
by-id
, and
harddrive
is your main hard drive
by-id
Tip
You could also close
cryptboot
using
cryptsetup close
, but having it open makes it easier to mount for system updates using
Pacman
and regenerating the initramfs with
mkinitcpio
. The
/boot
partition must be mounted for updates that affect the
kernel
or
Initramfs
, and the initramfs will be automatically regenerated after these updates.
# cp /usr/lib/initcpio/install/encrypt /etc/initcpio/install/customencrypthook
Now edit the copied file and remove the
help()
section as it is not necessary.
/etc/mkinitcpio.conf (edit this only do not replace it, these are just excerpts of the necessary parts)
MODULES=(loop)
...
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block customencrypthook lvm2 filesystems fsck)
The
files=()
and
binaries=()
arrays are empty, and you should not have to replace
HOOKS=(...)
array entirely just edit in
customencrypthook lvm2
after
block
and before
filesystems
, and make sure
systemd
and
encrypt
are removed.
Boot loader
Finish the
Installation Guide
from the
mkinitcpio
step. To boot you would need either
GRUB
or
efibootmgr
. Note you can use
GRUB
to support the encrypted disks by
Configuring the boot loader
but editing the
GRUB_CMDLINE_LINUX
is not necessary for this set up.
Or use direct UEFI Secure Boot by generating keys with
cryptboot
AUR
then signing the initramfs and kernel and creating a bootable
.efi
file for your EFI system partition with
sbupdate-git
AUR
. Before using cryptboot or sbupdate note this excerpt from
Secure Boot#Using your own keys
Tip
Note that
cryptboot
AUR
requires the encrypted boot partition to be specified in
/etc/crypttab
before it runs, and if you are using it in combination with
sbupdate-git
AUR
, sbupdate expects the
/boot/efikeys/db.*
files created by cryptboot to be capitalized like
DB.*
unless otherwise configured in
/etc/default/sbupdate
. Users who do not use systemd to handle encryption may not have anything in their
/etc/crypttab
file and would need to create an entry.
# efibootmgr --create --disk /dev/
device
--part
partition_number
--label "Arch Linux Signed" --loader "EFI\Arch\linux-signed.efi" --unicode
See
efibootmgr(8)
for an explanation of the options.
Make sure the boot order puts
Arch Linux Signed
first. If not change it with
efibootmgr --bootorder XXXX,YYYY,ZZZZ --unicode
Changing the LUKS keyfile
This article or section is a candidate for merging with
dm-crypt/Device encryption#Keyfiles
Notes:
Changing the keyfile is not a required action in this setup. (Discuss in
Talk:Dm-crypt/Specialties
# cryptsetup --header /boot/header.img --key-file=/dev/mapper/lukskey --keyfile-offset=
offset
--keyfile-size=
size
luksChangeKey /dev/mapper/enc /dev/mapper/lukskey2 --new-keyfile-size=
newsize
--new-keyfile-offset=
newoffset
Afterwards,
cryptsetup close lukskey
and
shred
or
dd
the old keyfile with random data before deleting it, then make sure that the new keyfile is renamed to the same name of the old one:
key.img
or other name.
Retrieved from "
Category
Data-at-rest encryption
Hidden categories:
Pages or sections flagged with Template:Accuracy
Sections flagged with Template:Remove
Pages or sections flagged with Template:Merge
dm-crypt/Specialties
Add topic