Linux Unified Key Setup

Linux Unified Key Setup

Full Disk Encryption

  • Transparent encryption on disk sector level
    • Transparent for filesystem
    • No user decision what to encrypt
    • Encryption of hibernation and swap partitions
  • Volume key – key used to encrypt data
  • Passphrase – unlocks encrypted disk

Linux Full Disk Encryption

  • dm-crypt (kernel module) + cryptsetup (control utility)
  • LUKS (Linux Unified Key Setup)
    • On-disk format to store encrypted volume key
    • Implemented inside cryptsetup library

LUKS Common Use Cases

  • Local encrypted disk
    • Encrypted notebook, portable drives, …
    • Corporate notebooks – on-demand recovery
  • Data center disks
    • Different physical access policies in-place
    • Data disks (also Gluster bricks, Ceph OSDs, …)
    • Automatic unlocking?
  • Mobile devices
    • Specific environment, usually non-LUKS metadata

LUKS Threat Example

  • Asset: Confidential data on-disk Threat: Stolen disk => Strong encryption with random key => Dictionary password attack resistance
  • LUKS provides data confidentiality only
  • No integrity protection
  • Protection only of locked (powered-off) device

Key Management

  • It’s all about weak passwords :-)
  • Password-based key derivation functions
    • PBKDF2
    • Argon2 (PHC winner)
  • No Trusted Platform Module (TPM) bindings
  • No 2nd factors authentication.
  • No secret sharing.

Disk Encryption “User Survey”

  • 6% does not use encryption (despite company policy :-)
  • 96% believes that encryption increases security
  • 20% lost data on encrypted disk at least once
    • 59% of them lost data forever
    • 18% of them suffered corruption of encrypted disk
  • 62% have backups of encrypted data
  • 1% have problem with slowdown caused by encryption
    • 75% did not notice, 19% negligible slowdown

Device-Mapper’s “crypt” target

dm-crypt is a transparent disk encryption subsystem in Linux kernel versions 2.6 and later and in DragonFly BSD. It is part of the device mapper (dm) infrastructure, and uses cryptographic routines from the kernel’s Crypto API.

dm-crypt is implemented as a device mapper target and may be stacked on top of other device mapper transformations. It can thus encrypt whole disks (including removable media), partitions, software RAID volumes, logical volumes, as well as files. It appears as a block device, which can be used to back file systems, swap or as an LVM physical volume.

Configuring File Encryption

Create a LUKS Format File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo apt-get install -y cryptsetup-bin

$ truncate --size 4G secret-block.raw
$ du -ms secret-block.raw
0 secret-block.raw

$ cryptsetup -y luksFormat --sector-size 4096 secret-block.raw

WARNING!
========
This will overwrite data on secret-block.raw irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for secret-block.raw:
Verify passphrase:

$ du -ms secret-block.raw
16 secret-block.raw

Open LUKS Format File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
$ sudo cryptsetup luksOpen secret-block.raw secret-block
Enter passphrase for secret-block.raw:

$ sudo cryptsetup status secret-block
/dev/mapper/secret-block is active.
type: LUKS2
cipher: aes-xts-plain64
keysize: 512 bits
key location: keyring
device: /dev/loop0
loop: secret-block.raw
sector size: 4096
offset: 32768 sectors
size: 8355840 sectors
mode: read/write

$ sudo cryptsetup luksDump /dev/loop0
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: f5b87a43-f565-4078-a1f2-735d90c170d8
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)

Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 4096 [bytes]

Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2id
Time cost: 5
Memory: 1048576
Threads: 4
Salt: cd 80 4c b7 06 c6 6c 21 e0 f6 1e a3 64 dc 2d 3e
f3 5b e1 a3 be 38 95 20 34 d3 30 fc 03 f6 04 0b
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 123419
Salt: 50 21 fd 06 c0 88 fa 3b 6a 34 08 a2 16 47 e6 b1
25 53 85 c5 2e ec 65 ae 53 94 f3 56 af df ae ef
Digest: 64 a7 08 b0 8b ac cc bf cb a6 dc 9a a4 4c 41 f0
3e d5 da 70 e4 f8 95 36 99 83 70 b3 75 23 30 f2

Protect Against Disclosure of Usage Patterns

File block data with zeros, protect against disclosure of usage patterns.

1
$ sudo dd if=/dev/zero of=/dev/mapper/secret-block

Create a Filesystem

1
2
3
4
5
6
7
8
9
10
11
$ sudo mkfs.xfs /dev/mapper/secret-block
meta-data=/dev/mapper/secret-block isize=512 agcount=4, agsize=261120 blks
= sectsz=4096 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1 bigtime=0 inobtcount=0
data = bsize=4096 blocks=1044480, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=4096 sunit=1 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

Mount and Use Encrypted Filesystem

1
2
3
4
5
6
7
8
9
$ sudo xfs_info /dev/mapper/secret-block

$ sudo mount /dev/mapper/secret-block secret-fs
$ echo "01234567890abcdefghijklmnopqrstuvwxyz" | sudo tee secret-fs/test.txt

$ sudo umount secret-fs/
$ sudo cryptsetup luksClose /dev/mapper/secret-block

$ grep "01234567890abcdefghijklmnopqrstuvwxyz" secret-block.raw

