From patchwork Sun Nov 16 21:23:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 723 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org Authentication-Results: mail.u-boot.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=SX5wleO0; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C6AE068641 for ; Sun, 16 Nov 2025 14:24:11 -0700 (MST) 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 yAXjGqJ3uTU0 for ; Sun, 16 Nov 2025 14:24:11 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 3F3C9685F2 for ; Sun, 16 Nov 2025 14:24:11 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5274D685BF for ; Sun, 16 Nov 2025 14:24:09 -0700 (MST) 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 D9_w0hhsqf-E for ; Sun, 16 Nov 2025 14:24:09 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.166.47; helo=mail-io1-f47.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-io1-f47.google.com (mail-io1-f47.google.com [209.85.166.47]) by mail.u-boot.org (Postfix) with ESMTPS id AA6616864A for ; Sun, 16 Nov 2025 14:24:07 -0700 (MST) Received: by mail-io1-f47.google.com with SMTP id ca18e2360f4ac-9486696aafeso285913139f.3 for ; Sun, 16 Nov 2025 13:24:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1763328246; x=1763933046; darn=u-boot.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CPQXVx6Nx0PQ5Wt1eV4uiHIQiTF5mKtSqfiiV/aFwc8=; b=SX5wleO0Ihh1JZnouJp13OT+ojUSMBj8OwMF6oY8XofvQ5HpHt+cvMcwsBEktLjUSv w6I5ZhH6HzJx2A9gwzGe8CvY1VDBEqoDbdAQT21AKV1KiUxPtRps3Y2yfUUZhGUPc8Lc oqXar6sBoEkFUDglw/kFOk9GbqsUDrlWPslo4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763328246; x=1763933046; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=CPQXVx6Nx0PQ5Wt1eV4uiHIQiTF5mKtSqfiiV/aFwc8=; b=XX4kDChNtU4G//21Y3UExGJQDTcwNhag15GULrUP6pedpYn4Zn42HxYwGX6cbBtd5A yeT3pWvv930wBkFHyIjwPBnlvFtk62ilTWeH0D6+jW3YO+nUHnF9FpYSzz65Y6kA5i5u DrOn/nUWfM7HJWbC2xVRdi6gh0Ukkxhp2s7Q6lYFhbg1FKFDVHDlLyWNLmSXUQ/anCed 3KggNgP7EeeLqep+Y1g4nqBVvxG7HP70kNkwy1T6YzbmcjHMoELOlkNWzuPtiq9PcZbU tq8T90zAj1hpaw3BrO7JPZlfy1mZJQLt/+5xXNuTW1/Ow0f9yS66RUz7eelkelY5MwpO H0Cg== X-Gm-Message-State: AOJu0Yz+Mp2FLCJRRMGCreGyrEKPuX6XfXj61gMM5GnHLyz6LdQ03OaJ +v798EoZLuS1Fz2QEcV0RjA2UKDjcxDRzAWqkSKtwXdigPV1ONVMtRyDzC1yCBMrlWWmuQdMu8Z zKgE= X-Gm-Gg: ASbGnct0XGQH2LfL10Zv5zCcp6nyt0OYqY9tdmEZpe2yntS5tkFscHenGymDuzoe7s7 vj+uGJ274DOw44d95Oz5vi/s/SqDB/Fr5CYNKd8XwpqlBOvtQPGqwHxWzHlvPLEDV3KL9GKEnlK SKflB1ydBp46wD12U+hy3SCFwLOhZoQo8sE5amurkslKs1h6gFrmj5YRGuULFtoEGqeF0qfGIGf n80LpuJoAZ+KxdMIpQW4pim6q1IJ7/qk+nHTf3weo7P5tEzVgReHRuESceMYOvwHIig2AJ5Hj6H ya/yjC+c0FJWZEPdynRR8FEPeKNNIkkDuwTi6lauQ6urdahmb71ydvwsuG3je5GDqCqM2D8yQUW 61LT5rPyOgOrWALdwV6rjFY1Z9YJh23BHLqqhcy0R3JZi6On8TzMtcSrUWcsX1meD5AM0q1Oqqx y+u7pv5z+7ZMf9h+m7QU6U2YsY764= X-Google-Smtp-Source: AGHT+IE6Vo6smTfQVFSwUnonx2vm0a1lbRGsVE5jfDLIxKDqQKXBw1DHhHufR1x9dfShjBnGgRa7Dw== X-Received: by 2002:a05:6602:6c0b:b0:945:a6ed:d7a5 with SMTP id ca18e2360f4ac-948e0cdf757mr1362416639f.1.1763328246045; Sun, 16 Nov 2025 13:24:06 -0800 (PST) Received: from chromium.org ([73.34.74.121]) by smtp.gmail.com with ESMTPSA id ca18e2360f4ac-948d2d162dcsm577962339f.13.2025.11.16.13.24.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Nov 2025 13:24:04 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Sun, 16 Nov 2025 14:23:23 -0700 Message-ID: <20251116212334.1603490-10-simon.glass@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251116212334.1603490-1-simon.glass@canonical.com> References: <20251116212334.1603490-1-simon.glass@canonical.com> MIME-Version: 1.0 Message-ID-Hash: ELGQZULUPUWU66CX6L3SVFDO53DRH7M6 X-Message-ID-Hash: ELGQZULUPUWU66CX6L3SVFDO53DRH7M6 X-MailFrom: sjg@chromium.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 09/14] luks: Split LUKSv1 unlock code into a separate function List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Move the LUKSv1-specific unlock logic from luks_unlock() into a new unlock_luks1() function, lining up with the structure used for LUKSv2. Also update unlock_luks1() to use a local key_size variable and only set the output parameter on success. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/block/luks.c | 153 ++++++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 51 deletions(-) diff --git a/drivers/block/luks.c b/drivers/block/luks.c index c23b6f50671..a3c86c5a197 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -323,6 +323,23 @@ static int derive_key_pbkdf2(struct luks1_keyslot *slot, const u8 *pass, return 0; } +/** + * unlock_luks1() - Unlock a LUKSv1 partition + * + * @blk: Block device + * @pinfo: Partition information + * @hdr: LUKS1 header (already read) + * @pass: Passphrase + * @pass_len: Length of passphrase + * @master_key: Buffer to receive master key + * @key_size: Output for key size + * + * Return: 0 on success, -ve on error + */ +static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo, + struct luks1_phdr *hdr, const u8 *pass, size_t pass_len, + u8 *master_key, u32 *key_size); + /** * try_keyslot() - Try to unlock a LUKS key slot with a derived key * @@ -426,62 +443,44 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, return -EACCES; } -int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, - const u8 *pass, size_t pass_len, u8 *master_key, - u32 *key_size) +/** + * unlock_luks1() - Unlock a LUKSv1 partition + * + * Attempts to unlock a LUKSv1 encrypted partition by trying each active + * key slot with the provided passphrase. Uses PBKDF2 for key derivation + * and supports CBC cipher mode with optional ESSIV. + * + * @blk: Block device containing the partition + * @pinfo: Partition information + * @hdr: LUKSv1 header (already read and validated) + * @pass: Passphrase (binary data) + * @pass_len: Length of passphrase in bytes + * @master_key: Buffer to receive unlocked master key (min 128 bytes) + * @key_sizep: Output for master key size in bytes (set only on success) + * + * Return: 0 on success, -ve on error + */ +static int unlock_luks1(struct udevice *blk, struct disk_partition *pinfo, + struct luks1_phdr *hdr, const u8 *pass, size_t pass_len, + u8 *master_key, u32 *key_sizep) { - uint version, split_key_size, km_blocks, hdr_blocks; + uint split_key_size, km_blocks, key_size; u8 *split_key, *derived_key; struct hash_algo *hash_algo; u8 candidate_key[128], *km; mbedtls_md_type_t md_type; - struct luks1_phdr *hdr; struct blk_desc *desc; int i, ret; - if (!blk || !pinfo || !pass || !master_key || !key_size) - return -EINVAL; - desc = dev_get_uclass_plat(blk); - /* LUKS1 header is 592 bytes, calculate blocks needed */ - hdr_blocks = (sizeof(struct luks1_phdr) + desc->blksz - 1) / - desc->blksz; - - /* Allocate buffer for LUKS header */ - ALLOC_CACHE_ALIGN_BUFFER(u8, buffer, hdr_blocks * desc->blksz); - - /* Read LUKS header */ - if (blk_read(blk, pinfo->start, hdr_blocks, buffer) != hdr_blocks) { - log_debug("failed to read LUKS header\n"); - return -EIO; - } - - /* Verify it's LUKS */ - if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN) != 0) { - log_debug("not a LUKS partition\n"); - return -ENOENT; - } - - version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); - if (version == LUKS_VERSION_2) - return unlock_luks2(blk, pinfo, pass, pass_len, master_key, - key_size); - - if (version != LUKS_VERSION_1) { - log_debug("unsupported LUKS version %d\n", version); - return -ENOTSUPP; - } - - hdr = (struct luks1_phdr *)buffer; - /* Debug: show what we read from header */ log_debug("Read header at sector %llu, mk_digest[0-7] ", (unsigned long long)pinfo->start); log_debug_hex("", (u8 *)hdr->mk_digest, 8); /* Verify cipher mode - only CBC supported */ - if (strncmp(hdr->cipher_mode, "cbc", 3) != 0) { + if (strncmp(hdr->cipher_mode, "cbc", 3)) { log_debug("only CBC mode is currently supported (got: %.32s)\n", hdr->cipher_mode); return -ENOTSUPP; @@ -495,11 +494,11 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, } md_type = hash_mbedtls_type(hash_algo); - - *key_size = be32_to_cpu(hdr->key_bytes); + key_size = be32_to_cpu(hdr->key_bytes); /* Find the first active slot to get the stripes value */ u32 stripes = 0; + for (i = 0; i < LUKS_NUMKEYS; i++) { if (be32_to_cpu(hdr->key_slot[i].active) == LUKS_KEY_ENABLED) { stripes = be32_to_cpu(hdr->key_slot[i].stripes); @@ -511,13 +510,11 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, return -ENOENT; } - split_key_size = *key_size * stripes; - - log_debug("Trying to unlock LUKS partition: key size: %u bytes\n", - *key_size); + split_key_size = key_size * stripes; + log_debug("Unlocking LUKS partition: key size: %u bytes\n", key_size); /* Allocate buffers */ - derived_key = malloc(*key_size); + derived_key = malloc(key_size); split_key = malloc(split_key_size); km_blocks = (split_key_size + desc->blksz - 1) / desc->blksz; km = malloc_cache_aligned(km_blocks * desc->blksz); @@ -537,18 +534,19 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, /* Derive key for this slot */ ret = derive_key_pbkdf2(slot, pass, pass_len, md_type, - *key_size, derived_key); + key_size, derived_key); if (ret) continue; /* Try to unlock with the derived key */ - ret = try_keyslot(blk, pinfo, hdr, i, md_type, *key_size, + ret = try_keyslot(blk, pinfo, hdr, i, md_type, key_size, derived_key, km, km_blocks, split_key, candidate_key); if (!ret) { /* Successfully unlocked */ - memcpy(master_key, candidate_key, *key_size); + memcpy(master_key, candidate_key, key_size); + *key_sizep = key_size; goto out; } /* Continue trying other slots on failure */ @@ -559,7 +557,7 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, out: if (derived_key) { - memset(derived_key, '\0', *key_size); + memset(derived_key, '\0', key_size); free(derived_key); } if (split_key) { @@ -575,6 +573,59 @@ out: return ret; } +int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, + const u8 *pass, size_t pass_len, u8 *master_key, u32 *key_sizep) +{ + uint version, hdr_blocks; + struct luks1_phdr *hdr; + struct blk_desc *desc; + int ret; + + if (!blk || !pinfo || !pass || !master_key || !key_sizep) + return -EINVAL; + + desc = dev_get_uclass_plat(blk); + + /* LUKS1 header is 592 bytes, calculate blocks needed */ + hdr_blocks = (sizeof(struct luks1_phdr) + desc->blksz - 1) / + desc->blksz; + + /* Allocate buffer for LUKS header */ + ALLOC_CACHE_ALIGN_BUFFER(u8, buffer, hdr_blocks * desc->blksz); + + /* Read LUKS header */ + if (blk_read(blk, pinfo->start, hdr_blocks, buffer) != hdr_blocks) { + log_debug("failed to read LUKS header\n"); + return -EIO; + } + + /* Verify it's LUKS */ + if (memcmp(buffer, LUKS_MAGIC, LUKS_MAGIC_LEN) != 0) { + log_debug("not a LUKS partition\n"); + return -ENOENT; + } + + version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); + switch (version) { + case LUKS_VERSION_1: + hdr = (struct luks1_phdr *)buffer; + ret = unlock_luks1(blk, pinfo, hdr, pass, pass_len, master_key, + key_sizep); + break; + case LUKS_VERSION_2: + ret = unlock_luks2(blk, pinfo, pass, pass_len, master_key, + key_sizep); + break; + default: + log_debug("unsupported LUKS version %d\n", version); + return -ENOTSUPP; + } + if (ret) + return ret; + + return 0; +} + int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, const u8 *master_key, u32 key_size, const char *label, struct udevice **blkmapp)