From patchwork Fri Oct 31 06:54:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 673 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893797; bh=u31eW1lNMDLkXOw7Y92UJWKSXD16+dBeTbiE3iSC25c=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=kE8peyJzNfclMcEo2K8Z/g5J4orfY9828Ej1K/Otouu+0eS0W1+ddRT9d9M+JtglX opCB02Ss3uTFC3tc07qBGHOV1RgVJLNLjpQY/yJFyn0DzgXUrGtmnVhgehaYGJyAOj 2d2RJbI0ZNxqzKluCwrmj5X8kvTJ51ggt5QySiKhqoWWcVAw14YBhN94FzWtJnuGmK mOPeVyfdffQ+ZxMGdfSA5gDZqInsDOLWI55P0Z+bXplJzdRWmRLa1nzEa+p+Vw2m0q WxFLYL28oiWzhwojUgtk/V7l9bMiPDYa6yK5mS/bLDHLoj+9JRi5WjqYLNe8XHaPTz l7hzbxa/CF/iw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DE3665FBA9 for ; Fri, 31 Oct 2025 00:56:37 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id f9YE864zxGQl for ; Fri, 31 Oct 2025 00:56:37 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893796; bh=u31eW1lNMDLkXOw7Y92UJWKSXD16+dBeTbiE3iSC25c=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=PP7+AA7fDjI4BJfeC+hDxxTBm31ASpwaFFB4PmM+QAIa0SN2/amXc2KkYvMm0+Ipb yo72yY+q5tsAD64tvXaPRFCrUgl6H1ziwRSWy/OtQdXMpqSLYjyaa94zGbe5VBNt9P fe5fYHKgxQACLUC95H7UUMh7n9+K3JjTAi7XYHEhE8HhTd43YhQKipLv1xxbrq5n7I Gi2q/cLwXwFaaS5uGJwxAYiJBia4tTD0zlAK2H+dGTaZwjqYfCHQgE/YuO1esFAWXb jL5r2bxRO+R1P2j+AFgq0SSIw91aWqBDnBXDL33LKlIxkA28ZDa6XLgx55bbjDtPQi Gyi4EFg8M9OAw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 73DE0682E9 for ; Fri, 31 Oct 2025 00:56:36 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893795; bh=1aoD2XZGli+KmETGNDOrcaFDD+MZj0kM+deiRyGwODo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SiYT6m6MqETPhWnMAzzr4oxe3AsdCFBIuS6CcEwqoJquVYDAearKGxuh6dipUyzrd TAEVv2bPqIaaHcUh3nhrYe5I0vtdRjZQ4s4GjJafIhr/4J6Gz1EIMPC1R4kUACKCGd M4b6ZpBZMP2ALYUn6wLVW8K0RvKD/w4ymSmpO3Y9Ji64hAttapxwKcs6lcAaKqDol2 u1m+lvrTTN4dEgkaOAL/WoYgOxI7Rvr6E6K9qq5Eg26CQv0qqRi/rSnoGHunv8Xwkc PmQQ0u42TNe29QxPgNo7E0eHZCyoUomSEczMjMvOp+pKXuveBcGdWDiuSOgoYfgdYa SOtlSGrAxX8Yg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8DD3F5FBA9; Fri, 31 Oct 2025 00:56:35 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id czVi9ayI8b3f; Fri, 31 Oct 2025 00:56:35 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1761893790; bh=bpOzNwnuhD1VxMa4AtvC8LwGGwRXKoXqZNyz1o1xTag=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k523nJbDDLAEnW9wfm3FFvWeryWJQiP8s4eTj06h119cTsdPXxO4ab39AGR/AVtnp EHtiDh+QrfSKChznLL+8hGK1rOa0NpAu0nYgJUUKnJQzJ7gkY5hxwdiP/ShBBgDfyh ylN0N52qqhJcwELzy2v9KQ44OAaDbrBbzvDC98q27r6OzdjuB9je094gkUWhGR3kGL 5vh2USDm3/GbJ6YEBtagk6Rw9ebmxQWQ7on0umEx+NfaxcvuLtLWwAdIzw9GssTNEp 375y+r1azLqbsTErZcDit9dzxMgVQDYZ/a+VPnVY9kb5iMntFsLhT1WcKjxd7r/pHD VZSl9nYxtpiOg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id BCE96682E9; Fri, 31 Oct 2025 00:56:29 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 31 Oct 2025 00:54:19 -0600 Message-ID: <20251031065439.3251464-24-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251031065439.3251464-1-sjg@u-boot.org> References: <20251031065439.3251464-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: UBZ6OAHW4ZSZ7AIUBKK3NNI3BKHZL47P X-Message-ID-Hash: UBZ6OAHW4ZSZ7AIUBKK3NNI3BKHZL47P X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 23/24] luks: Add a subcommand to unlock an encrypted partition List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Provide a new 'luks unlock' command which can unlock a LUKS1 partition, given a passphrase. Co-developed-by: Claude Signed-off-by: Simon Glass --- cmd/luks.c | 70 ++++++++++++++++++++++++++++++++- doc/usage/cmd/luks.rst | 87 +++++++++++++++++++++++++++++++++++++++++- test/boot/luks.c | 26 +++++++++++++ 3 files changed, 180 insertions(+), 3 deletions(-) diff --git a/cmd/luks.c b/cmd/luks.c index 04ddcdb1d46..19f909be96b 100644 --- a/cmd/luks.c +++ b/cmd/luks.c @@ -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 - detect if partition is LUKS encrypted\n" - "luks info - show LUKS header information"; + "luks info - show LUKS header information\n" + "luks unlock - 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)); diff --git a/doc/usage/cmd/luks.rst b/doc/usage/cmd/luks.rst index c3b03eeff2e..8dbcb8549c7 100644 --- a/doc/usage/cmd/luks.rst +++ b/doc/usage/cmd/luks.rst @@ -13,11 +13,12 @@ Synopsis luks detect luks info + luks unlock 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 diff --git a/test/boot/luks.c b/test/boot/luks.c index 70ee0fb0824..afa8c9f172e 100644 --- a/test/boot/luks.c +++ b/test/boot/luks.c @@ -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);