[Concept,3/5] luks: Move blkmap crypt code into a separate file

Message ID 20251112124252.1081477-4-sjg@u-boot.org
State New
Headers
Series luks: Support the AES-XTS cipher mode |

Commit Message

Simon Glass Nov. 12, 2025, 12:42 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Create a new blkmap_crypt.c file to hold the LUKS code, since it is
fairly large. Add an internal header for blkmap as well.

Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 drivers/block/Makefile          |   1 +
 drivers/block/blkmap.c          | 204 +-------------------------------
 drivers/block/blkmap_crypt.c    | 172 +++++++++++++++++++++++++++
 drivers/block/blkmap_internal.h |  74 ++++++++++++
 4 files changed, 249 insertions(+), 202 deletions(-)
 create mode 100644 drivers/block/blkmap_crypt.c
 create mode 100644 drivers/block/blkmap_internal.h
  

Patch

diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 538b602790d..0735efea719 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -17,6 +17,7 @@  endif
 obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o
 obj-$(CONFIG_$(PHASE_)BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap.o
+obj-$(CONFIG_BLK_LUKS) += blkmap_crypt.o
 obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap_helper.o
 
 obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index 13a79001979..14aa1e4d088 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -11,62 +11,11 @@ 
 #include <mapmem.h>
 #include <memalign.h>
 #include <part.h>
-#include <uboot_aes.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/root.h>
 #include <linux/string.h>
-
-struct blkmap;
-
-/**
- * struct blkmap_slice - Region mapped to a blkmap
- *
- * Common data for a region mapped to a blkmap, specialized by each
- * map type.
- *
- * @node: List node used to associate this slice with a blkmap
- * @blknr: Start block number of the mapping
- * @blkcnt: Number of blocks covered by this mapping
- */
-struct blkmap_slice {
-	struct list_head node;
-
-	lbaint_t blknr;
-	lbaint_t blkcnt;
-
-	/**
-	 * @read: - Read from slice
-	 *
-	 * @read.bm: Blkmap to which this slice belongs
-	 * @read.bms: This slice
-	 * @read.blknr: Start block number to read from
-	 * @read.blkcnt: Number of blocks to read
-	 * @read.buffer: Buffer to store read data to
-	 */
-	ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms,
-		      lbaint_t blknr, lbaint_t blkcnt, void *buffer);
-
-	/**
-	 * @write: - Write to slice
-	 *
-	 * @write.bm: Blkmap to which this slice belongs
-	 * @write.bms: This slice
-	 * @write.blknr: Start block number to write to
-	 * @write.blkcnt: Number of blocks to write
-	 * @write.buffer: Data to be written
-	 */
-	ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms,
-		       lbaint_t blknr, lbaint_t blkcnt, const void *buffer);
-
-	/**
-	 * @destroy: - Tear down slice
-	 *
-	 * @read.bm: Blkmap to which this slice belongs
-	 * @read.bms: This slice
-	 */
-	void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
-};
+#include "blkmap_internal.h"
 
 static bool blkmap_slice_contains(struct blkmap_slice *bms, lbaint_t blknr)
 {
@@ -92,7 +41,7 @@  static bool blkmap_slice_available(struct blkmap *bm, struct blkmap_slice *new)
 	return true;
 }
 
-static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
+int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
 {
 	struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
 	struct list_head *insert = &bm->slices;
@@ -293,155 +242,6 @@  int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 	return err;
 }
 
