Tags: #security #encryption #FDE #BIOS #UEFI #MBR #GPT #LUKS #LVM #GRUB
Linux: Full Disk Encryption with BIOS, UEFI using MBR, GPT, LUKS, LVM and GRUB
Disk layouts and encryption strategies differ within the Linux realm based on various computer dispositions. This is an overview to achieve full disk encryption (FDE) using GNU GRand Unified Bootloader (GRUB)…
Introduction
In order to perform hardware initialisation during the booting process (power-on startup) and to provide run-time services for operating systems and programs, IBM PC compatible computers utilise firmware, which is a specific class of computer software stored in a non-volatile read-only memory (ROM), erasable programmable ROM (EPROM) or flash memory. The most widespread are:
- Basic Input/Output System (BIOS),
- Unified Extensible Firmware Interface (UEFI).
The fact that the firmware can be replaced enabled not only easy fixes of bugs, but also a possibility of BIOS rootkit infections and other security-related issues, which are somewhat addressed by the UEFI and its secure boot protocol. Besides, UEFI provides support for:
- disks larger than 2 TB,
- CPU-independent architecture and drivers,
- modular design and
- backward compatibility with BIOS.
Note that this overview considers only “standard” Linux kernel provided by the particular Linux distribution. Not all options, such as hibernation/resume, will work with hardened kernels.
Disk Partition Schemes
In order to install an operating system on a physical storage device, it needs to be formatted. There are several ways to partition a disk drive, the most common of which (in Linux-based environment) are the following two:
- Master Boot Record (MBR),
- GUID Partition Table (GPT).
The MBR enables for up to four primary partitions (the partition table has four “slots”). If more partitions are needed, one of them needs to be replaced by an extended partition that can contain several logical partitions in it. The total number of partitions depends on the operating system and formatting tool. On the other hand, GPT can contain up to 128 (“primary”) partitions and of size up to 8 ZiB = (2^64)*512 bytes.
In order to start an operating system, a boot loader needs to be executed. The location of a boot loader and its other requirements on partitions differ as per each software. A reliable workhorse of all boot loaders is the GNU GRand Unified Bootloader (GRUB).
GRand Unified Bootloader (GRUB)
In the realm of BIOS, GRUB itself is not a single binary, rather it is a group of executable code that can be loaded in the following stages:
- Stage 1 (
boot.img
)- is always stored within the first 446 bytes (of the total 512 bytes) of the disk
- and contains only a pointer to either stage 1.5 or 2,
- Stage 1.5 (
core.img
)- contains file system drivers to address Stage 2 by full path and file name,
- Stage 2
- is located on a file system, usually in
/boot/grub
and - contains modules and smarts necessary to prepare the system for a real OS.
- is located on a file system, usually in
The location of the boot.img
and core.img
files depends on whether the disk drive is formatted using MBR or GPT. The difference is nicely depicted either in Wikipedia or Barney Desmond’s blog.
If GRUB is used as the boot loader, BIOS systems that are partitioned with GPT require a BIOS boot partition (BBP), which is:
- type
EF02
, - should be of size 1-2 MiB,
- unformatted,
- is not mounted anywhere, as it only serves as a “replacement” disk space for GRUB stage 1.5 loader (
core.img
).
In the realm of UEFI and 64-bit computer architecture (x86_64
), GRUB is a single binary named grubx64.efi
located in the \EFI\grub\
directory (FAT notation) in the EFI System Partition (ESP), which is:
- type
EF00
, but also denoted as:EFI System
(by fdisk) orboot, esp
(by GNU parted),
- should be of size 200 MiB and more,
- formatted as FAT16 or FAT32,
- is mounted in
/etc/efi
in Linux-based system.
Some UEFI-based systems are equipped with Compatibility Support Module (CSM) which enables booting in legacy BIOS mode from MBR-partitioned disks relying on the content of a boot sector. If GRUB is used as the boot loader, UEFI reads the Stage 1 (boot.img
) instead of reading the content of the ESP.
Full Disk Encryption (FDE)
Unless designed as deniable, any encryption method regardless of key strength will always be subject to the Rubberhose Attack. The following examples do not provide plausible deniability, but they can be modified accordingly. Reader discretion advised!
There exist several ways to achieve full disk encryption (FDE). Considering that a computer system has a single hard drive, the following example considers the LVM on LUKS scenario only, as it utilises:
- Linux Unified Key Setup (LUKS) and
- Logical Volume Manager (LVM).
In other words, the scenario creates logical volumes within a LUKS-encrypted partition, which is:
- type
8E00
, but also denoted asLinux LVM
, - contains an encrypted container that can have multiple keys set up (passphrase, binary key file etc.),
- is available in the
/dev/mapper/
directory once opened.
So the root and swap partitions will be created as logical volumes within a volume group that is encrypted within a single LUKS physical volume available as follows:
- the physical partition
Y
on disk driveX
in:/dev/sdXY
, - the decrypted LUKS container in:
/dev/mapper/CONTAINER-ID
- the volume group in:
/dev/VOLUME-GROUP-ID
- the swap volume in:
/dev/VOLUME-GROUP-ID/SWAP-VOLUME-ID
- the root volume in:
/dev/VOLUME-GROUP-ID/ROOT-VOLUME-ID
The disk partition details and format can be depicted as follows:

