Package: libcryptsetup12
Version: 2:2.1.0-7
Severity: important
Tags: upstream

(Cloning upstream issue #466 so we can track it for Buster, Bullseye and sid.)

Even when all (bound) key slots were removed from a LUKS header, the header is
still salvageable given a copy of the master key.

The crypt_keyslot_add_by_volume_key() API call works for LUKSv1 headers
without keyslot, but fails for LUKSv2:

    $ dd if=/dev/zero of=./disk.img bs=1M count=64
    $ cryptsetup luksFormat --pbkdf-force-iterations 1000 \
        --type luks1 -q ./disk.img <<<test
    $ ./test ./disk.img "test" "test2"
    $ cryptsetup luksOpen --test-passphrase --verbose ./disk.img <<<test2
    Key slot 0 unlocked.
    Command successful.

    $ cryptsetup luksFormat --pbkdf-force-iterations 4 --pbkdf-memory 32 \
        --type luks2 -q ./disk.img <<<test
    $ ./test ./disk.img "test" "test2"
    Failed to initialise default LUKS2 keyslot parameters.
    test: Error: crypt_keyslot_add_by_volume_key

As long as the volume key is known it's always possible to map the
device as a plain crypt target, however the risk of data loss is real
for applications like the above `test` that call crypt_volume_key_get(),
crypt_keyslot_destroy(), and crypt_keyslot_add_by_volume_key() in that
order, as they might leave the header in an unusable state (without
bound keyslots).  Hence the “Severity: important”.

(These applications should use crypt_keyslot_change_by_passphrase()
instead, though.)

#include <stdlib.h>
#include <string.h>
#include <err.h>

#include "libcryptsetup.h"

int main(int argc, char *argv[]) {
    struct crypt_device *cd = NULL;
    if (crypt_init(&cd, argv[1]))
        errx(EXIT_FAILURE, "Error: crypt_init");

    if (crypt_load(cd, NULL, NULL))
        errx(EXIT_FAILURE, "Error: crypt_load");

    size_t vk_size = crypt_get_volume_key_size(cd);
    char *volume_key = malloc(vk_size);

    int keyslot = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, volume_key, &vk_size,
            argv[2], strlen(argv[2]));
    if (keyslot < 0)
        errx(EXIT_FAILURE, "Error: crypt_volume_key_get");

    if (crypt_keyslot_destroy(cd, keyslot))
        errx(EXIT_FAILURE, "Error: crypt_keyslot_destroy");

    if (crypt_keyslot_add_by_volume_key(cd, keyslot, volume_key, vk_size,
            argv[3], strlen(argv[3])))
        errx(EXIT_FAILURE, "Error: crypt_keyslot_add_by_volume_key");

    return EXIT_SUCCESS;

Attachment: signature.asc
Description: PGP signature

Reply via email to