RaspberryPi with Root Partition encryption, unlocked using a flash drive

Page content
  • Why unlock using flash drive: Because you don’t have keyboard or monitor connected to your RPi, do you?
  • Information: I was using Pezz’s gist, which helped me a lot. Thank you very much, Pezz.
  • Why Arch linux: because I wanted to try Arch, default kernels of Raspbian and Pidora lack(lacked? Maybe already have) needed encryption modules.

SD card preparation

Download Arch linux image from here: RPi downloads

On your desktop check list of devices:

$ ls -lah /dev | grep sd

brw-rw---T   1 root disk      8,   0 Aug 11 15:43 sda
brw-rw---T   1 root disk      8,   1 Aug 11 15:43 sda1
brw-rw---T   1 root disk      8,   2 Aug 11 15:43 sda2
brw-rw---T   1 root disk      8,   3 Aug 11 15:43 sda3
brw-rw---T   1 root disk      8,   4 Aug 11 15:43 sda4

Now insert SD card into card reader on desktop, and check list once again. You’ll see a new device we’ll write Arch linux image to.

Achtung! You should write image to device itself, /dev/sdb, for example, not to partitions like /dev/sdb1, if there are any.

Write image to SD card:

# dd bs=1M if=archlinux-hf-2013-02-11.img of=/dev/sdb

That’s all folks, insert SD card into RPi, connect network cable and power supply. RPi should start to blink its LEDs and load.

Preliminary RPi configuration

RPi should get IP address from router via DHCP.

You can scan network for the new device:

# nmap -sP 192.168.1.0/24

Starting Nmap 6.00 ( http://nmap.org ) at 2013-08-24 10:09 EEST
Nmap scan report for DD-WRT (192.168.1.1)
Host is up (0.0029s latency).
MAC Address: 00:56:D2:E3:1D:3C (Unknown)
Nmap scan report for Net_host (192.168.1.98)
Host is up.
Nmap scan report for android-9548dffb92e3904f (192.168.1.121)
Host is up (0.10s latency).
MAC Address: 68:9C:5E:B7:43:8F (AcSiP Technology)
Nmap scan report for homepi (192.168.1.137)
Host is up (0.0026s latency).
MAC Address: B8:27:EB:EA:5F:DE (Raspberry Pi Foundation)
Nmap done: 256 IP addresses (4 hosts up) scanned in 3.24 seconds

192.168.1.137 is an IP address we need. Log into RPi from desktop using login/password root/root:

$ ssh [email protected]

Change hostname:

# hostnamectl set-hostname here-your-hostname-goes

I’m using RPi as a server only so I’ve assigned minimum memory to GPU RPi is able to load with, 16Mb. Also I’ve commented all strings related to dynamic memory management:

# vi /boot/config.txt

#gpu_mem_512=316
#gpu_mem_256=128
#cma_lwm=16
#cma_hwm=32
#cma_offline_start=16
gpu_mem=16

Network configuration

By default RPi gets IP address via DHCP, we’ll assign a static IP:

# cp /etc/netctl/examples/ethernet-static /etc/netctl
# vi /etc/netctl/ethernet-static

Description='A basic static ethernet connection'
Interface=eth0
Connection=ethernet
IP=static
Address=('192.168.1.137/24')
#Routes=('192.168.0.0/24 via 192.168.1.2')
Gateway='192.168.1.1'
DNS=('192.168.1.1')

Disable default settings:

# systemctl disable [email protected]
# systemctl disable dhcpcd
# systemctl disable netctl-ifplugd@eth0

Enable static IP:

# netctl enable ethernet-static

Update system, install some packages may be needed in the future.

# pacman -Syu
# pacman -S rsync vim mkinitcpio

Cross fingers and reboot:

# shutdown -r now

Preparations for root partition encryption

I’ve used the same approach as Pezz suggested: We have two systems, one we had by default which can be used in case of fuckup, and one - encrypted.

Create new partition in unallocated part of SD card:

# fdisk /dev/mmcblk0

Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition type:
   p   primary (1 primary, 1 extended, 2 free)
   l   logical (numbered from 5)
Select (default p): p
Partition number (3,4, default 3): 3
First sector (3667968-61863935, default 3667968): 
Using default value 3667968
Last sector, +sectors or +size{K,M,G} (3667968-61863935, default 61863935): 
Using default value 61863935
Partition 3 of type Linux and of size 27.8 GiB is set
Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)

Reboot RPi so it sees new partition table:

# shutdown -r now

Encrypted partition configuration

Create partition, assign password:

# cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/mmcblk0p3

WARNING!
========
This will overwrite data on /dev/mmcblk0p3 irrevocably.

Are you sure? (Type uppercase yes): YES

Open partition:

# cryptsetup luksOpen /dev/mmcblk0p3 root

Create filesystem:

# mkfs.ext4 /dev/mapper/root

Mount:

# mount /dev/mapper/root /mnt

Copy root filesystem to encrypted partition:

Achtung! /mnt/ should have trailing slash otherwise you’ll have wrong directory tree.

# rsync --progress -axv / /mnt/

Check kernel version:

# uname -a

Linux homepi 3.6.11-16-ARCH+ #1 PREEMPT Tue Aug 20 19:25:48 CDT 2013 armv6l GNU/Linux

Modify /etc/mkinitcpio.conf and make sure there is a string:

HOOKS="base udev autodetect modconf block keyboard encrypt filesystems fsck"

Generate initrd:

Achtung! Please be careful with the part after “-k”, if initrd is generated for other kernel system won’t load. You should re-generate initrd after kernel upgrade. This basically means after each Arch system upgrade since partial updates are dishonored.

# mkinitcpio -k 3.6.11-16-ARCH+ -g /boot/initrd

Modify /boot/config.txt and add to the end:

initramfs initrd 0x00f00000

Modify boot cmdlint file /boot/cmdline.txt:

cryptdevice=/dev/mmcblk0p3:root:allow-discards root=/dev/mapper/root initrd=0x00f00000

Up to you if you want allow-discards or not, your choice.

Be sure to leave the “ro” option there.

Now add the following to fstab, edit /mnt/etc/fstab and ensure:

/dev/mmcblk0p1      /boot       vfat    defaults                    0      0
/dev/mapper/root    /           ext4    defaults,discard,commit=120 0      1

Root partition key-authorized mount configuration

As a key we’ll use secret.txt file in the root directory of flash drive:

Connect flash drive with the file to RPi and get UUID of partition with the file:

# blkid /dev/sda
/dev/sda: LABEL="FLASH_DRIVE" UUID="B714-B30C" TYPE="vfat"

Mount filesystem to get access to the file:

# mount /dev/disk/by-uuid/E614-B25B /mnt

Add file to keys allowed to unlock root partition:

# cryptsetup luksAddKey /dev/mmcblk0p3 /mnt/secret.txt

Unmount:

# umount /mnt

Modify /boot/cmdline.txt by adding

cryptkey=/dev/disk/by-uuid/B714-B30C:vfat:/secret.txt

File should be similar to the following one, option order matters, RPi won’t boot if some options are misplaced:

ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 cryptdevice=/dev/mmcblk0p3:root:allow-discards root=/dev/mapper/root cryptkey=/dev/disk/by-uuid/E614-B25B:vfat:/secret.txt initrd=0x00f00000 rootfstype=ext4 elevator=noop rootwait

Reboot.

Now, if everything is fine, your RPi should automatically mount root partition and boot if it sees key file on the connected drive. Otherwise you will be prompted for a password for encrypted root partition.