In this blog post I will show how LUKS works perfect with FIDO2 devices. You can learn how to setup a LUKS device and then switch from password to a FIDO2 device. This ensures, that not only a password is required but also a hardware device (security factors “Knowledge: Something you know” and “Possession: Something you have”).
Test environment setup
First we will setup a small test environment. Let’s create a small new (virtual) disk.
1$ dd if=/dev/zero of=test.img bs=1M count=20
220+0 records in
320+0 records out
420971520 bytes (21 MB, 20 MiB) copied, 0.01 s, 1.2 GB/s
5
6$ cryptsetup luksFormat ./test.img
7
8WARNING!
9========
10This will overwrite data on ./test.img irrevocably.
11
12Are you sure? (Type 'yes' in capital letters): YES
13Enter passphrase for ./test.img:
14Verify passphrase:
15
16$ cryptsetup luksDump ./test.img
17LUKS header information
18Version: 2
19Epoch: 3
20Metadata area: 16384 [bytes]
21Keyslots area: 16744448 [bytes]
22UUID: bedfd819-a0e9-43dd-a5c5-29e3c7679a65
23Label: (no label)
24Subsystem: (no subsystem)
25Flags: (no flags)
26
27Data segments:
28 0: crypt
29 offset: 16777216 [bytes]
30 length: (whole device)
31 cipher: aes-xts-plain64
32 sector: 4096 [bytes]
33
34Keyslots:
35 0: luks2
36 Key: 512 bits
37 Priority: normal
38 Cipher: aes-xts-plain64
39 Cipher key: 512 bits
40 PBKDF: argon2id
41 Time cost: 7
42 Memory: 1048576
43 Threads: 4
44 Salt: 6d 1e 78 1c f5 c1 30 06 06 03 21 a2 ad 94 fd 31
45 b1 b6 c3 8e 70 5a c4 14 36 cb 4b 6e 52 28 ff 84
46 AF stripes: 4000
47 AF hash: sha256
48 Area offset:32768 [bytes]
49 Area length:258048 [bytes]
50 Digest ID: 0
51Tokens:
52Digests:
53 0: pbkdf2
54 Hash: sha256
55 Iterations: 589750
56 Salt: bd 77 84 53 6b cd 48 13 23 5d 09 fa 59 5d d3 5f
57 72 ad 6e b7 93 57 a8 e8 ca 5d ab b2 0a 56 55 1d
58 Digest: 78 fc 99 e1 fe c5 63 99 1f c0 14 4f f9 fb ca 53
59 c6 df 40 7b 4d 99 fa 01 a7 cb 5a 95 f6 b6 3e 84
Let’s now setup the FIDO device. For this we need a Yubikey (should also work with other devices which are FIDO compliant). The FIDO device should have set a pin to ensure the security factor possession.
1$ ykman fido info
2AAGUID: 00000000-0000-0000-0000-000000000000
3PIN: Not set
4Minimum PIN length: 4
5
6$ ykman fido access change-pin
7Enter your new PIN:
8Repeat for confirmation:
9FIDO PIN updated.
10
11$ ykman fido info
12AAGUID: 00000000-0000-0000-0000-000000000000
13PIN: 8 attempt(s) remaining
14Minimum PIN length: 4
Now we have a small disk and the Yubikey FIDO device is configured.
Change LUKS to FIDO
Let’s now add a FIDO secret to the LUKS device. This requires the FIDO password and after the password you have to touch the FIDO device twice.
1$ sudo systemd-cryptenroll --fido2-device=auto test.img
2🔐 Please enter current passphrase for disk ./test.img: ••••••••••••••••••••••••
3Initializing FIDO2 credential on security token.
4👆 (Hint: This might require confirmation of user presence on security token.)
5🔐 Please enter security token PIN: ••••••••••••••••••••••••
6Generating secret key on FIDO2 security token.
7👆 In order to allow secret key generation, please confirm presence on security token.
8New FIDO2 token enrolled as key slot 1.
Let’s have a look what is in the LUKS header now.
1sudo systemd-cryptenroll ./test.img
2SLOT TYPE
3 0 password
4 1 fido2
5
6$ cryptsetup luksDump ./test.img
7LUKS header information
8Version: 2
9Epoch: 8
10Metadata area: 16384 [bytes]
11Keyslots area: 16744448 [bytes]
12UUID: 00000000-0000-0000-0000-000000000000
13Label: (no label)
14Subsystem: (no subsystem)
15Flags: (no flags)
16
17Data segments:
18 0: crypt
19 offset: 16777216 [bytes]
20 length: (whole device)
21 cipher: aes-xts-plain64
22 sector: 4096 [bytes]
23
24Keyslots:
25 0: luks2
26 Key: 512 bits
27 Priority: normal
28 Cipher: aes-xts-plain64
29 Cipher key: 512 bits
30 PBKDF: argon2id
31 Time cost: 7
32 Memory: 1048576
33 Threads: 4
34 Salt: 6d 1e 78 1c f5 c1 30 06 06 03 21 a2 ad 94 fd 31
35 b1 b6 c3 8e 70 5a c4 14 36 cb 4b 6e 52 28 ff 84
36 AF stripes: 4000
37 AF hash: sha256
38 Area offset:32768 [bytes]
39 Area length:258048 [bytes]
40 Digest ID: 0
41 1: luks2
42 Key: 512 bits
43 Priority: normal
44 Cipher: aes-xts-plain64
45 Cipher key: 512 bits
46 PBKDF: pbkdf2
47 Hash: sha512
48 Iterations: 1000
49 Salt: 1a bf 2e 7d 28 72 e6 18 f1 25 f2 aa 4c 89 86 1a
50 4f 0c 95 d6 82 54 ee 34 40 8e 05 fe 1f fa 2e 3d
51 AF stripes: 4000
52 AF hash: sha512
53 Area offset:290816 [bytes]
54 Area length:258048 [bytes]
55 Digest ID: 0
56Tokens:
57 0: systemd-fido2
58 fido2-credential:
59 25 f2 ce 8a 37 bf 5c 05 5d 49 f6 63 23 e8 ce 69
60 2f 06 b8 33 54 1a f9 92 b3 de 07 41 33 6b 12 c8
61 8e c5 e6 cc dd 31 01 c4 9e b1 60 7c 25 25 71 27
62 cf dd 82 b3 f1 50 e1 42 9c c4 a6 88 dd e0 95 5b
63 fido2-salt: eb f5 43 f0 22 7c da 78 a6 8e 6f 9e 34 4e bc ff
64 49 f3 78 bc 46 8d ab a6 0e f4 fe a6 ff 98 e5 3a
65 fido2-rp: io.systemd.cryptsetup
66 fido2-clientPin-required:
67 true
68 fido2-up-required:
69 true
70 fido2-uv-required:
71 false
72 Keyslot: 1
73Digests:
74 0: pbkdf2
75 Hash: sha256
76 Iterations: 589750
77 Salt: bd 77 84 53 6b cd 48 13 23 5d 09 fa 59 5d d3 5f
78 72 ad 6e b7 93 57 a8 e8 ca 5d ab b2 0a 56 55 1d
79 Digest: 78 fc 99 e1 fe c5 63 99 1f c0 14 4f f9 fb ca 53
80 c6 df 40 7b 4d 99 fa 01 a7 cb 5a 95 f6 b6 3e 84
There are two keyslots used, keyslot 0 with the initial password and keyslot 1 with the systemd-fido2 token (referenced in the tokens section).
Now let’s get rid of the password slot.
1$ sudo systemd-cryptenroll --unlock-fido2-device=auto --wipe-slot=0 ./test.img
2Wiped slot 0.
3
4$ sudo systemd-cryptenroll ./test.img
5SLOT TYPE
6 1 fido2
7
8$ cryptsetup luksDump ./test.img
9LUKS header information
10Version: 2
11Epoch: 9
12Metadata area: 16384 [bytes]
13Keyslots area: 16744448 [bytes]
14UUID: bedfd819-a0e9-43dd-a5c5-29e3c7679a65
15Label: (no label)
16Subsystem: (no subsystem)
17Flags: (no flags)
18
19Data segments:
20 0: crypt
21 offset: 16777216 [bytes]
22 length: (whole device)
23 cipher: aes-xts-plain64
24 sector: 4096 [bytes]
25
26Keyslots:
27 1: luks2
28 Key: 512 bits
29 Priority: normal
30 Cipher: aes-xts-plain64
31 Cipher key: 512 bits
32 PBKDF: pbkdf2
33 Hash: sha512
34 Iterations: 1000
35 Salt: 1a bf 2e 7d 28 72 e6 18 f1 25 f2 aa 4c 89 86 1a
36 4f 0c 95 d6 82 54 ee 34 40 8e 05 fe 1f fa 2e 3d
37 AF stripes: 4000
38 AF hash: sha512
39 Area offset:290816 [bytes]
40 Area length:258048 [bytes]
41 Digest ID: 0
42Tokens:
43 0: systemd-fido2
44 fido2-credential:
45 25 f2 ce 8a 37 bf 5c 05 5d 49 f6 63 23 e8 ce 69
46 2f 06 b8 33 54 1a f9 92 b3 de 07 41 33 6b 12 c8
47 8e c5 e6 cc dd 31 01 c4 9e b1 60 7c 25 25 71 27
48 cf dd 82 b3 f1 50 e1 42 9c c4 a6 88 dd e0 95 5b
49 fido2-salt: eb f5 43 f0 22 7c da 78 a6 8e 6f 9e 34 4e bc ff
50 49 f3 78 bc 46 8d ab a6 0e f4 fe a6 ff 98 e5 3a
51 fido2-rp: io.systemd.cryptsetup
52 fido2-clientPin-required:
53 true
54 fido2-up-required:
55 true
56 fido2-uv-required:
57 false
58 Keyslot: 1
59Digests:
60 0: pbkdf2
61 Hash: sha256
62 Iterations: 589750
63 Salt: bd 77 84 53 6b cd 48 13 23 5d 09 fa 59 5d d3 5f
64 72 ad 6e b7 93 57 a8 e8 ca 5d ab b2 0a 56 55 1d
65 Digest: 78 fc 99 e1 fe c5 63 99 1f c0 14 4f f9 fb ca 53
66 c6 df 40 7b 4d 99 fa 01 a7 cb 5a 95 f6 b6 3e 84
That’s it. Now you can unlock the disk only with the FIDO device.
Unlocking LUKS devices
Let’s have a look how to unlock a LUKS device manually. During the unlock mechanism the FIDO pin is required and then you also have to touch the device.
1$ sudo systemd-cryptsetup attach luks-test test.img
2🔐 Please enter LUKS2 token PIN: ••••••••••••••••••••••••
3Asking FIDO2 token for authentication.
4👆 Please confirm presence on security token to unlock.
5
6$ ls -l /dev/mapper/luks-test
7lrwxrwxrwx 1 root root 7 Sep 17 20:32 /dev/mapper/luks-test -> ../dm-1
8
9$ sudo systemd-cryptsetup detach luks-test
That’s everything. With those commands you can encrypt your LUKS device with a FIDO device and ensure you have a MFA encrypted LUKS.