@@ -57,11 +57,77 @@ static int do_luks_info(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_SUCCESS;
}
+static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct blk_desc *dev_desc;
+ struct disk_partition info;
+ struct udevice *blkmap_dev;
+ const char *passphrase;
+ int part, ret, version;
+ u8 master_key[128];
+ char label[64];
+ u32 key_size;
+
+ if (argc != 4)
+ 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;
+
+ passphrase = argv[3];
+
+ /* Verify it's a LUKS partition */
+ version = luks_get_version(dev_desc->bdev, &info);
+ if (version < 0) {
+ printf("Not a LUKS partition\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (version != LUKS_VERSION_1) {
+ printf("Only LUKS1 is currently supported\n");
+ return CMD_RET_FAILURE;
+ }
+
+ /* Unlock the partition to get the master key */
+ ret = luks_unlock(dev_desc->bdev, &info, passphrase, master_key,
+ &key_size);
+ if (ret) {
+ printf("Failed to unlock LUKS partition (err %dE)\n", ret);
+ return CMD_RET_FAILURE;
+ }
+
+ /* Create blkmap device with label based on source device */
+ snprintf(label, sizeof(label), "luks-%s-%s", argv[1], argv[2]);
+
+ /* Create and map the blkmap device */
+ ret = luks_create_blkmap(dev_desc->bdev, &info, master_key, key_size,
+ label, &blkmap_dev);
+ if (ret) {
+ printf("Failed to create blkmap device (err %dE)\n", ret);
+ ret = CMD_RET_FAILURE;
+ goto cleanup;
+ }
+
+ printf("Unlocked LUKS partition as blkmap device '%s'\n", label);
+
+ ret = CMD_RET_SUCCESS;
+
+cleanup:
+ /* Wipe master key from stack */
+ memset(master_key, '\0', sizeof(master_key));
+
+ return ret;
+}
+
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";
+ "luks info <interface> <dev[:part]> - show LUKS header information\n"
+ "luks unlock <interface> <dev[:part]> <passphrase> - unlock LUKS partition\n";
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));
+ U_BOOT_SUBCMD_MKENT(info, 3, 1, do_luks_info),
+ U_BOOT_SUBCMD_MKENT(unlock, 4, 1, do_luks_unlock));
@@ -13,11 +13,12 @@ Synopsis
luks detect <interface> <dev[:part]>
luks info <interface> <dev[:part]>
+ luks unlock <interface> <dev[:part]> <passphrase>
Description
-----------
-The *luks* command provides an interface to detect and inspect LUKS
+The *luks* command provides an interface to detect, inspect, and unlock LUKS
(Linux Unified Key Setup) encrypted partitions. LUKS is a disk encryption
specification used for full disk encryption on Linux systems.
@@ -25,6 +26,7 @@ This command supports:
* Detection of LUKS encrypted partitions (LUKS1 and LUKS2)
* Display of LUKS header information
+* Unlocking LUKS1 partitions with passphrase-based authentication
* Access to decrypted data via blkmap devices
The LUKS format uses a distinctive header containing:
@@ -83,6 +85,42 @@ dev[:part]
The device number and optional partition number. If partition is omitted,
defaults to the whole device.
+luks unlock
+~~~~~~~~~~~
+
+Unlock a LUKS1 encrypted partition using a passphrase. This command:
+
+1. Verifies the partition is LUKS1 encrypted
+2. Derives the encryption key using PBKDF2 with the provided passphrase
+3. Attempts to unlock each active key slot
+4. Verifies the master key against the stored digest
+5. Creates a blkmap device providing on-the-fly decryption
+
+After successful unlock, the decrypted data is accessible through a blkmap
+device (typically ``blkmap 0``). Standard U-Boot filesystem commands can then
+be used to access files on the unlocked partition.
+
+**Currently only LUKS1 is supported for unlocking. LUKS2 unlock is not yet
+implemented.**
+
+Supported cipher modes:
+
+* aes-cbc-essiv:sha256 (AES in CBC mode with ESSIV)
+
+interface
+ The storage interface type (e.g., mmc, usb, scsi)
+
+dev[:part]
+ The device number and optional partition number
+
+passphrase
+ The passphrase to unlock the LUKS partition. Note that the passphrase is
+ passed as a command-line argument and may be visible in command history.
+ Consider using environment variables to minimize exposure.
+
+The unlocked data remains accessible until U-Boot exits or the blkmap device
+is explicitly destroyed.
+
Examples
--------
@@ -145,6 +183,40 @@ Display LUKS header information for a LUKS1 partition::
Payload offset: 4096 sectors
Key bytes: 32
+Unlock a LUKS1 partition and access files::
+
+ => luks unlock mmc 0:2 mypassword
+ Trying to unlock LUKS partition...
+ Key size: 32 bytes
+ Trying key slot 0...
+ Successfully unlocked with key slot 0!
+ Unlocked LUKS partition as blkmap device 'luks-mmc-0:2'
+ Access decrypted data via: blkmap 0
+
+ => ls blkmap 0 /
+ ./
+ ../
+ lost+found/
+ 221 README.md
+ 17 hello.txt
+ subdir/
+ 20 test.txt
+
+ 3 file(s), 4 dir(s)
+
+ => cat blkmap 0 /hello.txt
+ Hello from LUKS!
+
+Unlock and load a kernel from encrypted partition::
+
+ => luks unlock mmc 0:2 ${rootfs_password}
+ Successfully unlocked with key slot 0!
+
+ => ext4load blkmap 0 ${kernel_addr_r} /boot/vmlinuz
+ 5242880 bytes read in 123 ms (40.6 MiB/s)
+
+ => bootz ${kernel_addr_r} - ${fdt_addr_r}
+
Configuration
-------------
@@ -155,14 +227,27 @@ For LUKS detection and info commands::
CONFIG_BLK_LUKS=y
CONFIG_CMD_LUKS=y
+For LUKS unlock functionality, additional options are required::
+
+ CONFIG_BLK_LUKS=y
+ CONFIG_CMD_LUKS=y
+ CONFIG_BLKMAP=y # For blkmap device support
+ CONFIG_AES=y # For AES encryption
+ CONFIG_SHA256=y # For SHA-256 hashing
+ CONFIG_PBKDF2=y # For PBKDF2 key derivation
+
Return value
------------
For *detect* and *info*: The return value $? is 0 (true) on success, 1 (false)
on failure.
+For *unlock*: The return value $? is 0 (true) if unlock succeeded, 1 (false)
+if unlock failed (wrong passphrase, unsupported format, etc.).
+
See also
--------
+* :doc:`blkmap` - Blkmap device documentation
* cryptsetup project: https://gitlab.com/cryptsetup/cryptsetup
* LUKS on-disk format specifications: https://gitlab.com/cryptsetup/cryptsetup/-/wikis/home
@@ -213,3 +213,29 @@ static int bootstd_test_luks2_info(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(bootstd_test_luks2_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Test LUKS unlock command with LUKS1 encrypted partition */
+static int bootstd_test_luks_unlock(struct unit_test_state *uts)
+{
+ struct udevice *mmc;
+
+ ut_assertok(setup_mmc11(uts, &mmc));
+
+ /* Test that unlock command exists and handles errors properly */
+ /* Should fail because partition 1 is not LUKS */
+ ut_asserteq(1, run_command("luks unlock mmc b:1 test", 0));
+ ut_assert_nextline("Not a LUKS partition");
+ ut_assert_console_end();
+
+ /* Test unlocking partition 2 with correct passphrase */
+ ut_assertok(run_command("luks unlock mmc b:2 test", 0));
+ ut_assert_nextline("Unlocked LUKS partition as blkmap device 'luks-mmc-b:2'");
+ ut_assert_console_end();
+
+ /* Test unlocking with wrong passphrase */
+ ut_asserteq(1, run_command("luks unlock mmc b:2 wrongpass", 0));
+ ut_assert_skip_to_line("Failed to unlock LUKS partition (err -13: Permission denied)");
+
+ return 0;
+}
+BOOTSTD_TEST(bootstd_test_luks_unlock, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);