From patchwork Fri Oct 31 06:54:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 671 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893793; bh=n0ZuHMd7FN1q07x85cItxkgs8csjRVH0YFXyxiguiyw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=HXE8KGNh9S0es0GV0InQPjN4zL9IOHv1i4IUkDu8Dr68Xz4v6nipljqVNlaHOpNPe b4Lw6JHqL2mgqyvyd7dlztc18mxMrFEjLwltT4/j/6PF5GMmKw6IZ/oCj1mCq2m3Lu ARM1Sj0eCuKYzPvtSm3mVsT+Og9kujL+Mr8WK7f13mn1/FYsteYHi2iAgod2rYJUQY /VF7A94N9rrIW8S6SzYcpP95M4JCerRSpnQ6CuuuwW2zAEHq906KCYK1wawMJksyyr uIJJ7JaPJSbUrHZA3lT1l+T8FMhMmL9/97lM1nydni40JTGYdaa1NkkpSOa5y2QV1f JYVBWHCe4AKog== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4DDD068368 for ; Fri, 31 Oct 2025 00:56:33 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id shzS3MnHv3SI for ; Fri, 31 Oct 2025 00:56:33 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893793; bh=n0ZuHMd7FN1q07x85cItxkgs8csjRVH0YFXyxiguiyw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=HXE8KGNh9S0es0GV0InQPjN4zL9IOHv1i4IUkDu8Dr68Xz4v6nipljqVNlaHOpNPe b4Lw6JHqL2mgqyvyd7dlztc18mxMrFEjLwltT4/j/6PF5GMmKw6IZ/oCj1mCq2m3Lu ARM1Sj0eCuKYzPvtSm3mVsT+Og9kujL+Mr8WK7f13mn1/FYsteYHi2iAgod2rYJUQY /VF7A94N9rrIW8S6SzYcpP95M4JCerRSpnQ6CuuuwW2zAEHq906KCYK1wawMJksyyr uIJJ7JaPJSbUrHZA3lT1l+T8FMhMmL9/97lM1nydni40JTGYdaa1NkkpSOa5y2QV1f JYVBWHCe4AKog== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 3D260682CD for ; Fri, 31 Oct 2025 00:56:33 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893791; bh=m1pthdJRWqoOLSAF9MAwUU/DagXXy44Uz2+25Fjg698=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aC8acGlw07lraGo2zNTlKuZpj3vEXJFXoQNedOUJcAx129CSuWdYQlhpipjQkZh5V WC2fGPBJnfk14sAya5jFB6MsEngLG+y5enEI7yXD5oJxPvWval76b4+/PAs2uOOqDy lKGFZ6ziHU04gpxBWbOPVyAw2sv+3KcBoFvHahLvFwmrmCWmFG/JtmxgJjTyNfLi5U V9KQuStmLplGciZhsXdAda3h4sjOKvge+WTUi4Y7FmImVDwdX9WiJyY0AGhXlGsQ39 2L2Bh07ek9q0JC2ZV2UyRk/AzIH3VCK2bM59jVBCF5MVpl0KDkB9rnv5p+MPdbzj3X AIAImGDv67hww== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 1BB9E5FBA9; Fri, 31 Oct 2025 00:56:31 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id bs70CJGUIwZq; Fri, 31 Oct 2025 00:56:31 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893784; bh=Hv3MH9b6rjBP9Ts//ac1iSJq484Id4OOdUwNAUjU4ZI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BXHIOnvTwTCZkjjLSCzJMFYtSG4tSFFWP1b98THNVvTl503YzsFogaJfl40hRxc83 Z5uNr4WymGHN4MgDVY7mQEzfm0dcp3xAAlb9Nb442ZruUEW/+EZsWNGqY8XtWCQ1tq bWRHFqcdebKD0qkVSTD4AWD7EoRzeOnXx0SPBvhTAMtHdJGo05TKGf9u/g5RlrEudO FoWBVY6GupeqssXdCBM1VTfgG8gXpUfu5isOYsIlfId6nszRlEHMYa3shwN1xA3o52 zJAooDpocN1o7Vwj4Nd6xvHZMQ0yY0PlVpmVANla/cHJmjFV1IP1DK68Wv7jZsha8H 35nseZ1WqS7Bg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id BCE65682CD; Fri, 31 Oct 2025 00:56:23 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 31 Oct 2025 00:54:17 -0600 Message-ID: <20251031065439.3251464-22-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251031065439.3251464-1-sjg@u-boot.org> References: <20251031065439.3251464-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 7NVFWFFWNOTWZUPCIQN6DBON7WBQNLBD X-Message-ID-Hash: 7NVFWFFWNOTWZUPCIQN6DBON7WBQNLBD X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 21/24] luks: Enhance blkmap to support LUKSv1 List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Enhance blkmap to support decrypting a partition encrypted with LUKS version 1. This will allow filesystems to access files on the parition. This will be tested once filesystems support is plumbed in. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/block/blkmap.c | 152 +++++++++++++++++++++++++++++++++++++++++ include/blkmap.h | 24 +++++++ 2 files changed, 176 insertions(+) diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c index 34eed1380dc..13a79001979 100644 --- a/drivers/block/blkmap.c +++ b/drivers/block/blkmap.c @@ -9,10 +9,13 @@ #include #include #include +#include #include +#include #include #include #include +#include struct blkmap; @@ -290,6 +293,155 @@ 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/include/blkmap.h b/include/blkmap.h index d53095437fa..a0f46748b92 100644 --- a/include/blkmap.h +++ b/include/blkmap.h @@ -65,6 +65,30 @@ int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, phys_addr_t paddr); +/** + * blkmap_map_crypt() - Map region of encrypted device + * + * Creates a mapping that performs on-the-fly decryption of the specified + * region from another block device. Suitable for LUKS and other encrypted + * block devices. + * + * @dev: Blkmap to create the mapping on + * @blknr: Start block number of the mapping + * @blkcnt: Number of blocks to map + * @lblk: The target block device containing encrypted data + * @lblknr: The start block number of the encrypted partition + * @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 + * @use_essiv: True to use ESSIV mode, false for plain64 mode + * @essiv_key: ESSIV key (SHA256 of master key), or NULL if use_essiv is false + * Returns: 0 on success, negative error code on failure + */ +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); + /** * blkmap_from_label() - Find blkmap from label *