How to encrypt an ODROID-C1’s Ubuntu root filesystem with DM-crypt LUKS

The starting point is a running ORDOID-C1 with the Ubuntu minimal image. Make sure the Ubuntu installation has been dist-upgraded and to use the latest linux-image-c1 kernel image available (3.10.72-78 as of this writing). The ODROID-C1 has to be running the lastest kernel available, check with uname -r. Some of the early Ubuntu minimal images may suffer from a dist-upgrade problem, see here how to fix it. I’m using an 8 GB eMMC card but if you change the /dev ids throughout the installation process, it may work with an SD-card too.

root@c1:/# apt-get -y install lvm2 cryptsetup parted nano rsync

Since we can’t convert a running root partition, we’re going to add a 3rd partition which will be our encrypted root filesystem. Check with parted -l where the 2nd partition ends because we’re going to add the new partition right there.

root@c1:~# parted -l
Model: MMC 008G92 (sd/mmc)
Disk /dev/mmcblk0: 7818MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 1049kB 135MB 134MB primary fat16 lba
2 135MB 4295MB 4160MB primary ext4

In this case, the 2nd partition ends at 4295MB, which will be the starting value for the new partition.

root@c1:~# parted
(parted) mkpart primary ext4
Start? 4295MB
END? 100%
q

Now we’re going to tag the new partition for LVM:
root@c1:~# fdisk /dev/mmcblk0
Command (m for help): t
Partition number (1-4): 3
Hex code (type L to list codes): 8e

Command (m for help): w

The next step is to setup LVM and to encrypt our new root partition. I’m going to name the physical volume (PV) lvm, the volume group vg and the logical root volume root.

root@c1:~# cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/mmcblk0p3
root@c1:~# cryptsetup luksOpen /dev/mmcblk0p3 lvm
root@c1:~# pvcreate /dev/mapper/lvm
root@c1:~# vgcreate vg /dev/mapper/lvm
root@c1:~# lvcreate -l 100%FREE -n root vg
root@c1:~# mkfs.ext4 /dev/mapper/vg-root

Let’s try to mount the new, encrypted root volume:

root@c1:~# mount /dev/mapper/vg-root /mnt

Copy the existing root volume to the new, enrypted root volume:

root@c1:~# rsync -av --exclude=/media --exclude=/mnt --exclude=/proc --exclude=/dev --exclude=/sys / /mnt

These are the commands to chroot our new root volume from the old root partition. You can always use them to gain access to the encrypted root volume from the old root partition.

mkdir -p /mnt/dev
mkdir -p /mnt/mnt
mkdir -p /mnt/proc
mkdir -p /mnt/sys
mkdir -p /mnt/media
cryptsetup luksOpen /dev/mmcblk0p3 lvm
mount /dev/mapper/vg-root /mnt
mount -o rbind /dev /mnt/dev
mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -t vfat /dev/mmcblk0p1 /mnt/media
chroot /mnt

The following actions take place in the chrooted environment on the new, encrypted root LV. Make sure you don’t modify the existing root partition!

Register the encrypted volume in /etc/crypttab:

echo lvm UUID=$(cryptsetup luksUUID /dev/mmcblk0p3) none luks|tee /etc/crypttab

Add a line in /etc/fstab for the root volume:

/dev/mapper/vg-root / ext4 errors=remount-ro 0 1

Being chrooted to the encrypted volume, we can now regenerate the initrd.img using

root@c1:~# update-initramfs -u -k $(uname -r)

Since support for dm-crypt has already been built into the kernel of the minimal image, we don’t have to add any crypto-modules to /etc/initramfs-tools/modules/. initramfs also does a pretty good job (thanks to the MODULES=most setting) determining what to add for lvm and dm-crypt support. Just to make sure, let’s have a look what has been placed into the new initrd.img:

