`luksAddKey` and `luksOpen` fail (ENOMEM) on LUKS2 headers without keyslots despite the use of `--master-key-file`
This is a follow-up for #466 (closed). fe4e1de5 addressed the issue with the crypt_keyslot_add_by_volume_key()
API call (already in 2.2.0-rc0), however the problem remains for the cryptsetup(8)
binary: luksAddKey --master-key-file
and luksOpen --master-key-file
fail on LUKS2 headers without key slots.
$ dd if=/dev/zero of=./disk.img bs=1M count=64
$ cryptsetup luksFormat --pbkdf-force-iterations 4 --pbkdf-memory 32 \
--type luks2 -q ./disk.img <<<test
$ rm -f ./master.key
$ cryptsetup luksDump --master-key-file ./master.key --dump-master-key \
-q ./disk.img <<<test
At this point it's still possible to open the device, both with the passphrase and the master key file:
$ cryptsetup luksOpen --test-passphrase --verbose ./disk.img <<<test
Key slot 0 unlocked.
Command successful.
$ cryptsetup luksOpen --test-passphrase --master-key-file ./master.key --verbose ./disk.img
Command successful.
However after removing the (only) keyslot, it's no longer possible to open the device, or to add a new key slot.
$ cryptsetup luksKillSlot -q ./disk.img 0
$ cryptsetup luksOpen --test-passphrase --master-key-file ./master.key --verbose ./disk.img
Command failed with code -3 (out of memory).
$ cryptsetup luksAddKey --master-key-file ./master.key --verbose -q ./disk.img <<<test2
Command failed with code -3 (out of memory).
AFAIK ENOMEM
comes from tools_read_mk(master_keyfile,,0)
in src/utils_password.c
. The 0 is the value returned from crypt_get_volume_key_size()
which, as @mbroz documented in fe4e1de5, doesn't work for LUKS2 headers without keyslots. Fair enough, but in that case I suppose tools_read_mk()
could set the key size from the file's stat structure before calling crypt_safe_alloc(keysize)
?
Since there is no mention that --master-key-file
doesn't work with LUKS2 headers without (bound) keyslots, I assume it's a bug :-) (Perhaps only a documentation bug.) Of course, there is no data loss as long as the volume key remains known. A workaround for luksOpen
is to use plainOpen
with suitable payload offset and cipher, for instance
$ cryptsetup plainOpen \
--offset 32768 \
--key-file ./master.key \
--key-size $(( $(stat -c %s ./master.key) * 8 )) \
--cipher aes-xts-plain64 …