@@ -1293,6 +1293,8 @@ LUKS
M: Simon Glass <sjg@chromium.org>
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
@@ -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
@@ -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
new file mode 100644
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LUKS (Linux Unified Key Setup) command
+ *
+ * Copyright (C) 2025 Canonical Ltd
+ */
+
+#include <blk.h>
+#include <command.h>
+#include <dm.h>
+#include <luks.h>
+#include <part.h>
+
+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 <interface> <dev[:part]> - detect if partition is LUKS encrypted\n"
+ "luks info <interface> <dev[:part]> - 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));
new file mode 100644
@@ -0,0 +1,139 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+.. index::
+ single: luks (command)
+
+luks command
+============
+
+Synopsis
+--------
+
+::
+
+ luks detect <interface> <dev[:part]>
+ luks info <interface> <dev[:part]>
+
+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
@@ -93,6 +93,7 @@ Shell commands
cmd/loads
cmd/loadx
cmd/loady
+ cmd/luks
cmd/meminfo
cmd/mbr
cmd/md
@@ -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;
+}
@@ -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);