[Concept,16/19] luks: Add -p flag for pre-derived master key

Message ID 20251208023229.3929910-17-sjg@u-boot.org
State New
Headers
Series bootctl: Continue development with TKey functionality |

Commit Message

Simon Glass Dec. 8, 2025, 2:32 a.m. UTC
  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(-)
  

Patch

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
 -------------