Skip to content

Automatic Unlock Encrypted Disk Using LUKS ​

Unlocking LUKS2 volumes with TPM2, FIDO2, PKCS#11 Security Hardware on systemd 248 @ref: https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html > A very good and simple way to encrypt LUKS

WARNING

Only systemd version 248 and above has native support to unlock disks, as per

With the upcoming systemd v248 the systemd-cryptsetup component of systemd (which is responsible for assembling encrypted volumes during boot) gained direct support for unlocking encrypted storage with three types of security hardware:

Unlocking with FIDO2 security tokens (well, at least with those which implement the hmac-secret extension; most do). i.e. your YubiKeys (series 5 and above), Nitrokey FIDO2, AuthenTrend ATKey.Pro and such.

Unlocking with TPM2 security chips (pretty ubiquitous on non-budget PCs/laptops/â€Ļ)

Unlocking with PKCS#11 security tokens, i.e. your smartcards and older YubiKeys (the ones that implement PIV). (Strictly speaking this was supported on older systemd already, but was a lot more "manual".)

TIP

The command systemd-cryptenroll is only available on Ubuntu 21.10 onwards.

Resize Existing LVM rootfs ​

Use this if there is existing lvm with rootfs

# resize existing rootfs
lvresize -L -50G ubuntu-vg/ubuntu-lv

# create a new lv with the freed space
lvcreate -L 50G -n rootfs ubuntu-vg

# create new ext4 file system. Can check the [LV Path] using lvdisplay
mkfs.ext4 /dev/ubuntu-vg/rootfs

# create mountpoint
mkdir /mnt/rootfs

# mount the newly created lv named rootfs
mount /dev/ubuntu-vg/rootfs /mnt/rootfs

test create ​

DISK_DEV="/dev/loop0"

TPM_NVRAM_ADDR=0x81010023
LUKS_KEY_SLOT=1 # from 0 to 7
TPM_SEAL_PCR="sha256:0" # pcrbank:pcrvalue

# Create test file
dd if=/dev/zero of=enc.disk bs=1M count=10
dd if=/dev/urandom of=disk.key bs=1 count=32

# create loopback device
loopdevice=$(losetup -f) && sudo losetup $loopdevice enc.disk

echo -n "Unsealing TPM2 NVRAM with PCR... "
# initialize a TPM session
tpm2_startauthsession --policy-session -S session.ctx 

# Generates a PCR policy event with the TPM.
tpm2_policypcr -Q -S session.ctx -l $TPM_SEAL_PCR

tpm2_unseal -p session:session.ctx -c $TPM_NVRAM_ADDR > /tmp/disk.key

sudo cryptsetup luksFormat --key-file=/tmp/disk.key $loopdevice

# open luks, this will mount to /dev/mapper/enc_volume
sudo cryptsetup luksOpen --key-file=/tmp/disk.key $loopdevice enc_volume

# format file system
sudo mkfs.ext4 -j /dev/mapper/enc_volume

# finally mount
sudo mkdir /mnt/enc_volume
sudo mount /dev/mapper/enc_volume /mnt/enc_volume

Method 1: Manual ​

@ref: https://tpm2-software.github.io/2020/04/13/Disk-Encryption.html

Create a random key and save it persistent to TPM NVRAM.

TPM_NVRAM_ADDR=0x81010023
# Creating and persisting a sealing object and sealing a random byte sequence as the disk key.
tpm2_createprimary -Q -C o -c prim.ctx
dd if=/dev/urandom bs=1 count=32 status=none | tpm2_create -Q -g sha256 -u seal.pub -r seal.priv -i- -C prim.ctx
tpm2_load -Q -C prim.ctx -u seal.pub -r seal.priv -n seal.name -c seal.ctx
tpm2_evictcontrol -C o -c seal.ctx $TPM_NVRAM_ADDR

Setup loop device for the partition

loopdevice=$(losetup -f) 
losetup $loopdevice /dev/mapper/ubuntu--vg-ubuntu--lv

# Pipe the sealed key from TPM and save it as a luks keyslot 0 in the partitionl
tpm2_unseal -Q -c 0x81010023 | cryptsetup luksFormat --key-file=- $loopdevice

Dump the info. Note that we are using LUKS2, and it allow up to 8 slots, allow key rotation.

cryptsetup luksDump $loopdevice
LUKS header information for /dev/loop3

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      6b b6 6f 0d 98 3f e4 2b 6c 9e e5 58 3f 41 35 ab c7 05 aa e3
MK salt:        06 cf e0 12 51 74 2d b7 23 a7 7c 2b 22 84 78 53
                84 7d f5 17 a1 e9 d8 2b 46 b6 1a 54 24 54 5f 72
MK iterations:  159454
UUID:           c002ae7c-f65e-48d8-979a-7696974fffb5

Key Slot 0: ENABLED
        Iterations:             2551278
        Salt:                   b4 59 b6 99 a9 99 31 6d eb f0 d8 c0 c9 b0 6d 85
                                6d f7 6d fe f0 9d bc ae ba 6a 98 60 20 4b 8c 47
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Scenario 2: Existing LUKS crypt ​

Before adding luks key

cryptsetup luksDump /dev/sda3
LUKS header information for /dev/sda3

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      01 9b 6f b7 18 9e ad 3c 28 f4 12 16 a3 f1 5a b0 a5 7d ab ae
MK salt:        20 d6 38 03 dd e1 10 40 1b 55 cc a2 a7 42 50 a9
                62 22 08 88 da a5 30 18 d8 70 dc b0 a3 55 b8 84
MK iterations:  159649
UUID:           d00093b4-305c-45f1-946e-cd9b2e8203ab

Key Slot 0: ENABLED
        Iterations:             2554386
        Salt:                   cd a2 aa 2d b1 d4 a8 b8 6d 56 9f 22 23 ad f7 72
                                5c 2a bc 31 11 5a 86 3a f5 26 d3 db 52 b7 41 be
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

After adding luks Key

TPM_NVRAM_ADDR=0x81010023
DISK_DEV=/dev/sda3
tpm2_unseal -Q -c $TPM_NVRAM_ADDR | sudo cryptsetup luksAddKey $DISK_DEV -

Appendix ​

Dump LUKS info

cryptsetup luksDump /dev/sda3

It will return nothing if not setup yet