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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
63
drivers/block/luks.c
Normal 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
140
include/luks.h
Normal 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__ */
|
||||
@@ -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
67
test/boot/luks.c
Normal 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);
|
||||
Reference in New Issue
Block a user