1. Purpose of article[edit source]
This article describes how to encrypt a storage block device as a sdcard with the "dm-crypt" tool. The encrypting key is wrapped with the SAES IP in secure world (OP-TEE) with a key derived from the HUK.
2. Pre-requesites[edit source]
You are already familiar with the Yocto build process and OpenSTLinux distribution.
3. Introduction[edit source]
This article describe a process to encrypt dynamically a block device with "dm-crypt", here a sdcard partition. We use the Linux in-kernel key management, to create a "trusted key" key type as block device encrypting key. The "trusted key" is a key generated, seal (encrypt/wrap) & unseal(decrypt/unwrapp) within the secure world (OP-TEE). The wrapping key used to seal&unseal the "trusted key" is a key derived by SAES from an internal SAES secret key HUK. We use AES encryption algorithm with CBC mode or (ESSIV or XTS). Only the AES CBC encryption can be accelerated with the CRYP IP.
4. Architecture overview[edit source]
The Hardware Unique Key (HUK) is hidden to the CPU, only SAES IP can access to it
5. Configuration[edit source]
5.1. Kernel configuration in Developer Package[edit source]
- Go to linux kernel build directory
cd <Linux kernel build directory>
Using menuconfig configure the kernel as follow (see : Menuconfig or how to configure kernel)
5.1.1. To Enable crypto using ST SAES hardware accelerator and AES algorithm[edit source]
- OpenSTLinux 4.x
Cryptographic API--- > -- Hardware crypto devices --- Hardware crypto devices < > Support for Microchip / Atmel ECC hw accelerator < > Support for Microchip / Atmel SHA accelerator and RNG <*> Support for STM32 crc accelerators < > VirtlO crypto driver <*> Support for STM32 crc accelerators <*> Support for STM32 hash accelerators <*> Support for STM32 cryp accelerators {M} SHA384 and SHA512 digest algorithms < > SHA3 digest algorithm < > SM3 digest algorithm < > Streebog Hash Function < > Whirlpool digest algorithms *** Ciphers *** -*- AES cipher algorithms
- OpenSTLinux 5.x
Cryptographic API--- >
-- Hardware crypto devices
--- Hardware crypto devices
<*> Support for STM32 crc accelerators
...
{M} Support for amlogic cryptographic offloader NEW
...
-*- Support for Aspeed cryptographic engine driver
<*> Support for Aspeed Crypto debug messages
<*> Support for Aspeed Hash Crypto Engine HACE hash
<*> Support for Aspeed Hash Crypto Engine HACE crypto
5.1.2. To disable software crypto[edit source]
- OpenSTLinux 4.x
ARM Accelerated Cryptographic Algorithms {M}SHA1 digest algorithm (ARM-asm) <M>SHA1 digest algorithm (ARM NEON) <M>SHA1 digest algorithm (ARM v8 Crypto Extensions) <M>SHA-224/256 digest algorithm (ARM v8 Crypto Extensions) {M}SHA-224/256 digest algorithm (ARM-asm and NEON) <M>SHA-384/512 digest algorithm (ARM-asm and NEON) [ ]BLAKE2s digest algorithm (ARM) < >BLAKE2b digest algorithm (ARM NEON) < >Scalar AES cipher for ARM < >Bit sliced AES using NEON instructions < >Accelerated AES using ARMv8 Crypto Extensions
- OpenSTLinux 5.x
ARM Accelerated Cryptographic Algorithms {M} Hash functions SHA 1 NEW <M> Hash functions SHA 1 neon <M> Hash functions SHA 1 Armv8 crypto extensions <M> Hash functions SHA 224 and SHA 256 Armv8 crypto extensions {M} Hash functions SHA 224 and SHA 256 neon NEW <M> Hash functions SHA 384 and SHA 512 neon < >Ciphers : AES < >Ciphers : AES modes ECB CBC CTR XTS bit sliced NEON < >Ciphers : AES modes ECB CBC CTR XTS bit sliced ARMv8 crypto extension < >Ciphers : Chacha20 xChacha20 xChaCha12 NEON <M> CRC32C CRC32
5.1.3. To enable the support of the device mapper and the crypt function used by dmsetup[edit source]
- OpenSTLinux 4.x
Device Drivers < > Parallel port support ---> -*- Plug and Play support ---> [*] Block devices ---> NVME Support ---> Misc devices ---> SCSI device support ---> <*> Serial ATA and Parallel ATA drivers (libata) ---> [*] Multiple devices driver support (RAID and LVM) --->
- OpenSTLinux 5.x
Device Drivers < > Parallel port support ---> -*- Plug and Play support ---> [*] Block devices ---> NVME Support ---> Misc devices ---> SCSI device support ---> <*> Serial ATA and Parallel ATA drivers (libata) ---> [*] Multiple devices driver support (RAID and LVM) --->
[*] Multiple devices driver support (RAID and LVM) ---> < > RAID support < > Block device as cache <*> Device mapper support [ ] Device mapper debugging support < > Unstriped target <M> Crypt target support
5.1.4. To enable the TEE trusted key[edit source]
- OpenSTLinux 4.x
Security options ---> -*- Enable access key retention support [ ] Enable temporary caching of the last request_key() result [ ] Enable register of persistent per-UID keyrings <M> TRUSTED KEYS <*> ENCRYPTED KEYS
- OpenSTLinux 5.x
Security options ---> -*- Enable access key retention support [ ] Enable temporary caching of the last request_key() result [ ] Enable register of persistent per-UID keyrings <M> TRUSTED KEYS [ ] TPM based trusted keys [ ] TEE based trusted keys NEW <*> ENCRYPTED KEYS
5.1.5. Check on your kernel .config file[edit source]
Check on your .config file at <Linux kernel build directory> that the following flag's value as following
- Check that crypto using ST SAES hardware accelerator and AES algorithm is enabled:
CONFIG_CRYPTO_DEV_STM32_HASH=y CONFIG_CRYPTO_DEV_STM32_CRYP=y CONFIG_CRYPTO_AES=y
- Check that software crypto are disabled:
CONFIG_CRYPTO_AES_ARM=n CONFIG_CRYPTO_AES_ARM_BS=n CONFIG_CRYPTO_AES_ARM_CE=n
- Check that device mapper and crypt function can be used by dmsetup:
CONFIG_MD=y CONFIG_DM_CRYPT=y CONFIG_BLK_DEV_DM=y
- Check that encrypted and trusted key can be used:
- OpenSTLinux 4.x
CONFIG_KEYS=y CONFIG_TRUSTED_KEYS=m CONFIG_ENCRYPTED_KEYS=y
- OpenSTLinux 5.x
CONFIG_KEYS=y
CONFIG_TRUSTED_KEYS=m
CONFIG_ENCRYPTED_KEYS=y
CONFIG_TRUSTED_KEYS_TEE=y
5.1.6. Rebuild and update target[edit source]
Now follow the How to cross-compile with the Developer Package wiki in order to :
- Cross-compile the Linux kernel.
- Cross-compile the Linux kernel modules.
Once you have all this done, you can continue.
- Update the Linux kernel image on board.
- Update the modules on the board.
5.2. Optee OS configuration in Developer Package[edit source]
Optee should have been compiled with "trusted key" TA in CFG_IN_TREE_EARLY_TAS option
- Go to OP-TEE OS source directory
cd <OP-TEE OS source directory>
- Open make file sdk file, and add the line
EXTRA_OEMAKE += "CFG_IN_TREE_EARLY_TAS=trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c"
- Compile OPTEE-OS and flash it to the board: see How to cross-compile with the Developer Package
5.3. Image configuration in Developer Package[edit source]
Install keycontrol utility
- get board connection on internet
- on board :
apt-get install keyutils
Selecting previously unselected package keyutils. (Reading database ... 15652 files and directories currently installed.) Preparing to unpack .../keyutils_1.6.3-r0_armhf.deb ... Unpacking keyutils (1.6.3-r0) ... Setting up keyutils (1.6.3-r0) ...
apt-get install libdevmapper
Selecting previously unselected package libdevmapper. (Reading database ... 15662 files and directories currently installed.) Preparing to unpack .../libdevmapper_2.03.16-r0_armhf.deb ... Unpacking libdevmapper (2.03.16-r0) ... Setting up libdevmapper (2.03.16-r0) ...
apt-get install lvm2
Selecting previously unselected package lvm2-udevrules. (Reading database ... 15665 files and directories currently installed.) Preparing to unpack .../lvm2-udevrules_2.03.16-r0_armhf.deb ... Unpacking lvm2-udevrules (2.03.16-r0) ... Selecting previously unselected package lvm2. Preparing to unpack .../lvm2_2.03.16-r0_armhf.deb ... Unpacking lvm2 (2.03.16-r0) ... Selecting previously unselected package lvm2-scripts. Preparing to unpack .../lvm2-scripts_2.03.16-r0_armhf.deb ... Unpacking lvm2-scripts (2.03.16-r0) ... Setting up lvm2-udevrules (2.03.16-r0) ... Setting up lvm2 (2.03.16-r0) ... Setting up lvm2-scripts (2.03.16-r0) ...
5.4. Configuration in Distribution Package[edit source]
OP-TEE :
optee-os-stm32mp_3.16.0.bbappend
EXTRA_OEMAKE += "CFG_IN_TREE_EARLY_TAS=trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c"
KERNEL (with nenuconfig ???) :
CONFIG_KEYS=y
CONFIG_TRUSTED_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
IMAGE CONTAINS (to add in local.conf):
IMAGE_INSTALL:append= " keyutils "
IMAGE_INSTALL:append= " lvm2 "
5.5. Linux workaround for OpenSTLinux 4.1[edit source]
!!!!!!! A workaround for the "access_ok" issue is needed in OpenSTLinux 4.1.0 (this issue is no more present OpenSTLinux 5.x) linux_xx/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long /*dm-crypt */ /* if (!access_ok((void __user *)addr, length)) return ERR_PTR(-EFAULT);*/
Rebuild the kernel uImage and update the target
6. Process[edit source]
6.1. Encrypted disk creation[edit source]
- Create a secure volume. It could be a physical partition, in this example, make use of an image file and mount it later.
dd if=/dev/zero of=encrypted.img bs=1M count=32
32+0 records in 32+0 records out
losetup /dev/loop0 encrypted.img
loop0: detected capacity change from 0 to 65536
- check the new partition created
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 32M 0 loop mmcblk0 179:0 0 14.8G 0 disk |-mmcblk0p1 179:1 0 256K 0 part |-mmcblk0p2 179:2 0 256K 0 part |-mmcblk0p3 179:3 0 256K 0 part |-mmcblk0p4 179:4 0 256K 0 part |-mmcblk0p5 179:5 0 4M 0 part |-mmcblk0p6 179:6 0 4M 0 part |-mmcblk0p7 179:7 0 512K 0 part |-mmcblk0p8 179:8 0 64M 0 part /boot |-mmcblk0p9 179:9 0 16M 0 part /vendor |-mmcblk0p10 179:10 0 4G 0 part / -mmcblk0p11 179:11 0 10.7G 0 part /usr/local
- Trusted Key creation in keyring session
keyctl add trusted my_key "new 64" @s
Here, this commands generate a new key "my_key" with the OPTEE random generator RNG IP
*** TRACE FROM: trusted_keys/entry.c, function : get_random ***
"my_key" is trusted. Therefore "my_key" is "sealed" (ie encrypted/wrapped) with a derived key from a HUK hidden in SAES IP.
The below traces is the OPTEE Trusted TA source code (added manually), shows the "derived Huk" derivation by SAES IP . The OPTEE SAES huk_subkey_derive function uses the internal SAES HUK and an input constant. Then this "derived Huk" is used to seal "my_key" in an encrypted format.
*** TRACE FROM: trusted_keys/entry.c, function : seal_trusted_key *** M/TC: *** TRACE FROM : stm32_saes.c, function : huk_subkey_derive *** 53139771
- check the key my_key is created. Show the all the keys of the keyring session. Print the a blob containing "my_key" encrypted at creation as seen above (key d 53139771).
keyctl show @s
result: Keyring 989387511 --alswrv 0 0 keyring: _ses 809952222 ----s-rv 0 0 \_ user: invocation_id 53139771 --alswrv 0 0 \_ trusted: my_key
keyctl print 53139771
result: 00334c376ecf6d8e80d7737506eec2456dea0baa119d86cb0aec5643edfe5bbdcdb736e94075fc6f 832731067e3452a16eb40891ee7cdf2133aa6fbce6b1bd8428f2ca9afece90153e84e0c3c1107f66 1ccc53b88f2e2d9dbb21223e9aeacafff2
- save Key blob into a file (file system is located on flash memory).
keyctl pipe 53139771 > my_key.blob
- Using dmsetup, create a new device-mapper device named encrypted, for example, and specify mapping table. The
table can be provided on stdin or as argument.
dmsetup -v create cryp_dev --table "0 $(blockdev --getsz /dev/loop0) crypt aes-xts-plain64 :64:trusted:my_key 0 /dev/loop0 0"
[ 340.644542] cryptd: max_cpu_qlen set to 1000 [ 340.657129] crypto_simd: disagrees about version of symbol module_layout [ 340.708664] aes_arm: disagrees about version of symbol module_layout Name: cryp_dev State: ACTIVE Read Ahead: 256 Tables present: LIVE Open count: 0 Event number: 0 Major, minor: 253, 0 Number of targets: 1
Following is a brief description of the command.
- setting 0 as start value means that the encrypting begins at 0.
- size is the size of the volume in sectors.
- blockdev gets the device's number of sectors.
- target is crypt.
- cipher is set in kernel crypto API format to use tagged key.
- IV is the initialization vector defined to plain64.
- key size is the size of the key.
- key type is the keyring key service type.
- key name is the key description to identify the key to load.
- IV offset is the value to add to sector number to compute the IV value.
- device path is the path to device to be used as backend. It will contain the encrypted data.
- offset value as 0 means that encrypted data begins at sector 0 of the device.
For more information see : https://gitlab.com/cryptsetup/cryptsetup/-/wikis/DMCrypt.
- Let's see the created device.
dmsetup table --showkeys
result: cryp_dev: 0 65536 crypt aes-xts-plain64 :64:trusted:my_key 0 7:0 0
- delete the keys from the keyring session (optional)
keyctl clear @s
- Create a file system on the device
mkfs.ext4 /dev/mapper/cryp_dev
mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 32768 1k blocks and 8192 inodes
Filesystem UUID: c1e3c1db-1a6c-42d6-8e3f-d0641a1f19c1
Superblock backups stored on blocks:
8193, 24577
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
- Setup a mount point.
mkdir /mnt/cryp_dev
- Mount the mapped device.
mount -t ext4 /dev/mapper/cryp_dev /mnt/cryp_dev/
[ 1436.179168] EXT4-fs (dm-0): mounted filesystem with ordered data mode. Opts:.
- check the mountpoint
lsblk
result: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 32M 0 loop `-cryp_dev 253:0 0 32M 0 dm /mnt/cryp_dev mmcblk0 179:0 0 14.8G 0 disk |-mmcblk0p1 179:1 0 256K 0 part |-mmcblk0p2 179:2 0 256K 0 part |-mmcblk0p3 179:3 0 256K 0 part |-mmcblk0p4 179:4 0 256K 0 part |-mmcblk0p5 179:5 0 4M 0 part |-mmcblk0p6 179:6 0 4M 0 part |-mmcblk0p7 179:7 0 512K 0 part |-mmcblk0p8 179:8 0 64M 0 part /boot |-mmcblk0p9 179:9 0 16M 0 part /vendor |-mmcblk0p10 179:10 0 4G 0 part / `-mmcblk0p11 179:11 0 10.7G 0 part /usr/local
- write some data to the device
echo "This is a test of full disk encryption" > /mnt/cryp_dev/readme.txt
sync
6.2. Encrypted disk reload[edit source]
- reboot the board
- reload the trusted key in the keyring session
keyctl add trusted my_key "load `cat my_key.blob`" @s
Here, my_key.blob contains the trusted key "my_key" . This commands unseal (ie decypt) "my_key" with a derived HUK hidden in SAES IP.
By adding the below traces is the OPTEE Trusted TA source code, here is the evidence by this call, that the "derived Huk" is derived by SAES itself (as see above from the internal SAES HUK and from SAES input constant). This "derived Huk" is then used to unseal my_key.blob to retrieve "my_key" in clear text.
*** TRACE FROM: trusted_keys/entry.c, function : unseal_trusted_key *** M/TC: *** TRACE FROM : stm32_saes.c, function : huk_subkey_derive *** 990951249
- redefine with "dmsetup" the logical device.
losetup /dev/loop0 encrypted.img
detected capacity change from 0 to 65536
dmsetup -v create cryp_dev --table "0 $(blockdev --getsz /dev/loop0) crypt aes-xts-plain64 :64:trusted:my_key 0 /dev/loop0 0"
[ 771.864791] cryptd: max_cpu_qlen set to 1000 Name: cryp_dev State: ACTIVE Read Ahead: 256 Tables present: LIVE Open count: 0 Event number: 0 Major, minor: 253, 0 Number of targets: 1
- remount the device
mount -t ext4 /dev/mapper/cryp_dev /mnt/cryp_dev/
[ 1673.451800] EXT4-fs (dm-0): recovery complete [ 1673.466522] EXT4-fs (dm-0): mounted filesystem with ordered data mode. Opts.
- Read from device the data stored.
cat /mnt/cryp_dev/readme.txt
result: This is a test of full disk encryption
7. References[edit source]