Authenticated and Encrypted Storage on Embedded Linux - Jan Lübbe, Pengutronix e.K. [Open Source Summit EU 2019]

The Linux storage stack has block devices and device mapper, and mtd devices and UBI. To make it usable from userspace there is filesystems and VFS. Encryption and authentication (transparent to applications) can be inserted at various places.

Many different ones exist: ecryptfs, fscrypt, fsverity, IMA/EVM, UBI auth, dm-crypt, dm-verity, dm-integrity.

Important terms in this talk:

  • hash functions: one-way function with fixed output size
  • HMAC: hash-based message authentication code: combination of hash and shared secret, to verify that the data comes from a trusted source and has not been tampered with
  • signature: authentication based on asymmetric (public key) cryptography. Signature is created with private key, can be verified with public key. Can be used when you need to autheticate for multiple receivers.
  • Unauthenticated encryption: attacker cannot read private data, but can modify it. Modified data may be wrong, but nothing tells you if it has been modified.
  • Authenticated encryption: if data is modified, receiver will detect it. AES-AEAD

dm-verity exists since 2012, v3.4. It authenticates the data on the block device. Adds a tree of hashes to the block data. Blocks of hashes are hashed again, until you arrive at the root hash. The root hash is provided out-of-band, i.e. not stored on the filesystem. Alternatively (since 5.4) it can be signed and included in the superblock. Blocks can be verified incrementally while reading each block. This is what is used by Android and ChromeOS. veritysetup is part of LUKS2. Can be used with ext4, EROFS. Suitable for readonly filesystems.

dm-integrity exists since 2017, v4.12. Adds authenticated data to each N data blocks. This actually comes from the storage industry, T10, where disks were organised in this way. For writeable data, if the integrity data has not been written yet when a reboot happens, you loose data. Therefore, there’s also a journal for the integrity data. That gives a serious performance penalty.

dm-crypt is used with cryptsetup. Block-based encryption. Recently experimental support for online reencryption has been added. Does not authenticate because it doesn’t take additional space, and you need additional space for authentication. This is the best choice for RW block devices if authentication is not needed.

It is possibly to layer dm-crypt on top of dm-integrity. Then dm-crypt can use the extra space used by dm-integrity to add authentication. However, it is sector-based, so it is not possible to verify the integrity compared to other blocks, so it is possible for an attacker to inject an older version of that block (replay attack) and it looks correct.

fsverity, since 2019, v5.4, is like dm-verity but at a file level. It allows efficient verification of large read-only files via a hash tree, and combine different read-only files into a read-write filesystem. Android uses this to verify apps. The root hash is provided out-of-band. It is integrated in ext4.

fscrypt is the same idea but for encryption. Since 2015 for ext4, generalized in 2016, v4.6; UBIFS since 2017, v4.10. Different users can use different keys and only access their own files. It is also possible to remove directories without the corresponding key (e.g. to delete a user). Like dm-crypt, it has no authentication. It’s an alternative for dm-crypt on multi-user systems.

UBIFS authentication was added in 2018, v4.20. Because UBIFS is copy-on-write, it is easy to add hashes. It is “wandering tree” so it is also easy to add hashes at every level of the tree. The root hash is stored in the superblock and authenticated with HMAC, or since v5.3 with a signature (so the same image can be deployed to different devices). It is the only fs-level system with authenticates the metadata in addition to data.

ecryptfs is a stacked filesystem that encrypts individual files, but it is deprecated in favour of dm-crypt or fscrypt. Userspace tools are not really maintained.

IMA/EVM is somewhat related. It also stores it metadata in attributes in the filesystem. It is used for remote attestation with a TPM module. It makes hashes of each file and sends these to the TPM for attestation. However this can only be used for remote attestation, not for authentication. EVM can be layered on top of it to actually have authentication. However, this cannot protect agains directory modification, only against file modification.

For all of these, the problem is where to store the key. For embedded, there’s no user to type a password. Many SoCs have a method to write a secret key in the device itself; this can be combined with a per-device generated key to generate the root key. But that is only useful if it is combined with secure boot. Alternatives are OP-TEE or a TPM.

Authenticated writeable storage doesn’t protect against online attacks: while running, the attacker implicitly has access to the keys and can write authenticated data. So there is a need for at least a readonly recovery partition to restore the factory state in case intrusion is detected.

Authenticated storage is a problem for debugging of devices that come back from the field. To make that possible, you need to implement an authenticated method to first erase the keys for private data, and then disable the verified boot.

For read-write block devices, use dm-crypt and dm-integrity if you can take the performance hit. For read-only, use dm-verity. Use UBIFS authentication for NAND.