From: Simon Glass <simon.glass@canonical.com> Add a -p flag to the luks unlock command that allows passing a hex-encoded pre-derived master key, skipping the KDF step. This is useful when the master key has been derived externally, such as from a hardware security module. Adjust the normal flow (without -p) to use a key derived on the TKey output. While that works OK with LUKS1, the 32-byte value is not long enough to work with LUKS2. Update the documentation to describe the new flag. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- cmd/luks.c | 42 +++++++++++++++++++++++++++++++----------- doc/usage/cmd/luks.rst | 18 ++++++++++++++++-- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/cmd/luks.c b/cmd/luks.c index ec4d400b44e..31805ffa5ad 100644 --- a/cmd/luks.c +++ b/cmd/luks.c @@ -85,10 +85,10 @@ static int unlock_with_tkey(struct blk_desc *dev_desc, printf("Using TKey for disk encryption key\n"); /* Find TKey device */ - ret = uclass_first_device_err(UCLASS_TKEY, &tkey_dev); - if (ret) { - printf("Failed to find TKey device (err %dE)\n", ret); - return ret; + tkey_dev = tkey_get_device(); + if (!tkey_dev) { + printf("Failed to find TKey device\n"); + return -ENOENT; } /* Derive disk key using TKey with passphrase as USS */ @@ -113,7 +113,7 @@ static int unlock_with_tkey(struct blk_desc *dev_desc, TKEY_DISK_KEY_SIZE, false); ret = luks_unlock(dev_desc->bdev, info, tkey_disk_key, - TKEY_DISK_KEY_SIZE, true, master_key, key_size); + TKEY_DISK_KEY_SIZE, false, master_key, key_size); /* Wipe TKey disk key */ memset(tkey_disk_key, '\0', sizeof(tkey_disk_key)); @@ -129,14 +129,21 @@ static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc, struct udevice *blkmap_dev; const char *passphrase = NULL; bool use_tkey = false; + bool pre_derived = false; int part, ret, version; u8 master_key[128]; char label[64]; u32 key_size; - /* Check for -t flag */ - if (!strcmp(argv[1], "-t")) { - use_tkey = true; + /* Check for flags */ + while (argc > 1 && argv[1][0] == '-') { + if (!strcmp(argv[1], "-t")) { + use_tkey = true; + } else if (!strcmp(argv[1], "-p")) { + pre_derived = true; + } else { + return CMD_RET_USAGE; + } argc--; argv++; } @@ -165,9 +172,21 @@ static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc, if (use_tkey) { ret = unlock_with_tkey(dev_desc, &info, passphrase, master_key, &key_size); + } else if (pre_derived) { + /* Pre-derived key: passphrase is hex-encoded master key */ + u8 key_buf[64]; + size_t key_len = strlen(passphrase) / 2; + + if (key_len > sizeof(key_buf) || hex2bin(key_buf, passphrase, + key_len)) { + printf("Invalid hex key\n"); + return CMD_RET_FAILURE; + } + ret = luks_unlock(dev_desc->bdev, &info, key_buf, key_len, + true, master_key, &key_size); } else { /* Unlock with passphrase */ - ret = luks_unlock(dev_desc->bdev, &info,(const u8 *)passphrase, + ret = luks_unlock(dev_desc->bdev, &info, (const u8 *)passphrase, strlen(passphrase), false, master_key, &key_size); } @@ -202,8 +221,9 @@ cleanup: static char luks_help_text[] = "detect <interface> <dev[:part]> - detect if partition is LUKS encrypted\n" "luks info <interface> <dev[:part]> - show LUKS header information\n" - "luks unlock [-t] <interface> <dev[:part]> <passphrase> - unlock LUKS partition\n" - " -t: Use TKey hardware security token with passphrase as USS\n"; + "luks unlock [-t] [-p] <interface> <dev[:part]> <passphrase> - unlock LUKS partition\n" + " -t: Use TKey hardware security token with passphrase as USS\n" + " -p: Treat passphrase as hex-encoded pre-derived master key (skip KDF)\n"; U_BOOT_CMD_WITH_SUBCMDS(luks, "LUKS (Linux Unified Key Setup) operations", luks_help_text, diff --git a/doc/usage/cmd/luks.rst b/doc/usage/cmd/luks.rst index ccf915f5844..1a9cba875ce 100644 --- a/doc/usage/cmd/luks.rst +++ b/doc/usage/cmd/luks.rst @@ -13,7 +13,7 @@ Synopsis luks detect <interface> <dev[:part]> luks info <interface> <dev[:part]> - luks unlock [-t] <interface> <dev[:part]> <passphrase> + luks unlock [-t] [-p] <interface> <dev[:part]> <passphrase> Description ----------- @@ -97,7 +97,8 @@ This command: - **Without -t**: Uses PBKDF2 or Argon2id with the provided passphrase - **With -t**: Uses TKey hardware token with passphrase as USS (User-Supplied - Secret) to derive a disk encryption key + Secret) to derive a disk encryption key. You can use 'tkey connect' to + select which TKey to use, otherwise it uses the first one it finds. 4. Attempts to unlock each active key slot 5. Verifies the master key against the stored digest @@ -128,6 +129,12 @@ be used to access files on the unlocked partition. passphrase is used as the USS (User-Supplied Secret) to derive a disk encryption key from the TKey's public key. +-p + Optional flag to treat the passphrase as a hex-encoded pre-derived master + key, skipping the KDF (Key Derivation Function) step. This is useful when + the master key has already been derived externally, such as from a hardware + security module or other key management system. + interface The storage interface type (e.g., mmc, usb, scsi) @@ -250,6 +257,13 @@ Unlock using TKey hardware token:: Successfully unlocked with key slot 0! Unlocked LUKS partition as blkmap device 'luks-mmc-0:2' +Unlock using a pre-derived master key (hex-encoded):: + + => luks unlock -p mmc 0:2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + Unlocking LUKS2 partition... + Successfully unlocked with key slot 0! + Unlocked LUKS partition as blkmap device 'luks-mmc-0:2' + Configuration ------------- -- 2.43.0