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:
@@ -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
|
||||
|
||||
67
cmd/luks.c
Normal file
67
cmd/luks.c
Normal 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
139
doc/usage/cmd/luks.rst
Normal 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
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user