[Concept,10/14] luks: Support a pre-derived key with LUKSv1

Message ID 20251116212334.1603490-11-simon.glass@canonical.com
State New
Headers
Series luks: Integrate support for a TKey |

Commit Message

Simon Glass Nov. 16, 2025, 9:23 p.m. UTC
  In some cases we may wish to provide a pre-derived key, e.g. obtained
from a TKey. Provide an option for this with LUKSv1. For now it is not
exported.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 drivers/block/luks.c | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)
  

Patch

diff --git a/drivers/block/luks.c b/drivers/block/luks.c
index a3c86c5a197..3fc54dbbb9a 100644
--- a/drivers/block/luks.c
+++ b/drivers/block/luks.c
@@ -329,8 +329,9 @@  static int derive_key_pbkdf2(struct luks1_keyslot *slot, const u8 *pass,
  * @blk:		Block device
  * @pinfo:		Partition information
  * @hdr:		LUKS1 header (already read)
- * @pass:		Passphrase
+ * @pass:		Passphrase or pre-derived key
  * @pass_len:		Length of passphrase
+ * @pre_derived:	True if pass is a pre-derived key, false for passphrase
  * @master_key:		Buffer to receive master key
  * @key_size:		Output for key size
  *
@@ -338,7 +339,7 @@  static int derive_key_pbkdf2(struct luks1_keyslot *slot, const u8 *pass,
  */
 static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
 			struct luks1_phdr *hdr, const u8 *pass, size_t pass_len,
-			u8 *master_key, u32 *key_size);
+			bool pre_derived, u8 *master_key, u32 *key_size);
 
 /**
  * try_keyslot() - Try to unlock a LUKS key slot with a derived key
@@ -447,14 +448,16 @@  static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo,
  * unlock_luks1() - Unlock a LUKSv1 partition
  *
  * Attempts to unlock a LUKSv1 encrypted partition by trying each active
- * key slot with the provided passphrase. Uses PBKDF2 for key derivation
- * and supports CBC cipher mode with optional ESSIV.
+ * key slot with the provided passphrase or pre-derived key. When pre_derived
+ * is false, uses PBKDF2 for key derivation. When true, uses the pass data
+ * directly as the derived key. Supports CBC cipher mode with optional ESSIV.
  *
  * @blk:		Block device containing the partition
  * @pinfo:		Partition information
  * @hdr:		LUKSv1 header (already read and validated)
- * @pass:		Passphrase (binary data)
+ * @pass:		Passphrase (binary data) or pre-derived key
  * @pass_len:		Length of passphrase in bytes
+ * @pre_derived:	True if pass is a pre-derived key, false for passphrase
  * @master_key:		Buffer to receive unlocked master key (min 128 bytes)
  * @key_sizep:		Output for master key size in bytes (set only on success)
  *
@@ -462,7 +465,7 @@  static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo,
  */
 static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
 			struct luks1_phdr *hdr, const u8 *pass, size_t pass_len,
-			u8 *master_key, u32 *key_sizep)
+			bool pre_derived, u8 *master_key, u32 *key_sizep)
 {
 	uint split_key_size, km_blocks, key_size;
 	u8 *split_key, *derived_key;
@@ -524,6 +527,17 @@  static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
 		goto out;
 	}
 
+	/* If using pre-derived key, use it directly */
+	if (pre_derived) {
+		if (pass_len != key_size) {
+			log_debug("Pre-derived key size mismatch: got %zu, need %u\n",
+				  pass_len, key_size);
+			ret = -EINVAL;
+			goto out;
+		}
+		memcpy(derived_key, pass, key_size);
+	}
+
 	/* Try each key slot */
 	for (i = 0; i < LUKS_NUMKEYS; i++) {
 		struct luks1_keyslot *slot = &hdr->key_slot[i];
@@ -532,11 +546,13 @@  static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo,
 		if (be32_to_cpu(slot->active) != LUKS_KEY_ENABLED)
 			continue;
 
-		/* Derive key for this slot */
-		ret = derive_key_pbkdf2(slot, pass, pass_len, md_type,
-					key_size, derived_key);
-		if (ret)
-			continue;
+		/* Derive key for this slot if not pre-derived */
+		if (!pre_derived) {
+			ret = derive_key_pbkdf2(slot, pass, pass_len, md_type,
+						key_size, derived_key);
+			if (ret)
+				continue;
+		}
 
 		/* Try to unlock with the derived key */
 		ret = try_keyslot(blk, pinfo, hdr, i, md_type, key_size,
@@ -610,7 +626,7 @@  int luks_unlock(struct udevice *blk, struct disk_partition *pinfo,
 	case LUKS_VERSION_1:
 		hdr = (struct luks1_phdr *)buffer;
 		ret = unlock_luks1(blk, pinfo, hdr, pass, pass_len, master_key,
-				   key_sizep);
+				   false, key_sizep);
 		break;
 	case LUKS_VERSION_2:
 		ret = unlock_luks2(blk, pinfo, pass, pass_len, master_key,