From patchwork Fri Oct 31 06:54:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 666 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=1761893773; bh=gW3bv6xV1PUvQ7wh4me9spYT/gg3Ynt/TVBdfs0SKps=; 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=tDgMpfd+qKpJAmnAv+pHUQYoWUaKAxHW43+2gMXBzO9kanL7ICvnIOuAFzF4pZbPE ORUP8ZRdIXJsGEmxlcXzBa1yRU5hpPOCvwdYSXLM1DxlBhEF5xLSXQShM4ibmFDkBY hO4SzsPuOoZFvruZ+a+UYF8A6SnjeOUSFGNt2WeBnxD4BOsbN3B8OSaUm4FwjK83q/ VWmQYGSv9i4bAp4GgX8fthB0jA8Ig8228XhRO9skKIQEwWGjGzisL5NvWiB6Fkw7XC 3jZO7938QsXVV+uR4H2IB4QcE1Pxb2U/8/MC6JCHe35LOR2E/tGeXv2aJ6DIgwZVGt 5WPVEg4+f+diQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id ECAA068346 for ; Fri, 31 Oct 2025 00:56:13 -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 hPdB4sPiQ7lq for ; Fri, 31 Oct 2025 00:56:13 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893773; bh=gW3bv6xV1PUvQ7wh4me9spYT/gg3Ynt/TVBdfs0SKps=; 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=tDgMpfd+qKpJAmnAv+pHUQYoWUaKAxHW43+2gMXBzO9kanL7ICvnIOuAFzF4pZbPE ORUP8ZRdIXJsGEmxlcXzBa1yRU5hpPOCvwdYSXLM1DxlBhEF5xLSXQShM4ibmFDkBY hO4SzsPuOoZFvruZ+a+UYF8A6SnjeOUSFGNt2WeBnxD4BOsbN3B8OSaUm4FwjK83q/ VWmQYGSv9i4bAp4GgX8fthB0jA8Ig8228XhRO9skKIQEwWGjGzisL5NvWiB6Fkw7XC 3jZO7938QsXVV+uR4H2IB4QcE1Pxb2U/8/MC6JCHe35LOR2E/tGeXv2aJ6DIgwZVGt 5WPVEg4+f+diQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DC45B682E9 for ; Fri, 31 Oct 2025 00:56:13 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893771; bh=AI0GrIMqLs85enUW+qgKbp1rU5oSBugsv30DZcJ8/o8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=etcbZzuv7yOMs960+ILatrZmoXAMFwZIMB/eFqZxmOrZvvi4U4r0W7YItnhg6rjnB 4sqPLvOcIneU8kG9TvE3YsigG+XB7DFKxRj+xXWxpKuUugIhGa0t9LwHigYn/MVkbU r2VDiIYIL5eI3oQS6ZIAgkkfoZxfQ507PPoTUbGSHp67mk0CtWom/O07imIfRgQwde GN9pHzmzCqb2usLGr7lrW5310TM52i8wabAg6xrQ3THDvlw69L7bOmOp59Up6cDMz6 9XTRPq/EJGBpzrDju5t/SDZPb30/lUJCOTy2ZrQs8zuxzLYfo7xyFHz/OtdVJo+Dsw PgOcHjHIE7scg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E0C18682CD; Fri, 31 Oct 2025 00:56:11 -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 H_ZIAgHhl4YG; Fri, 31 Oct 2025 00:56:11 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893767; bh=n1AYld88K4LfTsT2SsS4cU/52rgureCPilG38kOonfw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CgZ6PxpE6FndWP5NVVPl5wye4g8kNGgimoXAc3gZwsCr4vUkLNB0lPTez1uYsqLyq 9ZTHwmQ90g+ClDpUUVWKkkq8Y7ODKEqV3HruVTLdw2Guah6Q1k4MhetxtIYl86NW8H NF+DbawjX0V8xgLjdSqaCkJd5Z5VFqv9ivXn0PDdtRiSAySTiAsQ71DmLeVCV1mOg+ ROD4AnJVhfg/YOZlRqjcTMiW3WFBnszu1VoGi/4ReD6nBQJBfHD4hnvSHCX64ySMSN hy/tg8t8GNcbe0GjQR8IF1f2voSthcS+MVPJFrCC2S2mHqPoZhmo/Tp3RfKpkgmFy+ CYrm+Np+vLtlA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 667065FBA9; Fri, 31 Oct 2025 00:56:07 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 31 Oct 2025 00:54:12 -0600 Message-ID: <20251031065439.3251464-17-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: NJDBI4A56IFMEMVFZ6IHMNMGPGM4F5FL X-Message-ID-Hash: NJDBI4A56IFMEMVFZ6IHMNMGPGM4F5FL 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 16/24] luks: Add the beginning of LUKS support 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 Linux Unified Key Setup (LUKS) provides a way to encryption a disk partition with a a key an later unlock it. There are two versions (1 and 2). Add a definition of the main structures and the ability to detect a LUKS partition. Enable this for the sandbox board. Co-developed-by: Claude Signed-off-by: Simon Glass --- MAINTAINERS | 8 +++ configs/sandbox_defconfig | 1 + drivers/block/Kconfig | 21 ++++++ drivers/block/Makefile | 1 + drivers/block/luks.c | 63 +++++++++++++++++ include/luks.h | 140 ++++++++++++++++++++++++++++++++++++++ test/boot/Makefile | 1 + test/boot/luks.c | 67 ++++++++++++++++++ 8 files changed, 302 insertions(+) create mode 100644 drivers/block/luks.c create mode 100644 include/luks.h create mode 100644 test/boot/luks.c diff --git a/MAINTAINERS b/MAINTAINERS index 2a2a42aec5e..08d3806b6c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1289,6 +1289,14 @@ F: lib/getopt.c F: test/log/ F: test/py/tests/test_log.py +LUKS +M: Simon Glass +S: Maintained +T: git https://concept.u-boot.org/u-boot/u-boot.git +F: drivers/block/luks.c +F: include/luks.h +F: test/boot/luks.c + MALI DISPLAY PROCESSORS M: Liviu Dudau S: Supported diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 601afde421d..6a4b3e4363a 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -362,6 +362,7 @@ CONFIG_ADDR_MAP=y CONFIG_PANIC_POWEROFF=y CONFIG_CMD_DHRYSTONE=y CONFIG_MBEDTLS_LIB=y +CONFIG_BLK_LUKS=y CONFIG_ECDSA=y CONFIG_ECDSA_VERIFY=y CONFIG_TPM=y diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index adf13f2a243..b07012ec7c9 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -269,3 +269,24 @@ config RKMTD Enable "rkmtd" class and driver to create a virtual block device to transfer Rockchip boot block data to and from NAND with block orientate tools like "ums" and "rockusb". + +config BLK_LUKS + bool "Enable LUKS detection and decryption support" + depends on BLK && MBEDTLS_LIB + select BLKMAP + select AES + select SHA256 + select PBKDF2 + select PKCS5_MBEDTLS if MBEDTLS_LIB_CRYPTO + help + This provides support for detecting and decrypting LUKS (Linux Unified + Key Setup) encrypted partitions. LUKS is a disk encryption specification + used for full disk encryption on Linux systems. + + This option enables detection of both LUKS1 and LUKS2 encrypted + partitions by checking for the LUKS magic bytes and version + information in the partition header. + + LUKS1 decryption is supported using PBKDF2 key derivation and AES-CBC. + Decrypted partitions can be accessed transparently through the blkmap + device layer. diff --git a/drivers/block/Makefile b/drivers/block/Makefile index f5a9d8637a3..b428a5cfb78 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,6 +11,7 @@ endif ifndef CONFIG_XPL_BUILD obj-$(CONFIG_IDE) += ide.o +obj-$(CONFIG_BLK_LUKS) += luks.o obj-$(CONFIG_RKMTD) += rkmtd.o endif obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o diff --git a/drivers/block/luks.c b/drivers/block/luks.c new file mode 100644 index 00000000000..189226cb0ab --- /dev/null +++ b/drivers/block/luks.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LUKS (Linux Unified Key Setup) filesystem support + * + * Copyright (C) 2025 Canonical Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int luks_get_version(struct udevice *blk, struct disk_partition *pinfo) +{ + struct blk_desc *desc; + int version; + + desc = dev_get_uclass_plat(blk); + + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, desc->blksz); + + /* Read first block of the partition */ + if (blk_dread(desc, pinfo->start, 1, buffer) != 1) { + log_debug("Error: failed to read LUKS header\n"); + return -EIO; + } + + /* Check for LUKS magic bytes */ + if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN)) + return -ENOENT; + + /* Read version field (16-bit big-endian at offset 6) */ + version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); + + /* Validate version */ + if (version != LUKS_VERSION_1 && version != LUKS_VERSION_2) { + log_debug("Warning: unknown LUKS version %d\n", version); + return -EPROTONOSUPPORT; + } + + return version; +} + +int luks_detect(struct udevice *blk, struct disk_partition *pinfo) +{ + int version; + + version = luks_get_version(blk, pinfo); + if (IS_ERR_VALUE(version)) + return version; + + return 0; +} diff --git a/include/luks.h b/include/luks.h new file mode 100644 index 00000000000..ea6dd510c53 --- /dev/null +++ b/include/luks.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * LUKS (Linux Unified Key Setup) filesystem support + * + * Copyright (C) 2025 Canonical Ltd + */ + +#ifndef __LUKS_H__ +#define __LUKS_H__ + +#include + +struct udevice; +struct disk_partition; + +/* LUKS magic bytes: "LUKS" followed by 0xba 0xbe */ +#define LUKS_MAGIC "LUKS\xba\xbe" +#define LUKS_MAGIC_LEN 6 + +/* LUKS versions */ +#define LUKS_VERSION_1 1 +#define LUKS_VERSION_2 2 + +/* LUKS constants */ +#define LUKS_DIGESTSIZE 20 +#define LUKS_SALTSIZE 32 +#define LUKS_NUMKEYS 8 +#define LUKS_KEY_DISABLED 0x0000dead +#define LUKS_KEY_ENABLED 0x00ac71f3 +#define LUKS_STRIPES 4000 + +/** + * struct luks1_keyslot - LUKS1 key slot + * + * @active: Key slot state (LUKS_KEY_ENABLED/DISABLED) + * @iterations: PBKDF2 iteration count + * @salt: Salt for PBKDF2 + * @key_material_offset: Start sector of key material + * @stripes: Number of anti-forensic stripes + */ +struct luks1_keyslot { + __be32 active; + __be32 iterations; + char salt[LUKS_SALTSIZE]; + __be32 key_material_offset; + __be32 stripes; +} __packed; + +/** + * struct luks1_phdr - LUKS1 header structure + * + * @magic: LUKS magic bytes + * @version: LUKS version + * @cipher_name: Cipher name + * @cipher_mode: Cipher mode + * @hash_spec: Hash specification + * @payload_offset: Payload offset in sectors + * @key_bytes: Key length in bytes + * @mk_digest: Master key digest + * @mk_digest_salt: Salt for master key digest + * @mk_digest_iter: Iterations for master key digest + * @uuid: Partition UUID + * @key_slot: Key slots (8 total) + */ +struct luks1_phdr { + char magic[LUKS_MAGIC_LEN]; + __be16 version; + char cipher_name[32]; + char cipher_mode[32]; + char hash_spec[32]; + __be32 payload_offset; + __be32 key_bytes; + char mk_digest[LUKS_DIGESTSIZE]; + char mk_digest_salt[LUKS_SALTSIZE]; + __be32 mk_digest_iter; + char uuid[40]; + struct luks1_keyslot key_slot[LUKS_NUMKEYS]; +} __packed; + +/** + * struct luks2_hdr - LUKS2 binary header + * + * @magic: LUKS magic bytes + * @version: LUKS version + * @hdr_size: Header size (includes binary header + JSON area) + * @seqid: Sequence ID + * @label: Label string + * @csum_alg: Checksum algorithm + * @salt: Salt for header checksum + * @uuid: Partition UUID + * @subsystem: Subsystem identifier + * @hdr_offset: Offset of this header + * @_padding: Reserved padding + * @csum: Header checksum + * @_padding4096: Padding to 4096 bytes + */ +struct luks2_hdr { + char magic[LUKS_MAGIC_LEN]; + __be16 version; + __be64 hdr_size; + __be64 seqid; + char label[48]; + char csum_alg[32]; + u8 salt[64]; + char uuid[40]; + char subsystem[48]; + __be64 hdr_offset; + u8 _padding[184]; + u8 csum[64]; + u8 _padding4096[3584]; +} __packed; + +/** + * luks_detect() - Detect if a partition is LUKS encrypted + * + * @blk: Block device + * @pinfo: Partition information + * Return: 0 if LUKS partition detected, -ve on error + */ +int luks_detect(struct udevice *blk, struct disk_partition *pinfo); + +/** + * luks_get_version() - Get LUKS version of a partition + * + * @blk: Block device + * @pinfo: Partition information + * Return: LUKS version (1 or 2) if detected, -ve on error + */ +int luks_get_version(struct udevice *blk, struct disk_partition *pinfo); + +/** + * luks_show_info() - Display LUKS header information + * + * @blk: Block device + * @pinfo: Partition information + * Return: 0 on success, -ve on error + */ +int luks_show_info(struct udevice *blk, struct disk_partition *pinfo); + +#endif /* __LUKS_H__ */ diff --git a/test/boot/Makefile b/test/boot/Makefile index 7c492ba92af..71c482f8d24 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -5,6 +5,7 @@ ifdef CONFIG_UT_BOOTSTD obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o obj-$(CONFIG_FIT) += image.o +obj-$(CONFIG_BLK_LUKS) += luks.o obj-$(CONFIG_EXPO) += expo.o expo_common.o obj-$(CONFIG_CEDIT) += cedit.o expo_common.o diff --git a/test/boot/luks.c b/test/boot/luks.c new file mode 100644 index 00000000000..684fd643c3a --- /dev/null +++ b/test/boot/luks.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for LUKS detection + * + * Copyright (C) 2025 Canonical Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* Common function to setup mmc11 device */ +static int setup_mmc11(struct unit_test_state *uts, struct udevice **mmcp) +{ + ofnode root, node; + + /* Enable the mmc11 node */ + root = oftree_root(oftree_default()); + node = ofnode_find_subnode(root, "mmc11"); + ut_assert(ofnode_valid(node)); + ut_assertok(lists_bind_fdt(gd->dm_root, node, mmcp, NULL, false)); + + /* Probe the device */ + ut_assertok(device_probe(*mmcp)); + + return 0; +} + +/* Test LUKS detection on mmc11 partitions */ +static int bootstd_test_luks_detect(struct unit_test_state *uts) +{ + struct disk_partition info; + struct blk_desc *desc; + struct udevice *mmc; + int ret; + + ut_assertok(setup_mmc11(uts, &mmc)); + desc = blk_get_by_device(mmc); + ut_assertnonnull(desc); + ut_assertnonnull(desc->bdev); + + /* Check partition 1 - should NOT be LUKS */ + ut_assertok(part_get_info(desc, 1, &info)); + ret = luks_detect(desc->bdev, &info); + ut_assert(ret < 0); /* Should fail - not LUKS */ + + /* Check partition 2 - should BE LUKS */ + ut_assertok(part_get_info(desc, 2, &info)); + ut_assertok(luks_detect(desc->bdev, &info)); + + /* Verify it's LUKS version 1 */ + ut_asserteq(1, luks_get_version(desc->bdev, &info)); + + return 0; +} +BOOTSTD_TEST(bootstd_test_luks_detect, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);