Full-Disk-Encryption

Hi all,

I recently ordered a ODROID N2 and set up CoreELEC with it. I’m quite impressed, I only used Kodi on a FTV Stick before and it was always a bit slow etc, great job guys.

Since years, I have the habit of using a full disk encryption (via dm-crypt and luks) on all the devices I use, so I wanted to bring this to CoreELEC. There are various ideas floating around my head how to actually do this (including authentication servers, smcart cards, etc.), but I want to start with the simplest: prompt me for a password on bootup to unlock the SD card (or a second partition) - obviously this is not really user friendly, but should me get going with the boot procedure etc.

In the end, as much of the system as possible should be encrypted, with only the necessary parts for booting staying in clear text. I plan to actually unlock the boot through ssh or from my phone in the end, but this is still a bit unclear.

Where can I find information about how CoreELEC (especially on the ODROID N2) boots and how the startup can be modified? Which git repos are used to build the complete image including uboot?

I imagine the boot process of the N2 to be something like this:

  • first stage bootloader from ROM: search uboot in emmc / microsd / usb -> run uboot
  • uboot: do some stuff (what exactly?), mount rootfs -> run kernel
  • regular system startup

Is there something like initramfs in CoreELEC (this is where luks is usually integrated in regular systems) or does everything happen in uboot and then boot directly into the system? If the latter, then everything related to decryption of the rootfs must be done in uboot directly.

As you see, I’m a bit lost here, but maybe you guys can give me a few pointers in the right direction and point me to the relevant github repos. @Ray I’m pinging you here since you were quite active in the N2 nightlies thread and I assume you know how this might be achieved the easiest.

EDIT: another idea, that’s probably way easier to achieve, is to leave /flash and /storage/.config unencrypted and put the decryption script into a systemd service that starts before kodi.service. Then all userdata could be mounted before kodi starts and be symlinked into /storage/.kodi etc. The raw system would then be readable but should only reveal the contents of /flash and /storage/.config, which should not contain any privacy related data I guess.

I am a huge luks fan myself. There should be no problem to include the cipher modules etc and build cryptsetup. Unlock an external disk through ssh should be possible too.

For full disk it would be harder. Our SYSTEM KERNEL is read only and known. No point encrypting it! The only thing you could encrypt is /storage. It is not implemented right now.

I already installed cryptsetup through opkg and could unlock my drive over ssh, so it looks like the kernel already includes all the modules etc.
Yes, I’ll probably go for encrypting only /storage or maybe even leave /storage/.config unencrypted and only encrypt the remaining stuff on a separate partition and mount it as overlay or something.

Is there any documentation on how to plug something like this into CoreELEC or can you give me some other tips? Otherwise I’d start with putting things into a systemd service that gets started from .config and see how things go from there.

btw are there some docs what exactly is in the files on /flash? E.g. what is included in the SYSTEM and dtb.img files, rest should be obvious (only kernel, logos and boot configuration files).

SYSTEM is the / read only squashfs.
The boot init is here:

Nice, so the init script already provides hooks for mounting /storage.

My current plan is to:

  • leave /flash unencrypted, it contains only the public system files
  • add a mount-storage.sh script that fetches the key from a remote device and mounts the encrypted partition through cryptsetup

This seems to be pretty straight-forward actually. I have the following questions left:

  1. Would CoreELEC consider adding the necessary modules for cryptsetup to the official image? I’d rather not maintain a custom image, since keeping it up to date with each CoreELEC release would require manual work regularly.
  2. What network features are available in init? Is TCP available or only UDP? If tcp, is HTTPS supported for transferring the key from another device?

1.) Yes we can review and consider it.
2.) I don’t think there is any network in init. Network is done with connman.
But busybox should support networking with ethernet.
I don’t see a huge security improvement when you have to download the key from a remote server.

  1. Awesome.
  2. I think there should be some network available, since you can also mount NFS shares from there.