root@c1:~# lsinitramfs /boot/initrd.img-$(uname -r) | grep crypt
sbin/cryptsetup
conf/conf.d/cryptroot
scripts/local-top/cryptopensc
scripts/local-top/cryptroot
scripts/local-bottom/cryptopensc
lib/libcryptsetup.so.4
lib/modules/3.10.72-78/kernel/arch/arm/crypto
lib/modules/3.10.72-78/kernel/arch/arm/crypto/aes-arm.ko
lib/modules/3.10.72-78/kernel/crypto
lib/modules/3.10.72-78/kernel/crypto/rmd160.ko
lib/modules/3.10.72-78/kernel/crypto/seed.ko
lib/modules/3.10.72-78/kernel/crypto/michael_mic.ko
lib/modules/3.10.72-78/kernel/crypto/rmd320.ko
lib/modules/3.10.72-78/kernel/crypto/cast6_generic.ko
lib/modules/3.10.72-78/kernel/crypto/rmd128.ko
lib/modules/3.10.72-78/kernel/crypto/rmd256.ko
lib/modules/3.10.72-78/kernel/crypto/lzo.ko
lib/modules/3.10.72-78/kernel/crypto/blowfish_generic.ko
lib/modules/3.10.72-78/kernel/crypto/khazad.ko
lib/modules/3.10.72-78/kernel/crypto/serpent_generic.ko
lib/modules/3.10.72-78/kernel/crypto/fcrypt.ko
lib/modules/3.10.72-78/kernel/crypto/camellia_generic.ko
lib/modules/3.10.72-78/kernel/crypto/twofish_generic.ko
lib/modules/3.10.72-78/kernel/crypto/async_tx
lib/modules/3.10.72-78/kernel/crypto/async_tx/async_tx.ko
lib/modules/3.10.72-78/kernel/crypto/async_tx/async_pq.ko
lib/modules/3.10.72-78/kernel/crypto/async_tx/async_raid6_recov.ko
lib/modules/3.10.72-78/kernel/crypto/async_tx/async_xor.ko
lib/modules/3.10.72-78/kernel/crypto/async_tx/async_memcpy.ko
lib/modules/3.10.72-78/kernel/crypto/cast5_generic.ko
lib/modules/3.10.72-78/kernel/crypto/tea.ko
lib/modules/3.10.72-78/kernel/crypto/xts.ko
lib/modules/3.10.72-78/kernel/crypto/xor.ko
lib/modules/3.10.72-78/kernel/crypto/ansi_cprng.ko
lib/modules/3.10.72-78/kernel/crypto/wp512.ko
lib/modules/3.10.72-78/kernel/crypto/cast_common.ko
lib/modules/3.10.72-78/kernel/crypto/tgr192.ko
lib/modules/3.10.72-78/kernel/crypto/zlib.ko
lib/modules/3.10.72-78/kernel/crypto/lrw.ko
lib/modules/3.10.72-78/kernel/crypto/anubis.ko
lib/modules/3.10.72-78/kernel/crypto/blowfish_common.ko
lib/modules/3.10.72-78/kernel/crypto/sha512_generic.ko
lib/modules/3.10.72-78/kernel/crypto/twofish_common.ko
lib/modules/3.10.72-78/kernel/crypto/salsa20_generic.ko
lib/modules/3.10.72-78/kernel/crypto/gf128mul.ko
lib/cryptsetup
lib/cryptsetup/askpass
lib/arm-linux-gnueabihf/libgcrypt.so.11

Looking good, the scripts/local-top/cryptroot script is now part of initrd.img. It will be called during the first phase of the Linux boot and ask for the root volume passphrase once initramfs is executed.

To update the uInitrd file in the FAT32 boot partition we first have to recreate the image using the new initrd.img containing lvm and crypto support:

root@c1:~# mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n "uInitrd $(uname -r)" -d /boot/initrd.img-$(uname -r) /tmp/uInitrd-$(uname -r)

If everything went well, copy the uInitrd to /boot and /media:

root@c1:~# cp /tmp/uInitrd-$(uname -r) /boot
root@c1:~# cp /tmp/uInitrd-$(uname -r) /media/uInitrd

Edit /media/boot.ini (make a backup copy first) and replace the root UUID and add cryptdevice in the setenv booargs line:

# Boot Arguments
setenv bootargs "root=/dev/mapper/vg-root cryptdevice=/dev/mmcblk0p3:lvm ...and so on

Important: leave the rest of the setenv bootargs line intact!

That’s it.

root@c1:~# shutdown -r now

initramfs should now aks for the passphrase to decrypt the root volume during boot. Make sure to have a keyboard nearby ;-)

3 thoughts on “How to encrypt an ODROID-C1’s Ubuntu root filesystem with DM-crypt LUKS

  1. This also works on the Odroid C2! You just have to use -A arm64 with the mkimage command! Thanks for this great tutorial!

  2. Line: mount -t vfat /dev/mmcblk0p1 /mnt/media is correct? I can’t update initramfs, because /boot is empty, so maybe mount -t vfat /dev/mmcblk0p1 /boot?

Comments are closed.