From patchwork Fri Oct 31 06:54:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 667 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=1761893779; bh=RnwmytGi0MFXtNQpmxkO6grjCJD82l6tbpaTWxS5tVg=; 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=SCOlvGBNqk9rArFv8ZBdfyKS10CA3AdoYlHNm3vb2610a7ZexmqmWV+xwx3F+rbrO MphXkxOjwDVYa4FN17L/vU0JOY33QpfDc4kdlbQf7cT9QJSBQqs9QPGG/ynDVIU7vP TPykhN4lvnWVXwT6XhOgtiBWaEsGwNWiS7xx7GAYFcgzdIQvQhsJPH9luNmtthIFao SIZJTn1Bj+l/wrizyUvb06a6bSYpf8Q3uwF4wpBrlqv0XBLWaIB9LDMarw3JUngpNW 5MjeSuMxJR0pXizhaU/VMJN8elZHAw9d/T/QZhCLOtIUQ9WzrXKS0o/d6aCWnBt+2M VeAMAUEiPzp5g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4F65768351 for ; Fri, 31 Oct 2025 00:56:19 -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 DKs3g9rqbM4A for ; Fri, 31 Oct 2025 00:56:19 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893779; bh=RnwmytGi0MFXtNQpmxkO6grjCJD82l6tbpaTWxS5tVg=; 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=SCOlvGBNqk9rArFv8ZBdfyKS10CA3AdoYlHNm3vb2610a7ZexmqmWV+xwx3F+rbrO MphXkxOjwDVYa4FN17L/vU0JOY33QpfDc4kdlbQf7cT9QJSBQqs9QPGG/ynDVIU7vP TPykhN4lvnWVXwT6XhOgtiBWaEsGwNWiS7xx7GAYFcgzdIQvQhsJPH9luNmtthIFao SIZJTn1Bj+l/wrizyUvb06a6bSYpf8Q3uwF4wpBrlqv0XBLWaIB9LDMarw3JUngpNW 5MjeSuMxJR0pXizhaU/VMJN8elZHAw9d/T/QZhCLOtIUQ9WzrXKS0o/d6aCWnBt+2M VeAMAUEiPzp5g== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 3EECD682E9 for ; Fri, 31 Oct 2025 00:56:19 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893776; bh=mrLEepDf+hh8TAix/7WqLWQr2Vew0JtTvRPmfIC7Enw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=P24dYx7nlCYG4Wxcn3pCMGceNtyTOYXIQ0dsGt+enpIowwxancVbSPjaf+KF6PB37 qgoSrQlgODWKUEXV4PicOFJQmYIckB0znE+BTNANExJwcMX4nhj4hejNoKSCTeHLwk 9CWlbiUNH8njpRYbDwG5PhkTlRHutIsNMDLytp2NbV0oinkhFHJV+NoH6i+dmCQYgY pUpFIVgc8LUXS9NK6L0r7ZGFXvv7Yf3KPS9lGNvD6A1IR54QZxHq3QiCeuX9ctRGZt Ro93z9OTZJB5T05aDN95raNF+HAWXLdvRfySf6gRcRScECugtu3SolVvPMKdn9bvi9 afvlpKztbZRiQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B03CF682CD; Fri, 31 Oct 2025 00:56:16 -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 eEaEjx7xS9dc; Fri, 31 Oct 2025 00:56:16 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893772; bh=BXkN2GnQsyyCW7D/jUyGzOC99IVV3urclluBDG/hhpA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AAyjW1Q1mjuvNfd/pD7eWbShOYtKcX9C5uyMDMhQ23jRXy8CSBUlmUlr61cxAf4XI z8DRD9PunLecnxP8GwerXGKyN4nknRKgB03eLKBoOr2nlvciy+FVXMzwTQxIxkq6a5 hZEQzBXNV8MnSDoIGrUIWEoDnNbj6xnKy34XbzonCGCngHvjEmscTiOjtVdr0x1mUZ C37Y1e1SFnoZEVKtkdbFKOQ6eZ3CXjy2aY8TEQGaQhOhWH+1pHZWyE0paBpl0aW1sY NIbKgL7YN1o5qrbQh96PAbX9G6BahQDr4u2sBo0m4zI0K89JOuixKly+nqrC9SOG3z X3RdEX0rJNIVQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 310FC5FBA9; Fri, 31 Oct 2025 00:56:12 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 31 Oct 2025 00:54:13 -0600 Message-ID: <20251031065439.3251464-18-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: MFJD3VZKYWG5EY7KCSHHML32KUS6PVG6 X-Message-ID-Hash: MFJD3VZKYWG5EY7KCSHHML32KUS6PVG6 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 17/24] luks: Add a simple command 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 Add a 'luks' command which allows querying a partition to see if it is encrypted using LUKS, as well as showing information about a LUKS partition. Provide some documentation and a test. Co-developed-by: Claude Signed-off-by: Simon Glass --- MAINTAINERS | 2 + cmd/Kconfig | 9 +++ cmd/Makefile | 1 + cmd/luks.c | 67 ++++++++++++++++++++ doc/usage/cmd/luks.rst | 139 +++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + drivers/block/luks.c | 59 +++++++++++++++-- test/boot/luks.c | 42 +++++++++++++ 8 files changed, 315 insertions(+), 5 deletions(-) create mode 100644 cmd/luks.c create mode 100644 doc/usage/cmd/luks.rst diff --git a/MAINTAINERS b/MAINTAINERS index 08d3806b6c7..9b00829db93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1293,6 +1293,8 @@ LUKS M: Simon Glass S: Maintained T: git https://concept.u-boot.org/u-boot/u-boot.git +F: cmd/luks.c +F: doc/usage/cmd/luks.rst F: drivers/block/luks.c F: include/luks.h F: test/boot/luks.c diff --git a/cmd/Kconfig b/cmd/Kconfig index f4d6e544cc0..a45df78c8fd 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2819,6 +2819,15 @@ config CMD_FS_UUID help Enables fsuuid command for filesystem UUID. +config CMD_LUKS + bool "luks command" + depends on BLK_LUKS + default y if BLK_LUKS + help + Enables the 'luks' command for detecting LUKS (Linux Unified Key + Setup) encrypted partitions. This command checks if a partition + is LUKS encrypted and displays the LUKS version (1 or 2). + config CMD_JFFS2 bool "jffs2 command" select FS_JFFS2 diff --git a/cmd/Makefile b/cmd/Makefile index 28e9c261683..2c6a16752bd 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_CMD_SQUASHFS) += sqfs.o obj-$(CONFIG_CMD_SELECT_FONT) += font.o obj-$(CONFIG_CMD_FLASH) += flash.o obj-$(CONFIG_CMD_FPGA) += fpga.o +obj-$(CONFIG_CMD_LUKS) += luks.o obj-$(CONFIG_CMD_FPGAD) += fpgad.o obj-$(CONFIG_CMD_FS_GENERIC) += fs.o obj-$(CONFIG_CMD_FUSE) += fuse.o diff --git a/cmd/luks.c b/cmd/luks.c new file mode 100644 index 00000000000..04ddcdb1d46 --- /dev/null +++ b/cmd/luks.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LUKS (Linux Unified Key Setup) command + * + * Copyright (C) 2025 Canonical Ltd + */ + +#include +#include +#include +#include +#include + +static int do_luks_detect(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct blk_desc *dev_desc; + struct disk_partition info; + int part, ret, version; + + if (argc != 3) + return CMD_RET_USAGE; + + part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); + if (part < 0) + return CMD_RET_FAILURE; + + ret = luks_detect(dev_desc->bdev, &info); + if (ret < 0) { + printf("Not a LUKS partition (error %dE)\n", ret); + return CMD_RET_FAILURE; + } + version = luks_get_version(dev_desc->bdev, &info); + printf("LUKS%d encrypted partition detected\n", version); + + return CMD_RET_SUCCESS; +} + +static int do_luks_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct blk_desc *dev_desc; + struct disk_partition info; + int part, ret; + + if (argc != 3) + return CMD_RET_USAGE; + + part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); + if (part < 0) + return CMD_RET_FAILURE; + + ret = luks_show_info(dev_desc->bdev, &info); + if (ret < 0) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static char luks_help_text[] = + "detect - detect if partition is LUKS encrypted\n" + "luks info - show LUKS header information"; + +U_BOOT_CMD_WITH_SUBCMDS(luks, "LUKS (Linux Unified Key Setup) operations", + luks_help_text, + U_BOOT_SUBCMD_MKENT(detect, 3, 1, do_luks_detect), + U_BOOT_SUBCMD_MKENT(info, 3, 1, do_luks_info)); diff --git a/doc/usage/cmd/luks.rst b/doc/usage/cmd/luks.rst new file mode 100644 index 00000000000..b88fcd96439 --- /dev/null +++ b/doc/usage/cmd/luks.rst @@ -0,0 +1,139 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: luks (command) + +luks command +============ + +Synopsis +-------- + +:: + + luks detect + luks info + +Description +----------- + +The *luks* command provides an interface to detect and inspect LUKS +(Linux Unified Key Setup) encrypted partitions. LUKS is a disk encryption +specification used for full disk encryption on Linux systems. + +This command supports: + +* Detection of LUKS encrypted partitions (LUKS1 and LUKS2) +* Display of LUKS header information +* Access to decrypted data via blkmap devices + +The LUKS format uses a distinctive header containing: + +* Magic bytes: "LUKS" followed by 0xBA 0xBE +* Version information (16-bit big-endian) +* Encryption metadata (cipher, mode, hash specification) + +luks detect +~~~~~~~~~~~ + +Detect whether a specified partition is LUKS encrypted and report its version. + +interface + The storage interface type (e.g., mmc, usb, scsi) + +dev[:part] + The device number and optional partition number. If partition is omitted, + defaults to the whole device. + +luks info +~~~~~~~~~ + +Display detailed header information for a LUKS encrypted partition. This +subcommand reads the LUKS header and displays format-specific metadata. + +For LUKS1 partitions, the following information is displayed: + +* Version number +* Cipher name (encryption algorithm) +* Cipher mode (e.g., xts-plain64) +* Hash specification (e.g., sha256) +* Payload offset (in sectors) +* Key bytes (key size) + +For LUKS2 partitions, the following information is displayed: + +* Version number +* Header size (in bytes) +* Sequence ID (metadata update counter) +* UUID (partition identifier) +* Label (optional partition label) +* Checksum algorithm +* Full JSON metadata containing: + + - keyslots: Encryption key slot information including KDF parameters + - tokens: Optional token metadata + - segments: Encrypted data segment descriptions + - digests: Master key digest information + - config: Configuration parameters + +interface + The storage interface type (e.g., mmc, usb, scsi) + +dev[:part] + The device number and optional partition number. If partition is omitted, + defaults to the whole device. + +Examples +-------- + +Check if MMC device 0 partition 2 is LUKS encrypted:: + + => luks detect mmc 0:2 + LUKS2 encrypted partition detected + +Check a USB device partition:: + + => luks detect usb 0:1 + Not a LUKS partition (error -2: No such file or directory) + +Display LUKS header information for a LUKS2 partition:: + + => luks info mmc 0:2 + Version: 2 + Header size: 16384 bytes + Sequence ID: 3 + UUID: 7640da3a-d0a2-4238-9813-4714e7f62203 + Label: + Checksum alg: sha256 + +Display LUKS header information for a LUKS1 partition:: + + => luks info mmc 1:1 + Version: 1 + Cipher name: aes + Cipher mode: cbc-essiv:sha256 + Hash spec: sha256 + Payload offset: 4096 sectors + Key bytes: 32 + +Configuration +------------- + +The luks command is available when CONFIG_CMD_LUKS is enabled. + +For LUKS detection and info commands:: + + CONFIG_BLK_LUKS=y + CONFIG_CMD_LUKS=y + +Return value +------------ + +For *detect* and *info*: The return value $? is 0 (true) on success, 1 (false) +on failure. + +See also +-------- + +* cryptsetup project: https://gitlab.com/cryptsetup/cryptsetup +* LUKS on-disk format specifications: https://gitlab.com/cryptsetup/cryptsetup/-/wikis/home diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 2fff101868c..2bb01211227 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -93,6 +93,7 @@ Shell commands cmd/loads cmd/loadx cmd/loady + cmd/luks cmd/meminfo cmd/mbr cmd/md diff --git a/drivers/block/luks.c b/drivers/block/luks.c index 189226cb0ab..597359b98ff 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -22,15 +22,13 @@ int luks_get_version(struct udevice *blk, struct disk_partition *pinfo) { - struct blk_desc *desc; + struct blk_desc *desc = dev_get_uclass_plat(blk); + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, desc->blksz); 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) { + if (blk_read(blk, pinfo->start, 1, buffer) != 1) { log_debug("Error: failed to read LUKS header\n"); return -EIO; } @@ -61,3 +59,54 @@ int luks_detect(struct udevice *blk, struct disk_partition *pinfo) return 0; } + +int luks_show_info(struct udevice *blk, struct disk_partition *pinfo) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, desc->blksz); + int version; + + /* Read first block of the partition */ + if (blk_read(blk, pinfo->start, 1, buffer) != 1) { + printf("Error: failed to read LUKS header\n"); + return -EIO; + } + + /* Check for LUKS magic bytes */ + if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN)) { + printf("Not a LUKS partition\n"); + return -ENOENT; + } + + /* Read version field */ + version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); + + printf("Version: %d\n", version); + if (version == LUKS_VERSION_1) { + struct luks1_phdr *luks1_hdr = (struct luks1_phdr *)buffer; + + printf("Cipher name: %.32s\n", luks1_hdr->cipher_name); + printf("Cipher mode: %.32s\n", luks1_hdr->cipher_mode); + printf("Hash spec: %.32s\n", luks1_hdr->hash_spec); + printf("Payload offset: %u sectors\n", + be32_to_cpu(luks1_hdr->payload_offset)); + printf("Key bytes: %u\n", + be32_to_cpu(luks1_hdr->key_bytes)); + } else if (version == LUKS_VERSION_2) { + struct luks2_hdr *luks2_hdr = (struct luks2_hdr *)buffer; + u64 hdr_size; + + hdr_size = be64_to_cpu(luks2_hdr->hdr_size); + + printf("Header size: %llu bytes\n", hdr_size); + printf("Sequence ID: %llu\n", be64_to_cpu(luks2_hdr->seqid)); + printf("UUID: %.40s\n", luks2_hdr->uuid); + printf("Label: %.48s\n", luks2_hdr->label); + printf("Checksum alg: %.32s\n", luks2_hdr->csum_alg); + } else { + printf("Unknown LUKS version\n"); + return -EPROTONOSUPPORT; + } + + return 0; +} diff --git a/test/boot/luks.c b/test/boot/luks.c index 684fd643c3a..fadd3819ffe 100644 --- a/test/boot/luks.c +++ b/test/boot/luks.c @@ -65,3 +65,45 @@ static int bootstd_test_luks_detect(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootstd_test_luks_detect, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Test LUKS command on mmc11 partitions */ +static int bootstd_test_luks_cmd(struct unit_test_state *uts) +{ + struct udevice *mmc; + + ut_assertok(setup_mmc11(uts, &mmc)); + + /* Test partition 1 - should NOT be LUKS */ + ut_asserteq(1, run_command("luks detect mmc b:1", 0)); + ut_assert_nextlinen("Not a LUKS partition (error -"); + ut_assert_console_end(); + + /* Test partition 2 - should BE LUKS */ + ut_assertok(run_command("luks detect mmc b:2", 0)); + ut_assert_nextline("LUKS1 encrypted partition detected"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootstd_test_luks_cmd, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Test LUKS info command on mmc11 partition 2 */ +static int bootstd_test_luks_info(struct unit_test_state *uts) +{ + struct udevice *mmc; + + ut_assertok(setup_mmc11(uts, &mmc)); + + /* Test partition 2 LUKS info */ + ut_assertok(run_command("luks info mmc b:2", 0)); + ut_assert_nextline("Version: 1"); + ut_assert_nextlinen("Cipher name:"); + ut_assert_nextlinen("Cipher mode:"); + ut_assert_nextlinen("Hash spec:"); + ut_assert_nextlinen("Payload offset:"); + ut_assert_nextlinen("Key bytes:"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootstd_test_luks_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);