Yes the key exchange is actually the most critical thing. For my use case, this will be a non-issue since I have a custom storage device that uses a challenge-response mechanism and I will use my phone to unlock it (and actually just grab a luks keyfile from it to then finally mount /storage). This is obviously a highly customized flow, so for a regular use case we would have to capture a passphrase/keyfile through a remote connection anyways. Depending on how smart the remote is, the transfer can be encrypted with a preshared key, but then you don’t have much gained compared to having the LUKS keyfile stored locally directly.

Unfortunately I think unlocking a LUKS device is highly use-case specific and hugely depends on the available infrastructure and needs. You could also just put a keyfile on a USB drive and connect it before booting CoreELEC and then simply take it with you to make the device only bootable if you are present. To summarize, I think the actual way about how the drive is mounted must be modified by the user and will default to just requiring a passphrase that must be input through the keyboard. One improvement could be to allow entering the passphrase through ssh (I’ve used this approach using dropbear in the past and it works quite nicely, but I don’t know how easy it is to integrate this into CoreELEC).

I see. One way would be to allow user scripts in initramfs. Then an advaced user can setup a custom unlock procedure.
Your remote unlock by phone solution sounds awesome btw.
I’m happy to include such features if they are practical.

There is already possible to run script /flash/post-flash.sh after /flash is mounted.

1 Like

I’ll try to set up a little demo during the next weeks with three goals:

  1. typing the passphrase through a connected keyboard
  2. using a keyfile from a connected USB drive
  3. send UDP packets to another IP on the same network and query the keyfile from there (with the other device being an Android phone that stores the keyfile encrypted using Android’s KeyStore and requiring user consent to send the keyfile)

If someone has further ideas or tips (e.g. how to integrate dropbear) I’m all ears.

Temporary mount SYSTEM file and start sshd from there. After everything is done unmount it and “normal” boot continues. I used such approach in the past.

This sounds nice. Is there a writeup somewhere how this can be done?

@Ray I started to work on this today, but unfortunately I’m stuck early on.

I added ip=dhcp to my kernel arguments to have network when running the init script. However, the busybox binary of the initramfs does not include anything like wget or curl to send HTTP requests. Also, cryptsetup is missing.

So my general issue is: how can I build a custom initramfs that includes (or builds) some binaries so that they are available when running the post-flash.sh script?
I’ve checked out the coreelec repo, but I’m a bit lost at how to actually modify what gets included in the initramfs.

Look how it is done here https://github.com/LibreELEC/LibreELEC.tv/blob/master/packages/sysutils/busybox/scripts/init#L341

You need to mount SYSTEM file, use some binary from there and at the end unmount it. I don’t think you need to have same binaries in initramfs too.

Thanks, this worked for simple binaries like wget (through busybox), but complex things like cryptsetup did not work, because they link to so many shared libraries that are not available at the right locations.

I installed cryptsetup through opkg on my running system and can use cryptsetup from there, but not in initramfs (because of missing libraries obviously). Is it even possible to use all the cryptsetup features (like devicemapper) in initramfs and correctly bringing this over to the running system afterwards? How would I properly locate the needed libraries (ldd cryptsetup prints ‘not a dynamic executable’ somehow) and make them available in initramfs? I guess I’d have to mount /lib and /usr/lib and copy all required libraries there.

I think you don’t need to do all of it in initramfs. Root fs is read only and there is nothing special to hide. We would have to add cryptsetup and crypto modules to the image and kernel.

Rootfs is not the problem, but as soon as systemd starts up, also /storage/.config/systemd needs to be available, which means /storage must be there (more or less).

I tried not doing it in initramfs, but this adds quite a bit of complexity on its own, because of systemd, so now I’m not sure anymore if it’s easier to get cryptsetup working in initramfs or if it’s easier to detangle the dependencies in /storage to let parts of it stay readable and mount the remaining things afterwards. This could cause sensitive information to leak into the unprotected areas though.

Yeah I am sure we can use cryptsetup from system for this. Otherwise we will still be able to make it into initramfs cause other Distro’s have it too.

Well, I’ve now compiled cryptsetup and its dependencies and can successfully execute the binary in initramfs :slight_smile:

BUT, now I get an error from cryptsetup when unlocking a drive that dm_mod kernel module is not loaded. Can you guys give me a hint how to include kernel modules in initramfs?

linux.conf You need to include the modules