March 27, 2020, 9:14 a.m.
Root LUKS Disk Encryption Raspberry Pi
IMPORTANT: Before you start following this tutorial, I suggest that you create backup of your Raspbian install (the entire microSD card of your Pi, if you are using a microSD card). This will not prevent attackers from doing something like ‘evil maid attack’ on the unencrypted boot partition. Physical security is a must, don’t ever let some one access to the microSD of the Pi!
I will not be held responsible for the lost of your valuable files.
Situation: You want to encrypt your currently unencrypted Raspbian /
partition including your /home
partition to protect sensitive files. Except for the /boot
partition. You have a free space that is twice of the total partition size of your /
, this free space can be in your Debian or any other GNU+Linux Operating System or in your current Pi storage medium (microSD, USB HDD SATA, etc.).
Steps that we will do:
- Backup your Pi’s current root partition and boot partition (Out of the scope of this tutorial).
- Update the Raspbian install, install dependencies and reboot. The current version is Raspbian 10.3 Buster (debian 10.3 32bit / Linux 4.19.97-v7+).
- Create our encrypted partition with cryptsetup. If your kernel version is greater than 4.21, you may want to use a different cipher for cryptsetup as it should be much faster than AES.
- Configure the current system to enable booting with encrypted root partition. (Generate initramfs)
- Decrypt and mount our encrypted partition and rsync (copy) all of our current system files to it.
- Reboot the system. (The next boot should fail with
dropping to initramfs, could not find root device!
) - Plug in Monitor and Keyboard to decrypt the encrypted root partition, Generate new initramfs then reboot.
- Enjoy
Current system configuration:
I am using a USB SATA HDD that has the unencrypted root partition. The microSD card has the boot partition because my USB SATA HDD cannot boot with Mass Storage Mode (Slow startup of spinning disk!).
By default here are the path of the devices:
/dev/mmcblk0p1 = /boot
/dev/sda1 = /
The microSD will always be detected as /dev/mmcblk0
, for the first partition /dev/mmcblk0p1
(this is always the /boot partition), for the root partition it will be /dev/mmcblk0p2
.
If you have more USB storage devices, it will be listed as /dev/sda2, /dev/sda3, ... /dev/sdX
My old /etc/fstab
file:
proc /proc proc defaults 0 0
# The line below is my unencrypted /boot partition (located on my microSD, detected as 63a3cc91-01, 63a3cc91 - is card UUID, 01 - is the first partition)
PARTUUID=63a3cc91-01 /boot vfat defaults 0 2
# The line below is my unencrypted root partition (this is located on my USB SATA HDD, 9f0bb82d is my HDD UUID, 03 - is the partition number of that HDD)
PARTUUID=9f0bb82d-03 / ext4 defaults,noatime 0 1
# I was using a microSD for my / partition before, I added the lines below to prevent the wear of SD Card
tmpfs /var/tmp tmpfs nodev,nosuid,noatime 0 0
tmpfs /tmp tmpfs defaults,noatime,nosuid 0 0
You may want to update and upgrade your Raspbian:
$ sudo apt update
$ sudo apt upgrade
Install dependencies and reboot:
$ sudo apt-get install cryptsetup lvm2 busybox rsync initramfs-tools
$ sudo reboot
Take note of your current UUIDs:
$ sudo blkid
/dev/mmcblk0: PTUUID="63a3cc81" PTTYPE="dos"
/dev/mmcblk0p1: LABEL_FATBOOT="BOOT" LABEL="BOOT" TYPE="vfat" PARTUUID="63a3cc91-01"
/dev/sda: PARTUUID="9f0bb82d"
/dev/sda3: LABEL="rfs" UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4" PARTUUID="9f0bb82d-03"
...
/dev/mmcblk0p1 - is the /boot stored in the microSD.
/dev/sda3 - unencrypted current root partition
...
Create our encrypted LUKS partition:
Raspberry Pi does not have a hardware-accelerated AES support, AES encryption/decryption will be very slow! Starting in kernel 4.21, a new encryption cipher can be used with cryptsetup, this is the Google Adiantum. This is much faster than the AES and more secure.
Credits to Kendek: https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=252980&p=1543723&hilit=LUKS#p1543753
If you are using Linux Kernel >4.21 you can try to benchmark that encryption cipher and use that instead of the default AES:
$ sudo cryptsetup benchmark -c xchacha12,aes-adiantum
$ sudo cryptsetup benchmark -c xchacha20,aes-adiantum
Current default cipher benchmark for RPi 3B+:
$ sudo cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1 147936 iterations per second for 256-bit key
PBKDF2-sha256 242277 iterations per second for 256-bit key
PBKDF2-sha512 158299 iterations per second for 256-bit key
PBKDF2-ripemd160 115177 iterations per second for 256-bit key
PBKDF2-whirlpool 22021 iterations per second for 256-bit key
argon2i 4 iterations, 110020 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
argon2id 4 iterations, 140072 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
# Algorithm | Key | Encryption | Decryption
aes-cbc 128b 25.2 MiB/s 49.2 MiB/s
aes-cbc 256b 21.0 MiB/s 37.0 MiB/s
aes-xts 256b 55.5 MiB/s 48.1 MiB/s
aes-xts 512b 41.5 MiB/s 36.3 MiB/s
We now need to create a new partition to our target drive. You can use gparted with this. Be careful to not delete your current partition or system partitions!
I assume that we have a USB SATA HDD or microSD drive with free space, and uses the old Master Boot Record partition type (I have not tested this on a GPT boot record). The MBR partitioning table allows up to four primary partitions only. Use GPT if you want to create more partitions but you will need to reformat the entire disk to change the partition table.
Plug in your microSD or USB HDD to your computer, I assume that you use GNU+Linux or just get a bootable gparted CD or Virtual Machine.
Open gparted and select your target drive.
NOTE: /dev/sda is always the first drive in your system, in this case it could be your Operating System drive (DO NOT SELECT THIS DRIVE!, YOU CAN DELETE YOUR CURRENT OPERATING SYSTEM with this tool.), for example the target drive is detected as /dev/sda2.
Now, if you have a free space you can create a new partition. It must be the same size as your current Pi partition as we will clone the data from that partition to our encryped partition. If you don’t have a free space, you can shrink your current Pi partition but this may take a long long time and may risk data corruption if you accidentally disconnect the drive, so always create backups.
Create the partition, select the type to unformatted. Double check, then click Apply.
Eject the drive and plug it back in to our Raspberry Pi.
Boot up the Raspberry Pi. Proceed to the steps below.
SSH to your Pi or just plug in Monitor, Keyboard and Mouse. We will now format the partition that we created earlier with cryptsetup to encrypt it.
Display the device partitions, determine the new partition that we created earlier:
$ sudo blkid
/dev/mmcblk0: PTUUID="63a3cc81" PTTYPE="dos"
/dev/mmcblk0p1: LABEL_FATBOOT="BOOT" LABEL="BOOT" TYPE="vfat" PARTUUID="63a3cc91-01"
/dev/sda: PARTUUID="9f0bb82d"
/dev/sda3: LABEL="rfs" UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4" PARTUUID="9f0bb82d-03"
/dev/sda4: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="unknown" PARTUUID="9f0bb82d-04"
/dev/sda4
is the partition that we created earlier. We will now format this partition to be encrypted.
/dev/mmcblk0p1 - is the /boot stored in the microSD.
/dev/sda3 - unencrypted current root partition
/dev/sda4 - our created partition
If the Pi’s Linux Kernel is 5.4 (Long Term Support) Release, then you should use the Google Adiantum cipher for a fast encryption/decryption. You can use this command to format the target partition (not tested!):
$ sudo cryptsetup luksFormat --type=luks2 --sector-size=4096 -c xchacha12,aes-adiantum-plain64 -s 256 -h sha512 --use-urandom /dev/sda4
Replace sda4 with your partition name. Credits to rpi forum member Kendek, for the command above.
Otherwise, we are just going to use the default non optimized cryptsetup LUKS cipher. ( I am too lazy to find an optimized alternative for AES. Read: https://security.stackexchange.com/questions/40208/recommended-options-for-luks-cryptsetup
)
Start encrypting the partition (formatting), creating a new EXT4 filesystem then mounting it:
$ sudo cryptsetup luksFormat /dev/sda4
WARNING!
========
This will overwrite data on /dev/sda4 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sda4:
Verify passphrase:
Decrypt the partition:
$ sudo cryptsetup luksOpen /dev/sda4 sda4
Enter passphrase for /dev/sda4:
Create a new EXT4 filesystem with a label of root
:
$ sudo mkfs.ext4 -L root /dev/mapper/sda4
mke2fs 1.44.5 (15-Dec-2018)
Creating filesystem with 2615552 4k blocks and 654080 inodes
Filesystem UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
Mount the partition to /mnt
:
$ sudo mount /dev/mapper/sda4 /mnt
Check our UUIDs again:
$ sudo blkid
/dev/mmcblk0: PTUUID="63a3cc81" PTTYPE="dos"
/dev/mmcblk0p1: LABEL_FATBOOT="BOOT" LABEL="BOOT" TYPE="vfat" PARTUUID="63a3cc91-01"
/dev/sda: PARTUUID="9f0bb82d"
/dev/sda3: LABEL="rfs" UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4" PARTUUID="9f0bb82d-03"
/dev/sda4: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="crypto_LUKS" PARTUUID="9f0bb82d-04"
/dev/sda4
partition type crypto_LUKS
, this means it is a LUKS encrypted partition.
/dev/mmcblk0p1 - is the /boot stored in the microSD.
/dev/sda3 - unencrypted current root partition
/dev/sda4 - our created LUKS encrypted partition
Configure the Raspbian to use the encrypted device as root partition:
Edit the file /boot/config.txt
and append our to be created initramfs:
$ sudo nano /boot/config.txt
initramfs initramfs.gz followkernel
Edit the file /boot/cmdline.txt
located on /boot
and change the root
location:
$ sudo nano /boot/cmdline.txt
root=/dev/mapper/crypt cryptdevice=/dev/sda4:crypt
Edit the file /etc/cryptsetup-initramfs/conf-hook
and change to CRYPTSETUP=y
:
$ sudo nano /etc/cryptsetup-initramfs/conf-hook
#
# Configuration file for the cryptroot initramfs hook.
#
#
# CRYPTSETUP: [ y | n ]
#
# Add cryptsetup and its dependencies to the initramfs image, regardless
# of _this_ machine configuration. By default, they're only added when
# a device is detected that needs to be unlocked at initramfs stage
# (such as root or resume devices or ones with explicit 'initramfs' flag
# in /etc/crypttab).
# Note: Honoring this setting will be deprecated in the future. Please
# uninstall the 'cryptsetup-initramfs' package if you don't want the
# cryptsetup initramfs integration.
#
CRYPTSETUP=y
Edit the file /etc/crypttab
, add our encrypted luks partition:
crypt /dev/sda4 none luks
If you have more drives, you can change the /dev/sda4
to point to it’s UUID:
crypt /dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none luks
Edit the file /etc/fstab
, change the root partition to point to our encrypted partition, comment out our old root partition so we can revert to this if we have issues:
proc /proc proc defaults 0 0
# The line below is my unencrypted /boot partition (located on my microSD, detected as 63a3cc91-01, 63a3cc91 - is card UUID, 01 - is the first partition)
PARTUUID=63a3cc91-01 /boot vfat defaults 0 2
# The line below is my unencrypted root partition (this is located on my USB SATA HDD, 9f0bb82d is my HDD UUID, 03 - is the partition number of that HDD)
#PARTUUID=9f0bb82d-03 / ext4 defaults,noatime 0 1
# This is now our encrypted root partition.
/dev/mapper/crypt / ext4 defaults,noatime 0 1
# I was using a microSD for my / partition before, I added the lines below to prevent the wear of SD Card
tmpfs /var/tmp tmpfs nodev,nosuid,noatime 0 0
tmpfs /tmp tmpfs defaults,noatime,nosuid 0 0
Generate initramfs (there will be warning, but ignore them for now):
$ sudo mkinitramfs -o /boot/initramfs.gz
Determine whether cryptsetup
file is included in our initramfs
. It must have that file, otherwise the we will fail to unlock our encrypted partition.
$ lsinitramfs /boot/initramfs.gz | grep cryptsetup
usr/lib/arm-linux-gnueabihf/libcryptsetup.so.12
usr/lib/arm-linux-gnueabihf/libcryptsetup.so.12.4.0
usr/lib/cryptsetup
usr/lib/cryptsetup/askpass
usr/lib/cryptsetup/functions
usr/sbin/cryptsetup
Clone our current system to our new encrypted partition:
Depending on your target medium and your number of files, this may take a while. Do not do anything until this is completed.
$ sudo rsync -avhPHAXx --progress --exclude={/dev/*,/proc/*,/sys/*,/tmp/*,/run/*,/mnt/*,/media/*,/lost+found} / /mnt/
sending incremental file list
./
.autorelabel
0 100% 0.00kB/s 0:00:00 (xfr#1, ir-chk=1020/1022)
bin/
bin/bash
925.12K 100% 42.55MB/s 0:00:00 (xfr#2, ir-chk=1165/1188)
bin/btrfs
814.53K 100% 13.87MB/s 0:00:00 (xfr#3, ir-chk=1164/1188)
bin/btrfs-find-root
440.88K 100% 5.39MB/s 0:00:00 (xfr#4, ir-chk=1163/1188)
bin/btrfs-image
473.73K 100% 4.43MB/s 0:00:00 (xfr#5, ir-chk=1162/1188)
bin/btrfs-map-logical
444.98K 100% 3.48MB/s 0:00:00 (xfr#6, ir-chk=1161/1188)
bin/btrfs-select-super
440.88K 100% 2.96MB/s 0:00:00 (xfr#7, ir-chk=1160/1188)
bin/btrfsck -> btrfs
bin/btrfstune
449.07K 100% 2.63MB/s 0:00:00 (xfr#8, ir-chk=1158/1188)
bin/busybox
743.21K 100% 3.65MB/s 0:00:00 (xfr#9, ir-chk=1156/1188)
bin/bzcmp -> bzdiff
bin/bzdiff
2.23K 100% 11.15kB/s 0:00:00 (xfr#10, ir-chk=1153/1188)
bin/bzegrep -> bzgrep
bin/bzexe
.
.
.
.
13.63K 100% 166.41kB/s 0:00:00 (xfr#222234, to-chk=0/270837)
sent 6.50G bytes received 4.50M bytes 1.64M bytes/sec
total size is 7.00G speedup is 1.08
First boot
We are now done, umount the encrypted partition and reboot.
Plug in your monitor, mouse and keyboard if you have not done so. The first boot will fail and we need to generate initramfs for it to work in the next reboot.
While in the busybox initramfs prompt, we now mount our encrypted partition and exit:
(initramfs) cryptsetup luksOpen /dev/sda4 crypt
WARNING: Locking directory /run/cryptsetup is missing?
Enter passphrase for /dev/sda4:
(initramfs) exit
Begin will now check root file system ... fsck from util-linux ...
The system should be able to boot completely.
After the bootup is completed, we will generate initramfs again to fix initramfs for not detecting the encrypted root partition:
$ sudo mkinitramfs -o /boot/initramfs.gz
Reboot the system and you should now be asked a passphrase when booting your encrypted root partition. You can now delete the old unencrypted partition. You need to generate initramfs after updating your Raspbian.
$ sudo sync
$ sudo reboot
Enjoy!
Video: https://youtube.com/watch?v=67WHIzLaly4
TODO: Dropbear SSH login and USB Boot Key file.
References:
https://robpol86.com/raspberry_pi_luks.html
https://github.com/NicoHood/NicoHood.github.io/wiki/Raspberry-Pi-Encrypt-Root-Partition-Tutorial
https://www.raspberrypi.org/forums/viewtopic.php?f=66&t=219867
https://paxswill.com/blog/2013/11/04/encrypted-raspberry-pi/