Encryption on phones is a hard problem. Several companies and distributions have taken different approaches to this problem.

In Linux there are a few possibilities for encryption. One very popular choice is LUKS. This counts as full-disk encryption. LUKS sits between the disk and the filesystem that's used on the disk (like ext4 or f2fs) and encrypts every single bit in the filesystem.

Another choice is eCryptfs which is also known as the "Encrypt my home directory" option in the Ubuntu installer and derivatives. eCryptfs counts as file level encryption. It doesn't sit between the disk and the filesystem but instead it sits between the files and the filesystem (roughly).

There's a few intermediate options like having multiple partitions and only running FDE on some of them. Or having multiple partitions and only using file encryption on some of them. For systems with a readonly root filesystems like Android or UBports having partial encryption can work. For systems that don't do this adding partial encryption like this has the risk of leaking data to the unencrypted partitions due to caches or fun things like print spoolers that aren't in the home directory, or the classic unencrypted logfiles.

For postmarketOS the choice was made to run LUKS on the full disk and have an unencrypted /boot partition. The unencrypted /boot is required to be able to load the kernel and initramfs since Android bootloaders usually cannot load from encrypted partitions and the non-android devices either don't support LUKS or don't have any way of entering data in the bootloader phase. The risk of having /boot unencrypted is not super high for data leakage since no logging or caching is normally happening to /boot.

LUKS encryption keys

The encryption in LUKS works in two steps. There's the LUKS header and the LUKS data. The LUKS header contains the master key for decrypting the LUKS data. The header is then encrypted again with whatever security mechanism is used for unlocking like the passphrase.

One big security issue can happen if the master key is re-used. If the passphrase for a LUKS container is changed the header will be decrypted using the old key and re-encrypted with the new key. The thing that won't change is the master key that's used for actually encrypting the data.

The LUKS documentation has several warnings for this:

LUKS PASSPHRASE IS NOT THE MASTER KEY: The LUKS passphrase is not used in deriving the master key. It is used in decrypting a master key that is randomly selected on header creation. This means that if you create a new LUKS header on top of an old one with exactly the same parameters and exactly the same passphrase as the old one, it will still have a different master key and your data will be permanently lost.


CLONING/IMAGING: If you clone or image a LUKS container, you make a copy of the LUKS header and the master key will stay the same! That means that if you distribute an image to several machines, the same master key will be used on all of them, regardless of whether you change the passphrases. Do NOT do this! If you do, a root-user on any of the machines with a mapped (decrypted) container or a passphrase on that machine can decrypt all other copies, breaking security. See also Item 6.15.

This is the reason why none of the pre-generated downloadable postmarketOS images have disk encryption. Distributing an image with LUKS in it will basically be distributing the private key for the disk encryption.

The fix in postmarketOS

The first fix for this issue in postmarketOS was just not distributing pre-generated images. The only way to get a postmarketOS installation with LUKS was by generating the image yourself using the pmbootstrap tool. This would generate the normal postmarketOS rootfs and then run cryptsetup to create a LUKS container in the final image file or SD card. Then after the user had provided the passphrase 3 times, two times while formatting using cryptsetup and once to unlock it after, the data would be copied into that encrypted container. The master key is generated when cryptsetup is initially ran and this ensures everyone has a secret and unique master key.

Making everyone use pmbootstrap directly didn't scale perfectly though. Especially since the release of the postmarketOS community edition of the PinePhone which had to have a pre-generated image. To fix this the postmarketOS ondev installer was added.

The ondev installer is a postmarketOS pre-generated image that runs the calamares installer on boot. The image also contains an unencrypted postmarketOS installation image which contains the rootfs that will be finally installed. This can contain a Phosh or Plasma Mobile postmarketOS image for example.

When you select disk encryption in the installer the installer will then run cryptsetup against the target partition and create a new LUKS container with the unique master key and then copy the contents of the embedded image into that, much like pmbootstrap would do when installing from a computer. This fixes the unique key problem for the pre-generated image usecase and also has the benefit that the installer lets end users customize a few more things on first run.

Installing in-place

The last hard hurdle for having the secure installer is dealing with installing in-place. For the PinePhone this could be conveniently ignored initially since it's possible to boot the installer image from the SD card and then format and install the internal storage. The harder install path is booting from the SD and also installing to the SD. Or the PinePhone factory image usecase that has the installer flashed to the eMMC and also lets the people receiving the phone install to eMMC.

The way in-place installation can be visualized perfectly with this image from @ollieparanoid from the wiki:

There's a gap between the boot partition and the rootfs for the installer image. While generating the image pmbootstrap will make sure the gap between the boot and installer partition is large enough to fit the final operating system.

If you choose to install in-place in the installer then calamaris will format p2 on the disk with either LUKS or ext4 depending on user choice and then copy the final rootfs into that formatted partition.

The second half of that installation is actually integrated in the postmarketOS initramfs. The partition label for the installer rootfs is pmOS_install and for a normal postmarketOS installation it would be pmOS_root. If the install label exists the initramfs loaded from /boot will refer that over the normal root partition and mount/boot that . At the end of the installation process the pmOS_install partition will be renamed into pmOS_deleteme which will make the initramfs delete that partition on boot instead. Now there's just a boot and root partition as the first 2 partitions on the disk and the normal booting process will take over.

The normal booting process will notice the unallocated space after the rootfs and will expand the rootfs to the maximum possible size before mounting it and booting it. At this point the postmarketOS image is fully installed and optionally encrypted without ever having a pre-generated key distributed.