luks: Add a simple command

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 <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-10-23 12:46:49 +01:00
parent 8410d62604
commit 414baddf37
8 changed files with 315 additions and 5 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

67
cmd/luks.c Normal file
View File

@@ -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));

139
doc/usage/cmd/luks.rst Normal file
View File

@@ -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

View File

@@ -93,6 +93,7 @@ Shell commands
cmd/loads
cmd/loadx
cmd/loady
cmd/luks
cmd/meminfo
cmd/mbr
cmd/md

View File

@@ -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;
}

View File

@@ -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);