Cryptsetup

By now, most companies are employing disk encryption. Linux has for a long time supported disk encryption, and using it is imperative for mobile devices in case of loss or theft. Upon occasion, replacing the decryption key is a necessity, and thankfully, LUKS (Linux Unified Key Setup) allows this.

To create a test filesystem with encryption:

# cd /tmp
# dd if=/dev/zero of=test.sparse bs=1 count=0 seek=100M
0+0 records in
0+0 records out
0 bytes (0 B) copied, 2.5627e-05 s, 0.0 kB/s

# ls -als test.sparse
0 -rw-r--r-- 1 root root 104857600 Dec 31 04:14 test.sparse

# losetup /dev/loop0 /tmp/test.sparse
# losetup -a
/dev/loop0: [fe00]:122882 (/tmp/test.sparse)

# cryptsetup luksFormat /dev/loop0

WARNING!
========
This will overwrite data on /dev/loop4 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: FOO
Verify passphrase: FOO

# cryptsetup luksOpen /dev/loop0 TEST-ENCRYPTED
Enter passphrase for /dev/loop0:

# mke2fs -j /dev/mapper/TEST-ENCRYPTED 
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
25168 inodes, 100352 blocks
5017 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=67371008
13 block groups
8192 blocks per group, 8192 fragments per group
1936 inodes per group
Superblock backups stored on blocks: 
	8193, 24577, 40961, 57345, 73729

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 31 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

# mount /dev/mapper/TEST-ENCRYPTED /tmp/mount
# df -k /tmp/mount
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/TEST-ENCRYPTED
                         97167      5663     86487   7% /tmp/mount

At this point we have an encrypted filesystem, 100 MB in size, mountable via the loopback filesystem (loopfs). Now, to examine the details of of test.sparse (remembering it could be any storage partition, logical volume, raid set, etc).

# cryptsetup luksDump /dev/loop0
LUKS header information for /dev/loop0

Version:       	1
Cipher name:   	aes
Cipher mode:   	cbc-essiv:sha256
Hash spec:     	sha1
Payload offset:	4096
MK bits:       	256
MK digest:     	88 e2 08 fb 6c 1f b3 cf 31 36 d6 b8 33 e5 26 e0 9e 00 87 3b 
MK salt:       	e9 9c 9b 35 f8 9f 72 f4 db 4d d7 aa 6d 6e 7e a3 
               	85 38 41 65 b5 35 0a 88 08 c9 66 ee ad ba 77 30 
MK iterations: 	66500
UUID:          	0b7452c4-1c2f-43d4-8768-fcf168d990a4

Key Slot 0: ENABLED
	Iterations:         	266167
	Salt:               	66 dc d0 4c dd 22 a4 48 b7 9b 2e bd b2 6d af 9d 
	                      	c5 5c 43 f8 25 f3 d4 86 36 8d 78 28 75 7a 52 a5 
	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

There are a lot of goodies here. One thing to note are the key slots – eight total. Isn’t that nice? Eight decryption keys can support one device. This means you can place an additional key in case one is lost, a back door. The next step is to add a key to a slot, and for this example, it is slot 7:

# cryptsetup --key-slot=7 luksAddKey /dev/loop0
Enter any passphrase: FOO
Enter new passphrase for key slot: BAR 
Verify passphrase: BAR

# cryptsetup luksDump /dev/loop0
LUKS header information for /dev/loop0

Version:       	1
Cipher name:   	aes
Cipher mode:   	cbc-essiv:sha256
Hash spec:     	sha1
Payload offset:	4096
MK bits:       	256
MK digest:     	88 e2 08 fb 6c 1f b3 cf 31 36 d6 b8 33 e5 26 e0 9e 00 87 3b 
MK salt:       	e9 9c 9b 35 f8 9f 72 f4 db 4d d7 aa 6d 6e 7e a3 
               	85 38 41 65 b5 35 0a 88 08 c9 66 ee ad ba 77 30 
MK iterations: 	66500
UUID:          	0b7452c4-1c2f-43d4-8768-fcf168d990a4

Key Slot 0: ENABLED
	Iterations:         	266167
	Salt:               	66 dc d0 4c dd 22 a4 48 b7 9b 2e bd b2 6d af 9d 
	                      	c5 5c 43 f8 25 f3 d4 86 36 8d 78 28 75 7a 52 a5 
	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: ENABLED
	Iterations:         	255589
	Salt:               	5e 49 e4 72 6f 27 7a 76 64 b9 df ae 4e 92 bc 1e 
	                      	d9 0e 55 87 61 ba e6 13 af d8 a5 4d 5f 6e 02 14 
	Key material offset:	1800
	AF stripes:            	4000

Now we have two keys for decryption, one in slot zero, the other in slot seven. To confirm the filesystem can be mounted with both passwords:

# umount /tmp/mount
# cryptsetup luksClose /dev/mapper/TEST-ENCRYPTED 
# cryptsetup luksOpen /dev/loop0 TEST-ENCRYPTED
Enter passphrase for /dev/loop0: FOO
# mount /dev/mapper/TEST-ENCRYPTED /tmp/mount
# df -k /tmp/mount
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/TEST-ENCRYPTED
                         97167      5663     86487   7% /tmp/mount