-/**
- * struct blkmap_crypt - Encrypted device mapping
- *
- * @slice: Common map data
- * @blk: Target encrypted block device
- * @blknr: Start block number of encrypted data on target device
- * @master_key: Decrypted master key for this mapping
- * @key_size: Size of master key in bytes
- * @payload_offset: LUKS payload offset in sectors
- * @use_essiv: True if ESSIV mode is used for IV generation
- * @essiv_key: ESSIV key (SHA256 hash of master key)
- */
-struct blkmap_crypt {
-	struct blkmap_slice slice;
-	struct udevice *blk;
-	lbaint_t blknr;
-	u8 master_key[128];
-	u32 key_size;
-	u32 payload_offset;
-	bool use_essiv;
-	u8 essiv_key[32];
-};
-
-static ulong blkmap_crypt_read(struct blkmap *bm, struct blkmap_slice *bms,
-			       lbaint_t blknr, lbaint_t blkcnt, void *buffer)
-{
-	struct blkmap_crypt *bmc = container_of(bms, struct blkmap_crypt, slice);
-	struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
-	struct blk_desc *src_bd = dev_get_uclass_plat(bmc->blk);
-	lbaint_t src_blknr, blocks_read;
-	u8 *encrypted_buf, *dest = buffer;
-	u8 expkey[AES256_EXPAND_KEY_LENGTH];
-	u8 iv[AES_BLOCK_LENGTH];
-	u64 sector;
-	lbaint_t i;
-
-	/* Allocate buffer for encrypted data */
-	encrypted_buf = malloc_cache_aligned(blkcnt * src_bd->blksz);
-	if (!encrypted_buf)
-		return 0;
-
-	/*
-	 * Calculate source block number (LUKS payload offset + requested
-	 * block)
-	 */
-	src_blknr = bmc->blknr + bmc->payload_offset + blknr;
-
-	/* Read encrypted data from underlying device */
-	blocks_read = blk_read(bmc->blk, src_blknr, blkcnt, encrypted_buf);
-	if (blocks_read != blkcnt) {
-		free(encrypted_buf);
-		return 0;
-	}
-
-	/* Expand AES key */
-	aes_expand_key(bmc->master_key, bmc->key_size * 8, expkey);
-
-	/* Decrypt each sector */
-	for (i = 0; i < blkcnt; i++) {
-		/* Calculate sector number for IV */
-		sector = blknr + i;
-
-		if (bmc->use_essiv) {
-			/*
-			 * ESSIV mode:
-			 * IV = AES_encrypt(sector_number, SHA256(master_key))
-			 */
-			u8 essiv_expkey[AES256_EXPAND_KEY_LENGTH];
-			u8 sector_iv[AES_BLOCK_LENGTH];
-
-			/* Create sector number as IV input (little-endian) */
-			memset(sector_iv, 0, sizeof(sector_iv));
-			*(u64 *)sector_iv = cpu_to_le64(sector);
-
-			/* Expand ESSIV key */
-			aes_expand_key(bmc->essiv_key, 256, essiv_expkey);
-
-			/* Encrypt sector number with ESSIV key to get IV */
-			aes_encrypt(256, sector_iv, essiv_expkey, iv);
-		} else {
-			/*
-			 * Plain64 mode:
-			 * IV is sector number in little-endian format
-			 */
-			memset(iv, '\0', sizeof(iv));
-			*(u64 *)iv = cpu_to_le64(sector);
-		}
-
-		/* Decrypt sector using AES-CBC */
-		aes_cbc_decrypt_blocks(bmc->key_size * 8, expkey, iv,
-				       encrypted_buf + i * bd->blksz,
-				       dest + i * bd->blksz,
-				       bd->blksz / AES_BLOCK_LENGTH);
-	}
-	free(encrypted_buf);
-
-	return blkcnt;
-}
-
-static void blkmap_crypt_destroy(struct blkmap *bm, struct blkmap_slice *bms)
-{
-	struct blkmap_crypt *bmc = container_of(bms, struct blkmap_crypt, slice);
-
-	/* Securely wipe master key before freeing */
-	memset(bmc->master_key, 0, sizeof(bmc->master_key));
-	free(bmc);
-}
-
-int blkmap_map_crypt(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
-		     struct udevice *lblk, lbaint_t lblknr,
-		     const u8 *master_key, u32 key_size, u32 payload_offset,
-		     bool use_essiv, const u8 *essiv_key)
-{
-	struct blkmap *bm = dev_get_plat(dev);
-	struct blkmap_crypt *bmc;
-	int err;
-
-	if (key_size > 128)
-		return -EINVAL;
-
-	bmc = malloc(sizeof(*bmc));
-	if (!bmc)
-		return -ENOMEM;
-
-	bmc->blk = lblk;
-	bmc->blknr = lblknr;
-	bmc->key_size = key_size;
-	bmc->payload_offset = payload_offset;
-	bmc->use_essiv = use_essiv;
-	memcpy(bmc->master_key, master_key, key_size);
-
-	if (use_essiv && essiv_key)
-		memcpy(bmc->essiv_key, essiv_key, sizeof(bmc->essiv_key));
-	else
-		memset(bmc->essiv_key, 0, sizeof(bmc->essiv_key));
-
-	bmc->slice.blknr = blknr;
-	bmc->slice.blkcnt = blkcnt;
-	bmc->slice.read = blkmap_crypt_read;
-	bmc->slice.write = NULL;  /* Read-only for now */
-	bmc->slice.destroy = blkmap_crypt_destroy;
-
-	err = blkmap_slice_add(bm, &bmc->slice);
-	if (err)
-		free(bmc);
-
-	return err;
-}
-
 static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms,
 				   lbaint_t blknr, lbaint_t blkcnt,
 				   void *buffer)