LUKS and LVM Device Availability
Practical Approaches
To sum the aforementioned information up, users or administrators can work with:
- BIOS- or UEFI-based computer systems, and
- MBR- or GPT-based disk partitioning schemes.
These four options generate four possible practical approaches:
- BIOS-based system and MBR-based partition scheme,
- BIOS-based system and GPT-based partition scheme,
- UEFI-based system and MBR-based partition scheme (CSM and native),
- UEFI-based system and GPT-based partition scheme.
GRUB on BIOS with MBR
The disk partitioning schema and format of partitions can be depicted as follows:

GRUB on BIOS with MBR
In order to achieve full disk encryption, the necessary commands are as follows:
$ parted -s /dev/sda mklabel msdos
$ parted -s -a optimal /dev/sda mkpart primary "0%" "100%"
$ parted -s /dev/sda set 1 boot on
$ parted -s /dev/sda set 1 lvm on
$ parted -s /dev/sda print
$ cryptsetup luksFormat -v /dev/sda1
$ cryptsetup luksOpen /dev/sda1 lvm-system
$ pvcreate /dev/mapper/lvm-system
$ vgcreate lvmSystem /dev/mapper/lvm-system
$ lvcreate -L 1G lvmSystem -n volSwap
$ lvcreate -l +100%FREE lvmSystem -n volRoot
$ mkswap /dev/lvmSystem/volSwap
$ mkfs.ext4 -L volRoot /dev/lvmSystem/volRoot
$ swapon /dev/lvmSystem/volSwap
$ mount /dev/lvmSystem/volRoot /mnt
...
$ sed -i "s/FILES=(/FILES=(\/crypto_keyfile.bin/g" /etc/mkinitcpio.conf
$ sed -i "s/modconf block/modconf block encrypt lvm2 resume/g" /etc/mkinitcpio.conf
$ dd if=/dev/random of=/crypto_keyfile.bin bs=512 count=8 iflag=fullblock
$ cryptsetup luksAddKey /dev/sda1 /crypto_keyfile.bin
$ chmod 000 /crypto_keyfile.bin
$ mkinitcpio -p linux
...
$ sed -i "s/quiet/quiet resume=UUID=`blkid -s UUID -o value /dev/lvmSystem/volSwap`/g" /etc/default/grub
$ sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=`blkid -s UUID -o value /dev/sda1`:lvm-system\"/g" /etc/default/grub
$ sed -i "s/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g" /etc/default/grub
$ grub-install --target=i386-pc --recheck /dev/sda
$ grub-mkconfig -o /boot/grub/grub.cfg
GRUB on BIOS with GPT
The disk partitioning schema and format of partitions can be depicted as follows:

GRUB on BIOS with GPT
In order to achieve full disk encryption, the necessary commands are as follows:
$ parted -s /dev/sda mklabel gpt
$ parted -s -a optimal /dev/sda mkpart primary "0%" "2MiB"
$ parted -s /dev/sda set 1 bios_grub on
$ parted -s -a optimal /dev/sda mkpart "primary" "2MiB" "100%"
$ parted -s /dev/sda set 2 lvm on
$ parted -s /dev/sda print
$ cryptsetup luksFormat -v /dev/sda2
$ cryptsetup luksOpen /dev/sda2 lvm-system
$ pvcreate /dev/mapper/lvm-system
$ vgcreate lvmSystem /dev/mapper/lvm-system
$ lvcreate -L 1G lvmSystem -n volSwap
$ lvcreate -l +100%FREE lvmSystem -n volRoot
$ mkswap /dev/lvmSystem/volSwap
$ mkfs.ext4 -L volRoot /dev/lvmSystem/volRoot
$ swapon /dev/lvmSystem/volSwap
$ mount /dev/lvmSystem/volRoot /mnt
...
$ sed -i "s/FILES=(/FILES=(\/crypto_keyfile.bin/g" /etc/mkinitcpio.conf
$ sed -i "s/modconf block/modconf block encrypt lvm2 resume/g" /etc/mkinitcpio.conf
$ dd if=/dev/random of=/crypto_keyfile.bin bs=512 count=8 iflag=fullblock
$ cryptsetup luksAddKey /dev/sda2 /crypto_keyfile.bin
$ chmod 000 /crypto_keyfile.bin
$ mkinitcpio -p linux
...
$ sed -i "s/quiet/quiet resume=UUID=`blkid -s UUID -o value /dev/lvmSystem/volSwap`/g" /etc/default/grub
$ sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=`blkid -s UUID -o value /dev/sda2`:lvm-system\"/g" /etc/default/grub
$ sed -i "s/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g" /etc/default/grub
$ grub-install --target=i386-pc --recheck /dev/sda
$ grub-mkconfig -o /boot/grub/grub.cfg
GRUB on UEFI with MBR
Theoretically, it could work with either no ESP partition at all, loading the GRUB from the first sector of the MBR just like in “BIOS with MBR” case; or with ESP partition grub containing something like: /boot/grub/grub386.efi
. Either way, this is a very non-standard and non-recommended way to partition the disks.
A more systematic and standard way would be to use the ESP as follows:

GRUB on UEFI with MBR
In order to achieve full disk encryption, the necessary commands are as follows:
$ parted -s /dev/sda print
$ parted -s /dev/sda mklabel msdos
$ parted -s -a optimal /dev/sda mkpart primary "0%" "512MiB"
$ parted -s /dev/sda set 1 esp on
$ parted -s -a optimal /dev/sda mkpart "primary" "512MiB" "100%"
$ parted -s /dev/sda set 2 lvm on
$ parted -s /dev/sda print
$ cryptsetup luksFormat -v /dev/sda2
$ cryptsetup luksOpen /dev/sda2 lvm-system
$ pvcreate /dev/mapper/lvm-system
$ vgcreate lvmSystem /dev/mapper/lvm-system
$ lvcreate -L 1G lvmSystem -n volSwap
$ lvcreate -l +100%FREE lvmSystem -n volRoot
$ mkswap /dev/lvmSystem/volSwap
$ mkfs.fat -F 32 -n ESP /dev/sda1
$ mkfs.ext4 -L volRoot /dev/lvmSystem/volRoot
$ swapon /dev/lvmSystem/volSwap
$ mount /dev/lvmSystem/volRoot /mnt
$ mkdir -p /mnt/boot/efi
$ mount /dev/sda1 /mnt/boot/efi
...
$ sed -i "s/FILES=(/FILES=(\/crypto_keyfile.bin/g" /etc/mkinitcpio.conf
$ sed -i "s/modconf block/modconf block encrypt lvm2 resume/g" /etc/mkinitcpio.conf
$ dd if=/dev/random of=/crypto_keyfile.bin bs=512 count=8 iflag=fullblock
$ cryptsetup luksAddKey /dev/sda2 /crypto_keyfile.bin
$ chmod 000 /crypto_keyfile.bin
$ mkinitcpio -p linux
...
$ sed -i "s/quiet/quiet resume=UUID=`blkid -s UUID -o value /dev/lvmSystem/volSwap`/g" /etc/default/grub
$ sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=`blkid -s UUID -o value /dev/sda2`:lvm-system\"/g" /etc/default/grub
$ sed -i "s/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g" /etc/default/grub
$ grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=artix --recheck /dev/sda
$ grub-mkconfig -o /boot/grub/grub.cfg
GRUB on UEFI with GPT
The disk partitioning schema and format of partitions can be depicted as follows:

GRUB on UEFI with GPT
In order to achieve full disk encryption, the necessary commands are as follows:
$ parted -s /dev/sda print
$ parted -s /dev/sda mklabel gpt
$ parted -s -a optimal /dev/sda mkpart primary "0%" "512MiB"
$ parted -s /dev/sda set 1 esp on
$ parted -s -a optimal /dev/sda mkpart "primary" "512MiB" "100%"
$ parted -s /dev/sda set 2 lvm on
$ parted -s /dev/sda print
$ cryptsetup luksFormat -v /dev/sda2
$ cryptsetup luksOpen /dev/sda2 lvm-system
$ pvcreate /dev/mapper/lvm-system
$ vgcreate lvmSystem /dev/mapper/lvm-system
$ lvcreate -L 1G lvmSystem -n volSwap
$ lvcreate -l +100%FREE lvmSystem -n volRoot
$ mkswap /dev/lvmSystem/volSwap
$ mkfs.fat -F 32 -n ESP /dev/sda1
$ mkfs.ext4 -L volRoot /dev/lvmSystem/volRoot
$ swapon /dev/lvmSystem/volSwap
$ mount /dev/lvmSystem/volRoot /mnt
$ mkdir -p /mnt/boot/efi
$ mount /dev/sda1 /mnt/boot/efi
...
$ sed -i "s/FILES=(/FILES=(\/crypto_keyfile.bin/g" /etc/mkinitcpio.conf
$ sed -i "s/modconf block/modconf block encrypt lvm2 resume/g" /etc/mkinitcpio.conf
$ dd if=/dev/random of=/crypto_keyfile.bin bs=512 count=8 iflag=fullblock
$ cryptsetup luksAddKey /dev/sda2 /crypto_keyfile.bin
$ chmod 000 /crypto_keyfile.bin
$ mkinitcpio -p linux
...
$ sed -i "s/quiet/quiet resume=UUID=`blkid -s UUID -o value /dev/lvmSystem/volSwap`/g" /etc/default/grub
$ sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=`blkid -s UUID -o value /dev/sda2`:lvm-system\"/g" /etc/default/grub
$ sed -i "s/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g" /etc/default/grub
$ grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=artix --recheck /dev/sda
$ grub-mkconfig -o /boot/grub/grub.cfg
UEFI Boot Records Management
Some UEFI firmware (e.g. VirtualBox) likes to search for EFI in \EFI\BOOT\bootx64.efi
. This can be easily resolved by the following copy command:
$ mkdir -p /boot/efi/EFI/BOOT
$ cp /boot/efi/EFI/artix/grubx64.efi /boot/efi/EFI/BOOT/bootx64.efi
Different UEFI may require different approaches. If necessary, the UEFI boot records can be manipulated using the efibootmgr
utility. For instance, in order to:
- show all boot records:
$ efibootmgr
- delete a
0x002a
record:
$ efibootmgr --bootnum 002a --delete-bootnum
- add a record to boot from ESP path:
$ efibootmgr --create --disk /dev/sdDISK-LETTER --part PARTITION-NUMBER --loader "\EFI\PATH\grubx64.efi" --label "BOOT RECORD LABEL"
Automatic Mounting of Other Partitions
Having a desktop computer with more disks or simply separating partitions for /home
, /tmp
, /var
directories from the root partition seem to be a reasonable solution for many administrators. A random byte file can be generated in order to serve as key to the encrypted partition(s), example of which is as follows (assuming there will be a single partition on disk sdY
and the key used will be called lvm-data.bin
and located in a newly created /etc/luks-keys
directory, which nobody needs to have access to):
$ mkdir -m 700 /etc/luks-keys
$ dd if=/dev/random of=/etc/luks-keys/lvm-data.bin bs=512 count=8 iflag=fullblock
$ cryptsetup luksAddKey /dev/sdY1 /etc/luks-keys/lvm-data.bin
$ chmod 000 /etc/luks-keys/*
For more details regarding usage of /dev/random
and /dev/urandom
for keys generation, this ArchWiki page can be visited.
An automatic decryption and mounting of an encrypted partition can be performed in regards to the init (short for initialisation) system installed:
$ echo "lvm-data UUID=\"`blkid -s UUID -o value /dev/sdY1`\" /etc/luks-keys/lvm-data.bin" >> /etc/crypttab
- In case of OpenRC, the process is configured in the
/etc/conf.d/dmcrypt
file:
$ echo "target=lvm-data" >> /etc/conf.d/dmcrypt
$ echo "source=UUID=\"`blkid -s UUID -o value /dev/sdY1`\"" >> /etc/conf.d/dmcrypt
$ echo "key=/etc/luks-keys/lvm-data.bin" >> /etc/conf.d/dmcrypt
Finally, the respective options need to be put into the /etc/fstab
file in order to get the disk partitions mounted accordingly:
$ echo "UUID=`blkid -s UUID -o value /dev/lvmData/volHome` /home ext4 rw,relatime,data=ordered 0 0" >> /etc/fstab