GnuPG Encrypted Key File

1
2
3
4
$ dd if=/dev/urandom count=64 bs=1k \
| gpg --symmetric --cipher-algo AES256 --armor > /path/to/secret-block-key.gpg
$ gpg --decrypt /path/to/secret-block-key.gpg \
| cryptsetup luksFormat --sector-size 4096 secret-block.raw

Daily Usage of File Encryption

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo cryptsetup luksOpen secret-block.raw secret-block
Enter passphrase for secret-block.raw:

# Only if you use GnuPG encrypted keyfile
$ gpg --decrypt /path/to/secret-block-key.gpg \
| sudo cryptsetup luksOpen secret-block.raw secret-block
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase

$ sudo mount /dev/mapper/secret-block secret-fs

$ echo "01234567890abcdefghijklmnopqrstuvwxyz" | sudo tee secret-fs/test.txt

$ sudo umount secret-fs/
$ sudo cryptsetup luksClose /dev/mapper/secret-block

Securely Integrating with QEMU

Secrets

  • secret” object type (v2.6.0)
    • raw or base64
    • plain text or encrypted
    • inline or file
  • RBD, iSCSI, CURL, LUKS, x509 cert
    • One global master secret via file
    • Per object secrets inline & encrypted

Secrets: Creation

  • Password inline as clear text (insecure) -object secret,id=sec0,data=letmein
  • Password from a clear text file (secure) -object secret,id=sec0,file=passwd.txt
  • Password from a base64 clear text file (secure) -object secret,id=sec0,file=passwd.b64,format=base64
  • Password inline as aes256 cipher text (secure) -object secret,id=sec0,file=master.aes
    -object secret,id=sec1,data=CIPHERTEXT,keyid=sec0,iv=NNNNNNNNNNNNNNN

Secrets: Usage

  • Disks with “password-secret” property
1
2
3
-drive driver=rbd,\
filename=rbd:pool/image:id=myname:\
auth_supported=cephx,password-secret=sec0
  • TLS cert with “passwordid” property
1
2
-object tls-creds-x509,dir=/etc/tls/qemu,\
id=tls0,endpoint=server,paswordid=sec0

QEMU with Plain LUKS File

1
2
3
4
5
6
7
8
9
10
11
$ qemu-img create -f luks --object secret,id=sec0,data=demo-password -o key-secret=sec0 demo.luks 64G
Formatting 'demo.luks', fmt=luks size=68719476736 key-secret=sec0

$ ls -ln demo.luks
-rw-r--r-- 1 1000 1000 68721545216 2021-09-21 21:19 demo.luks

$ stat demo.luks
File: demo.luks
Size: 68721545216 Blocks: 2048 IO Block: 4096 regular file
Device: fe01h/65025d Inode: 403937219 Links: 1
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo modprobe nbd max_part=16 nbds_max=16

$ sudo qemu-nbd --connect=/dev/nbd0 --object secret,id=sec0,data=demo-password --image-opts driver=luks,key-secret=sec0,file.driver=file,file.filename=demo.luks

$ sudo fdisk /dev/nbd0 -l
$ sudo mkfs.ext4 /dev/nbd0p1
$ du -ms demo.luks
323 demo.luks

$ sudo mount /dev/nbd0p1 nbd
$ echo "01234567890abcdefghijklmnopqrstuvwxyz" | sudo tee nbd/test.txt

$ sudo umount nbd/
$ sudo qemu-nbd --disconnect /dev/nbd0
/dev/nbd0 disconnected

$ grep "01234567890abcdefghijklmnopqrstuvwxyz" demo.luks

QEMU with QCOW2 Have LUKS Payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ qemu-img create -f qcow2 -o encrypt.format=luks,encrypt.key-secret=sec_luks --object secret,data=demo-password,id=sec_luks demo.qcow2 64G

Formatting 'demo.qcow2', fmt=qcow2 encrypt.format=luks encrypt.key-secret=sec_luks cluster_size=65536 extended_l2=off compression_type=zlib size=68719476736 lazy_refcounts=off refcount_bits=16

$ ls -ln demo.qcow2
-rw-r--r-- 1 1000 1000 2359296 2021-09-21 21:47 demo.qcow2

$ du -ks demo.qcow2
3328 demo.qcow2

$ stat demo.qcow2
File: demo.qcow2
Size: 2359296 Blocks: 6656 IO Block: 4096 regular file
Device: fe01h/65025d Inode: 403937216 Links: 1
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo modprobe nbd max_part=16 nbds_max=16

$ sudo qemu-nbd --connect=/dev/nbd0 --object secret,id=sec0,data=demo-password --image-opts driver=qcow2,encrypt.key-secret=sec0,file.driver=file,file.filename=demo.qcow2

$ sudo fdisk /dev/nbd0 -l
$ sudo mkfs.ext4 /dev/nbd0p1
$ du -ms demo.qcow2
283 demo.qcow2

$ sudo mount /dev/nbd0p1 nbd
$ echo "01234567890abcdefghijklmnopqrstuvwxyz" | sudo tee nbd/test.txt

$ sudo umount nbd/
$ sudo qemu-nbd --disconnect /dev/nbd0
/dev/nbd0 disconnected

$ grep "01234567890abcdefghijklmnopqrstuvwxyz" demo.qcow2