diff --git a/drivers/block/blkmap_crypt.c b/drivers/block/blkmap_crypt.c
new file mode 100644
index 00000000000..bc77ddc2751
--- /dev/null
+++ b/drivers/block/blkmap_crypt.c
@@ -0,0 +1,172 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 Canonical Ltd
+ * Author: Simon Glass <simon.glass@canonical.com>
+ *
+ * LUKS encryption/decryption support
+ */
+
+#include <blk.h>
+#include <blkmap.h>
+#include <dm.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <uboot_aes.h>
+#include <mbedtls/aes.h>
+#include <dm/device-internal.h>
+#include <linux/string.h>
+#include "blkmap_internal.h"
+
+/**
+ * struct blkmap_crypt - Encrypted mapping
+ *
+ * Data associated with an encrypted region of a block device (e.g., LUKS).
+ * Provides on-the-fly decryption of data using AES-CBC or AES-XTS modes.
+ *
+ * @slice: Common slice data (must be first member)
+ * @blk: Underlying block device containing encrypted data
+ * @blknr: Start block of the underlying block device
+ * @master_key: Decrypted master key for decryption
+ * @key_size: Size of the master key in bytes (must be <= 128)
+ * @payload_offset: Offset in sectors from lblknr to actual encrypted payload
+ * @sector_size: Sector size for IV calculation (typically 512 or 4096)
+ * @use_essiv: True if ESSIV mode is used for IV generation (CBC only)
+ * @essiv_key: ESSIV key (SHA256 hash of master key)
+ */
+struct blkmap_crypt {
+	struct blkmap_slice slice;
+	struct udevice *blk;
+	lbaint_t blknr;
+	u8 master_key[128];
+	u32 key_size;
+	u32 payload_offset;
+	u32 sector_size;
+	bool use_essiv;
+	u8 essiv_key[32];
+};
+
+static ulong blkmap_crypt_read(struct blkmap *bm, struct blkmap_slice *bms,
+			       lbaint_t blknr, lbaint_t blkcnt, void *buffer)
+{
+	struct blkmap_crypt *bmc = container_of(bms, struct blkmap_crypt, slice);
+	struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
+	struct blk_desc *src_bd = dev_get_uclass_plat(bmc->blk);
+	lbaint_t src_blknr, blocks_read;
+	u8 *encrypted_buf, *dest = buffer;
+	u8 expkey[AES256_EXPAND_KEY_LENGTH];
+	u8 iv[AES_BLOCK_LENGTH];
+	u64 sector;
+	lbaint_t i;
+
+	/* Allocate buffer for encrypted data */
+	encrypted_buf = malloc_cache_aligned(blkcnt * src_bd->blksz);
+	if (!encrypted_buf)
+		return 0;
+
+	/*
+	 * Calculate source block number (LUKS payload offset + requested
+	 * block)
+	 */
+	src_blknr = bmc->blknr + bmc->payload_offset + blknr;
+
+	/* Read encrypted data from underlying device */
+	blocks_read = blk_read(bmc->blk, src_blknr, blkcnt, encrypted_buf);
+	if (blocks_read != blkcnt) {
+		free(encrypted_buf);
+		return 0;
+	}
+
+	/* Expand AES key */
+	aes_expand_key(bmc->master_key, bmc->key_size * 8, expkey);
+
+	/* Decrypt each sector */
+	for (i = 0; i < blkcnt; i++) {
+		/* Calculate sector number for IV */
+		sector = blknr + i;
+
+		if (bmc->use_essiv) {
+			/*
+			 * ESSIV mode:
+			 * IV = AES_encrypt(sector_number, SHA256(master_key))
+			 */
+			u8 essiv_expkey[AES256_EXPAND_KEY_LENGTH];
+			u8 sector_iv[AES_BLOCK_LENGTH];
+
+			/* Create sector number as IV input (little-endian) */
+			memset(sector_iv, '\0', sizeof(sector_iv));
+			*(u64 *)sector_iv = cpu_to_le64(sector);
+
+			/* Expand ESSIV key */
+			aes_expand_key(bmc->essiv_key, 256, essiv_expkey);
+
+			/* Encrypt sector number with ESSIV key to get IV */
+			aes_encrypt(256, sector_iv, essiv_expkey, iv);
+		} else {
+			/*
+			 * Plain64 mode:
+			 * IV is sector number in little-endian format
+			 */
+			memset(iv, '\0', sizeof(iv));
+			*(u64 *)iv = cpu_to_le64(sector);
+		}
+
+		/* Decrypt sector using AES-CBC */
+		aes_cbc_decrypt_blocks(bmc->key_size * 8, expkey, iv,
+				       encrypted_buf + i * bd->blksz,
+				       dest + i * bd->blksz,
+				       bd->blksz / AES_BLOCK_LENGTH);
+	}
+	free(encrypted_buf);
+
+	return blkcnt;
+}
+
+static void blkmap_crypt_destroy(struct blkmap *bm, struct blkmap_slice *bms)
+{
+	struct blkmap_crypt *bmc = container_of(bms, struct blkmap_crypt, slice);
+
+	/* Securely wipe master key before freeing */
+	memset(bmc->master_key, '\0', sizeof(bmc->master_key));
+	free(bmc);
+}
+
+int blkmap_map_crypt(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+		     struct udevice *lblk, lbaint_t lblknr,
+		     const u8 *master_key, u32 key_size, u32 payload_offset,
+		     bool use_essiv, const u8 *essiv_key)
+{
+	struct blkmap *bm = dev_get_plat(dev);
+	struct blkmap_crypt *bmc;
+	int err;
+
+	if (key_size > 128)
+		return -EINVAL;
+
+	bmc = malloc(sizeof(*bmc));
+	if (!bmc)
+		return -ENOMEM;
+
+	bmc->blk = lblk;
+	bmc->blknr = lblknr;
+	bmc->key_size = key_size;
+	bmc->payload_offset = payload_offset;
+	bmc->use_essiv = use_essiv;
+	memcpy(bmc->master_key, master_key, key_size);
+
+	if (use_essiv && essiv_key)
+		memcpy(bmc->essiv_key, essiv_key, sizeof(bmc->essiv_key));
+	else
+		memset(bmc->essiv_key, '\0', sizeof(bmc->essiv_key));
+
+	bmc->slice.blknr = blknr;
+	bmc->slice.blkcnt = blkcnt;
+	bmc->slice.read = blkmap_crypt_read;
+	bmc->slice.write = NULL;  /* Read-only for now */
+	bmc->slice.destroy = blkmap_crypt_destroy;
+
+	err = blkmap_slice_add(bm, &bmc->slice);
+	if (err)
+		free(bmc);
+
+	return err;
+}
diff --git a/drivers/block/blkmap_internal.h b/drivers/block/blkmap_internal.h
new file mode 100644
index 00000000000..07947c7ef0b
--- /dev/null
+++ b/drivers/block/blkmap_internal.h
@@ -0,0 +1,74 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2023 Addiva Elektronik
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
+ *
+ * Internal blkmap structures and functions
+ */
+
+#ifndef _BLKMAP_INTERNAL_H
+#define _BLKMAP_INTERNAL_H
+
+#include <dm/lists.h>
+
+struct blkmap;
+
+/**
+ * struct blkmap_slice - Region mapped to a blkmap
+ *
+ * Common data for a region mapped to a blkmap, specialized by each
+ * map type.
+ *
+ * @node: List node used to associate this slice with a blkmap
+ * @blknr: Start block number of the mapping
+ * @blkcnt: Number of blocks covered by this mapping
+ */
+struct blkmap_slice {
+	struct list_head node;
+
+	lbaint_t blknr;
+	lbaint_t blkcnt;
+
+	/**
+	 * @read: - Read from slice
+	 *
+	 * @read.bm: Blkmap to which this slice belongs
+	 * @read.bms: This slice
+	 * @read.blknr: Start block number to read from
+	 * @read.blkcnt: Number of blocks to read
+	 * @read.buffer: Buffer to store read data to
+	 */
+	ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms,
+		      lbaint_t blknr, lbaint_t blkcnt, void *buffer);
+
+	/**
+	 * @write: - Write to slice
+	 *
+	 * @write.bm: Blkmap to which this slice belongs
+	 * @write.bms: This slice
+	 * @write.blknr: Start block number to write to
+	 * @write.blkcnt: Number of blocks to write
+	 * @write.buffer: Data to be written
+	 */
+	ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms,
+		       lbaint_t blknr, lbaint_t blkcnt, const void *buffer);
+
+	/**
+	 * @destroy: - Tear down slice
+	 *
+	 * @read.bm: Blkmap to which this slice belongs
+	 * @read.bms: This slice
+	 */
+	void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
+};
+
+/**
+ * blkmap_slice_add() - Add a slice to a blkmap
+ *
+ * @bm: Blkmap to add the slice to
+ * @new: New slice to add
+ * Returns: 0 on success, negative error code on failure
+ */
+int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new);
+
+#endif /* _BLKMAP_INTERNAL_H */