luks: Add the beginning of LUKS support

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 <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-10-23 12:52:25 +01:00
parent 838f9ce777
commit 8410d62604
8 changed files with 302 additions and 0 deletions

View File

@@ -1289,6 +1289,14 @@ F: lib/getopt.c
F: test/log/
F: test/py/tests/test_log.py
LUKS
M: Simon Glass <sjg@chromium.org>
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 <liviu.dudau@foss.arm.com>
S: Supported

View File

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

View File

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

View File

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

63
drivers/block/luks.c Normal file
View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* LUKS (Linux Unified Key Setup) filesystem support
*
* Copyright (C) 2025 Canonical Ltd
*/
#include <blk.h>
#include <dm.h>
#include <hexdump.h>
#include <log.h>
#include <luks.h>
#include <memalign.h>
#include <part.h>
#include <uboot_aes.h>
#include <linux/byteorder/generic.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
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;
}

140
include/luks.h Normal file
View File

@@ -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 <linux/types.h>
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__ */

View File

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

67
test/boot/luks.c Normal file
View File

@@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Test for LUKS detection
*
* Copyright (C) 2025 Canonical Ltd
*/
#include <blk.h>
#include <dm.h>
#include <luks.h>
#include <mmc.h>
#include <part.h>
#include <asm/global_data.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
#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);