From patchwork Sun Nov 16 21:23:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 725 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=H4+09uIf; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id CAE47685C6 for ; Sun, 16 Nov 2025 14:24:19 -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 i7ZJ6UPwIrp1 for ; Sun, 16 Nov 2025 14:24:19 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B716B685BF for ; Sun, 16 Nov 2025 14:24:19 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B7A746858A for ; Sun, 16 Nov 2025 14:24:17 -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 8nqcgPFa-Hk1 for ; Sun, 16 Nov 2025 14:24:17 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.166.50; helo=mail-io1-f50.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-io1-f50.google.com (mail-io1-f50.google.com [209.85.166.50]) by mail.u-boot.org (Postfix) with ESMTPS id E40E3685BF for ; Sun, 16 Nov 2025 14:24:13 -0700 (MST) Received: by mail-io1-f50.google.com with SMTP id ca18e2360f4ac-9486696aafeso285915439f.3 for ; Sun, 16 Nov 2025 13:24:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1763328252; x=1763933052; 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=lzh268hfC5NNlFfm6tftnwRuWbF7DsFZWc2/q9ecKGQ=; b=H4+09uIfOUUXES4LnM1U62Z42uSPOWJHKnwHnan7xrgmtmdI6xz/N5023I64JV4Ab9 rPZo6ORD58yXuK5IybbT5e06+G2XjZFvFFOttMaQW0hviyPiYb8A2FkOYVSB+n6Nrq1k hY1qvcb/fkaM6FWERz3mznELr0IABOvfLoexg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763328252; x=1763933052; 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=lzh268hfC5NNlFfm6tftnwRuWbF7DsFZWc2/q9ecKGQ=; b=jm3jA82U8bnajZO43ingHAmx4yFhq0cp9rOoSaz+/se/zRsd3C1S55Wlnt1Mk6olFs Vaw4jbYL9/3p5Fq0yM+p1UzZ96PB0NDJTQ4V+fF8iE06muHIfH8nN3UNB491dZj9+u95 XVtU++ngxAy/Ne2/J+wv0JN7hhcI8mGMNm1JJ2zMWLLO/ZssfNbcdwIfYd/VrqlE0up/ AJxikrLiQ7D0JfeO7ur6SA4LjDevr2UedAIU7LZOEV3OWvjR4W4Nq0ZXngozrY9+EoOJ X3CscpSs+QsRat4vPBvIGVpLdJMtvhGwkSD8rXyawnG6JwHGGypJ16gTLm6Np7da5T77 CASw== X-Gm-Message-State: AOJu0Yyoro+W0YePlwdwBgcUYvyelc78ecDoTs5Jj4NOR0dXNqHmyqV9 STwUl19IaF/eCYamZslmJtEYEknAk6hnYcEDeLi3CtsodBjpVA5Tsw241/wSdV7dd+N1ASucR+n s8mg= X-Gm-Gg: ASbGncuXaKH8OqIiUX/fVyXnOw21B1gxeNltb5q7tZoTDoU2WcKcQdxt0XzScy18tWc RPU1WGvQi/3kYO5aivuinrK5K2YYi88vC25HlQ4HjeD5H9AHqxjT3IgW+cR+NwQFJnTaVT2mKhg 0iK6yBEzjh0EvbRkJgGe34DvlMSk8Co88e9ACv4wMxQw22hNui1o/Edl6MGeh8jOfXz545Tpd9u VPieNX20bELYjxG9+Suj7T6OCS5MdwKl56yW5SWAqFDcxFH6KPoKmWs8KoQrEarebjCb19z9Lcc 5cSb5RNOzydgp0CX5GfjqdY3JZKwo3Czox0ZtiuMLrtpVR5uHr7Ke7rTQrGBB/1RHdgiHs1radE Ma2wHPhxZUnhD/SSHUYf1kqbeOyrBm+eIL1t7SpjW94bsA9eW1ZeXgJby7TbYzcRB6CFgtNS35t BMbAylrrqfUR4SbBQSNpokC5g99TA= X-Google-Smtp-Source: AGHT+IFPea3CKiIymD8f0GDak78b1cSpMKz8Vg0tkXa2d2cLxaWA00/pUZcP4GXVIyEaDS9GQMc7fw== X-Received: by 2002:a05:6638:6b97:b0:571:2bd0:eb59 with SMTP id 8926c6da1cb9f-5b7c9c7d928mr5759718173.6.1763328251958; Sun, 16 Nov 2025 13:24:11 -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.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Nov 2025 13:24:10 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Sun, 16 Nov 2025 14:23:25 -0700 Message-ID: <20251116212334.1603490-12-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: ZZ2BXLPNGLG5JH2NGORNPBIM5SAPUWST X-Message-ID-Hash: ZZ2BXLPNGLG5JH2NGORNPBIM5SAPUWST 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 11/14] luks: Support a pre-derived key with LUKSv2 List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: In some cases we may wish to provide a pre-derived key, e.g. obtained from a TKey. Provide an option for this with LUKSv2. For now it is not exported. Improve the error-return documentation while we are here. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/block/luks2.c | 54 ++++++++++++++++++++++------------- drivers/block/luks_internal.h | 10 ++++--- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/block/luks2.c b/drivers/block/luks2.c index 57e6b9f37d9..e3f3ac28c34 100644 --- a/drivers/block/luks2.c +++ b/drivers/block/luks2.c @@ -544,9 +544,9 @@ static int decrypt_km_xts(const u8 *derived_key, uint key_size, const u8 *km, * @blksz: Block size in bytes * Return: 0 on success, negative error code on failure */ -static int decrypt_km_cbc(u8 *derived_key, uint key_size, const char *encrypt, - u8 *km, u8 *split_key, int size, int km_blocks, - int blksz) +static int decrypt_km_cbc(const u8 *derived_key, uint key_size, + const char *encrypt, u8 *km, u8 *split_key, + int size, int km_blocks, int blksz) { u8 expkey[AES256_EXPAND_KEY_LENGTH]; @@ -811,7 +811,8 @@ static int verify_master_key(const struct luks2_digest *digest, * * This function attempts to unlock one keyslot by: * 1. Reading keyslot metadata from ofnode - * 2. Deriving the candidate master key using the appropriate KDF + * 2. Deriving the candidate master key using the appropriate KDF (or using + * pre-derived key directly) * 3. Verifying the candidate key against the stored digest * * @blk: Block device containing the LUKS partition @@ -819,7 +820,9 @@ static int verify_master_key(const struct luks2_digest *digest, * @keyslot_node: ofnode for this specific keyslot * @digest: Digest information for verification * @md_type: mbedtls message digest type (for PBKDF2) - * @pass: User-provided passphrase + * @pass: User-provided passphrase or pre-derived key + * @pass_len: Length of passphrase + * @pre_derived: True if pass is a pre-derived key, false for passphrase * @master_key: Output buffer for verified master key * @key_sizep: Returns the key size * Return: 0 if unlocked successfully, -EAGAIN to continue trying, -ve on error @@ -828,8 +831,8 @@ static int try_unlock_keyslot(struct udevice *blk, struct disk_partition *pinfo, ofnode keyslot_node, const struct luks2_digest *digest, mbedtls_md_type_t md_type, const u8 *pass, - size_t pass_len, u8 *master_key, - uint *key_sizep) + size_t pass_len, bool pre_derived, + u8 *master_key, uint *key_sizep) { struct luks2_keyslot keyslot; u8 cand_key[128]; @@ -845,16 +848,27 @@ static int try_unlock_keyslot(struct udevice *blk, struct disk_partition *pinfo, log_debug("LUKS2: trying keyslot (type=%d)\n", keyslot.kdf.type); - /* Try the keyslot using the appropriate KDF */ - if (keyslot.kdf.type == LUKS2_KDF_PBKDF2) { - log_debug("LUKS2: calling try_keyslot_pbkdf2\n"); - ret = try_keyslot_pbkdf2(blk, pinfo, &keyslot, pass, pass_len, - md_type, cand_key); + /* If using pre-derived key, use it directly */ + if (pre_derived) { + if (pass_len != keyslot.key_size) { + log_debug("Pre-derived key size mismatch: got %zu, need %u\n", + pass_len, keyslot.key_size); + return -EAGAIN; + } + memcpy(cand_key, pass, pass_len); + ret = 0; } else { - /* Argon2 (already checked for CONFIG_ARGON2 support) */ - log_debug("LUKS2: calling try_keyslot_argon2\n"); - ret = try_keyslot_argon2(blk, pinfo, &keyslot, pass, pass_len, - cand_key); + /* Try the keyslot using the appropriate KDF */ + if (keyslot.kdf.type == LUKS2_KDF_PBKDF2) { + log_debug("LUKS2: calling try_keyslot_pbkdf2\n"); + ret = try_keyslot_pbkdf2(blk, pinfo, &keyslot, pass, pass_len, + md_type, cand_key); + } else { + /* Argon2 (already checked for CONFIG_ARGON2 support) */ + log_debug("LUKS2: calling try_keyslot_argon2\n"); + ret = try_keyslot_argon2(blk, pinfo, &keyslot, pass, pass_len, + cand_key); + } } log_debug("LUKS2: keyslot try returned %d\n", ret); @@ -877,8 +891,8 @@ static int try_unlock_keyslot(struct udevice *blk, struct disk_partition *pinfo, } int unlock_luks2(struct udevice *blk, struct disk_partition *pinfo, - const u8 *pass, size_t pass_len, u8 *master_key, - uint *key_sizep) + const u8 *pass, size_t pass_len, bool pre_derived, + u8 *master_key, uint *key_sizep) { ofnode keyslots_node, keyslot_node; struct luks2_digest digest; @@ -896,8 +910,8 @@ int unlock_luks2(struct udevice *blk, struct disk_partition *pinfo, ret = -EACCES; ofnode_for_each_subnode(keyslot_node, keyslots_node) { ret = try_unlock_keyslot(blk, pinfo, keyslot_node, &digest, - md_type, pass, pass_len, master_key, - key_sizep); + md_type, pass, pass_len, pre_derived, + master_key, key_sizep); if (!ret) /* Successfully unlocked! */ break; diff --git a/drivers/block/luks_internal.h b/drivers/block/luks_internal.h index 6b0e41267ff..33f6ce12689 100644 --- a/drivers/block/luks_internal.h +++ b/drivers/block/luks_internal.h @@ -50,14 +50,16 @@ void essiv_decrypt(const u8 *derived_key, uint key_size, u8 *expkey, u8 *km, * * @blk: Block device * @pinfo: Partition information - * @pass: Passphrase to unlock the partition + * @pass: Passphrase to unlock the partition or pre-derived key * @pass_len: Length of the passphrase in bytes + * @pre_derived: True if pass is a pre-derived key, false for passphrase * @master_key: Buffer to receive the decrypted master key * @key_sizep: Returns the key size - * Return: 0 on success, -ve on error + * Return: 0 on success, -EACCES if no keyslots matched, other -ve on other + * error */ int unlock_luks2(struct udevice *blk, struct disk_partition *pinfo, - const u8 *pass, size_t pass_len, u8 *master_key, - uint *key_sizep); + const u8 *pass, size_t pass_len, bool pre_derived, + u8 *master_key, uint *key_sizep); #endif /* __LUKS_INTERNAL_H__ */