resetting passphrases for mapped LUKS volumes

Let's say you set up a machine using an encrypted disk with LUKS (debian-installer's partman makes this wonderfully easy!). You choose an initial passphrase, get the machine working, and it's working great. Then, you need to restart it, and realize that (for whatever reason) you've forgotten or lost the passphrase for the volume. oops! (i'm sure this has never happened to you -- let's just pretend it's your less-fortunate friend).

If your system is still running, and you have superuser access to it, you can actually set a new passphrase for the LUKS volume using information that the dm-crypt kernel module has about the in-use mapping. In my examples, i'll imagine that the source volume is /dev/XXX2 and the exported cleartext volume is known by the device-mapper as XXX2_crypt

In the bigger picture, this should serve as a reminder that even though your disk is encrypted, if someone gets live access to the superuser account on a system with the encryption keys loaded, your data is no longer secret.

Before you do any tweaking, you might want to back up your LUKS header, just in case:

0 root@example:~# umask 0770 root@example:~# cryptsetup luksHeaderBackup /dev/XXX2 --header-backup-file XXX2.luksheader.backup0 root@example:~# 

Maybe also copy that off the machine, since a copy of the LUKS header stored within its own volume isn't terribly useful for a backup-recovery situation.

You might also be interested in looking at the contents of the LUKS header:

0 root@example:~# cryptsetup luksDump /dev/XXX2LUKS header information for /dev/XXX2Version:        1Cipher name:    aesCipher mode:      cbc-essiv:sha256Hash spec:       sha1Payload offset:  2056MK bits:         256MK digest:      93 51 6c 66 ec ce 32 54 6f 6b 52 d1 27 9b 5a 62 6f 6b 52 d1MK salt:        b2 ca 20 49 9f 78 49 c2 fe 15 b4 0f 74 11 23 49                  64 9e 61 bb f2 82 60 47 a5 76 fa a4 24 0e 5a 7eMK iterations:    10UUID:              052f1da0-21a1-11e0-ac64-0800200c9a66Key Slot 0: ENABLED    Iterations:             218733   Salt:                   f2 ae 8c 53 48 a5 f0 bf e1 2c 06 5f 5a bd ff d9                          9a 2e d1 49 3a 63 f8 49 82 ed ae 86 7b 7b 7e 76  Key material offset:    8    AF stripes:             4000Key Slot 1: DISABLEDKey Slot 2: DISABLEDKey Slot 3: DISABLEDKey Slot 4: DISABLEDKey Slot 5: DISABLEDKey Slot 6: DISABLEDKey Slot 7: DISABLED0 root@example:~# 

Now, the fix: We pull the live "master key" from the running device map, and fill a new luksKeySlot from it (this example uses bash's <() syntax for process substitution -- if you use a different shell, i'm sure you can find a different way to do it):

0 root@example:~# cryptsetup --master-key-file <( > dmsetup --showkeys table | awk '/^XXX2_crypt: /{ print $6 }' | tr -d '\n' | perl -e 'print pack("H*", <STDIN>);' > ) luksAddKey /dev/XXX2Enter new passphrase for key slot: abc123Verify passphrase: abc1232 root@example:~# 

(note that the luksAddKey invocation above returned an error code of 2 even though it succeeded. I think this is a bug in cryptsetup's return code, not a bug in the password resetting -- it should have returned 0 instead of 2).

You can check to see that a new key slot was enabled by re-running cryptsetup luksDump

And if you really want to double-check before you reboot, you can try enabling a third keyslot using the passphrase you just added, since this would not succeed if your new passphrase failed to unlock any of the existing keyslots:

0 root@example:~# cryptsetup luksAddKey /dev/XXX2Enter any passphrase: abc123Enter new passphrase for key slot: anotherpassphraseVerify passphrase: anotherpassphrase0 root@example:~# 

You can also get rid of the original keyslot (which you don't know the passphrase to) like this:

0 root@example:~# cryptsetup luksKillSlot /dev/XXX2 0Enter any remaining LUKS passphrase: abc1230 root@example:~# 

(the above commands were all demonstrated using debian testing, with cryptsetup 2:1.1.3-4 and dmsetup 2:1.02.48-4)

Tags: cryptsetup, dmsetup, luks, tip