# umount /tmp/mount
# cryptsetup luksClose /dev/mapper/TEST-ENCRYPTED 
# cryptsetup luksOpen /dev/loop4 TEST-ENCRYPTED
Enter passphrase for /dev/loop4: BAR
# mount /dev/mapper/TEST-ENCRYPTED /tmp/mount
# df -k /tmp/mount
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/TEST-ENCRYPTED
                         97167      5663     86487   7% /tmp/mount

Everything works as expected. We now have two keys that can mount the encrypted loopback filesystem. The next step is to remove slot 0, and verify that its key no longer works.

# umount /tmp/mount
# cryptsetup luksClose /dev/mapper/TEST-ENCRYPTED 
# cryptsetup luksKillSlot /dev/loop0 0
Enter any remaining LUKS passphrase: BAR

# cryptsetup luksDump /dev/loop0
LUKS header information for /dev/loop0

Version:       	1
Cipher name:   	aes
Cipher mode:   	cbc-essiv:sha256
Hash spec:     	sha1
Payload offset:	4096
MK bits:       	256
MK digest:     	88 e2 08 fb 6c 1f b3 cf 31 36 d6 b8 33 e5 26 e0 9e 00 87 3b 
MK salt:       	e9 9c 9b 35 f8 9f 72 f4 db 4d d7 aa 6d 6e 7e a3 
               	85 38 41 65 b5 35 0a 88 08 c9 66 ee ad ba 77 30 
MK iterations: 	66500
UUID:          	0b7452c4-1c2f-43d4-8768-fcf168d990a4

Key Slot 0: DISABLED
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: ENABLED
	Iterations:         	255589
	Salt:               	5e 49 e4 72 6f 27 7a 76 64 b9 df ae 4e 92 bc 1e 
	                      	d9 0e 55 87 61 ba e6 13 af d8 a5 4d 5f 6e 02 14 
	Key material offset:	1800
	AF stripes:            	4000

Slot zero is now removed, and trying to use FOO confirms it:

cryptsetup luksOpen /dev/loop0 TEST-ENCRYPTED
Enter passphrase for /dev/loop0: FOO
No key available with this passphrase.
Enter passphrase for /dev/loop0: FOO
No key available with this passphrase.
Enter passphrase for /dev/loop0: FOO
No key available with this passphrase.

To tidy things up, the last steps are to add new key to slot zero, and remove slot seven.

# cryptsetup --key-slot=0 luksAddKey /dev/loop0 
Enter any passphrase: BAR
Enter new passphrase for key slot: NEW 
Verify passphrase: NEW 
# cryptsetup luksKillSlot /dev/loop0 7
Enter any remaining LUKS passphrase: NEW

# cryptsetup luksOpen /dev/loop0 TEST-ENCRYPTED
Enter passphrase for /dev/loop0: 
# mount /dev/mapper/TEST-ENCRYPTED /tmp/mount
# df -k /tmp/mount
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/TEST-ENCRYPTED
                         97167      5663     86487   7% /tmp/mount

# cryptsetup luksDump /dev/loop0
LUKS header information for /dev/loop0

Version:       	1
Cipher name:   	aes
Cipher mode:   	cbc-essiv:sha256
Hash spec:     	sha1
Payload offset:	4096
MK bits:       	256
MK digest:     	88 e2 08 fb 6c 1f b3 cf 31 36 d6 b8 33 e5 26 e0 9e 00 87 3b 
MK salt:       	e9 9c 9b 35 f8 9f 72 f4 db 4d d7 aa 6d 6e 7e a3 
               	85 38 41 65 b5 35 0a 88 08 c9 66 ee ad ba 77 30 
MK iterations: 	66500
UUID:          	0b7452c4-1c2f-43d4-8768-fcf168d990a4

Key Slot 0: ENABLED
	Iterations:         	251733
	Salt:               	4d a1 48 b7 26 15 a3 1c 53 e2 14 a4 75 7d f9 02 
	                      	8b 0f 2c 3d e3 1f 34 05 fa 21 92 15 ea d0 1b a8 
	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

This completes the key change. Looking at the above dump, one interesting item is the cipher. The default cipher can be changed at compile time for cryptsetup. From the man page (1.2.0 was used in this example), a few key points:

NOTES ON SUPPORTED CIPHERS, MODES, HASHES AND KEY SIZES

The available combinations of ciphers, modes, hashes and key sizes
depend on kernel support. See /proc/crypto for a list of available
options. You might need to load additional kernel crypto modules in
order to get more options.

For –hash option all algorithms supported by gcrypt library are avail-
able.

NOTES ON PASSWORDS

Mathematics can’t be bribed. Make sure you keep your passwords safe.
There are a few nice tricks for constructing a fallback, when suddenly
out of (or after being) blue, your brain refuses to cooperate. These
fallbacks are possible with LUKS, as it’s only possible with LUKS to
have multiple passwords.

Thank you to the folks who wrote cryptsetup. It is available here:

http://code.google.com/p/cryptsetup/

Comments are closed.