From patchwork Tue Nov 11 12:41:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 674 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=1762864928; bh=FcKWeaCeTLatAnofhy3DcY9h53UXgCftaLmCMPoRQrQ=; 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=bY5HuAkktO9vLQoaQPMBc7CSZ0nMmNTgyEwPv0wFcnyDwbsHU0tuDlC0oOcOJxTAG sGmwhNUPgsFq0egpcHUKuyvHXLVUgOJVZE5VWkr6PKy1Tel01w9t8roMCN/rymdLX0 kjQoSMUiJbyOmI5MMLd2mZw3kz05zjcvEuIO+yMx8LRWz/E1aD4PrgCuOgobNGKvJw O0PdOA+4Chl6xphFKNOhJgPBJOR5tyv+PIkhtcilwwaG4kOx1LSOMftoPcrlxLIuK+ j3bJNfOAo4flVyBk2K54wzo1KTLHwE2zVnB+qvek5VxkZ9e7uJby5AlEGAks5JCT7b sXmGr4DfZOJnw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7C96B684E0 for ; Tue, 11 Nov 2025 05:42:08 -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 6qoWIUQK3rk0 for ; Tue, 11 Nov 2025 05:42:08 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864928; bh=FcKWeaCeTLatAnofhy3DcY9h53UXgCftaLmCMPoRQrQ=; 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=bY5HuAkktO9vLQoaQPMBc7CSZ0nMmNTgyEwPv0wFcnyDwbsHU0tuDlC0oOcOJxTAG sGmwhNUPgsFq0egpcHUKuyvHXLVUgOJVZE5VWkr6PKy1Tel01w9t8roMCN/rymdLX0 kjQoSMUiJbyOmI5MMLd2mZw3kz05zjcvEuIO+yMx8LRWz/E1aD4PrgCuOgobNGKvJw O0PdOA+4Chl6xphFKNOhJgPBJOR5tyv+PIkhtcilwwaG4kOx1LSOMftoPcrlxLIuK+ j3bJNfOAo4flVyBk2K54wzo1KTLHwE2zVnB+qvek5VxkZ9e7uJby5AlEGAks5JCT7b sXmGr4DfZOJnw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6CE7F6846C for ; Tue, 11 Nov 2025 05:42:08 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864927; bh=Oqwm8j3K3oDAkuU3aOPT22QZQbcAdPoJteP88A5W/Xc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=At/DXRTs8sWe6+t0+c0qICLIaVHCVSkUDCRFvIoCrCPkCJKwLgR8T23hOd8VytYh1 7sryWXehhFpQlhzK0U3FiB/jY09T/Ew5QRR19nV6m/jLZ/6m/VPQUgZ71r/7uEViFA CY+2t2nCgVVVEwdShiAXl36B1dGvZ0lKuPbzCR58ZjzqG+QHPWGDWkJf3UxUkVcTGP 6z+nq06+s8PUzzW5OOYstUO9MTT6T3t0UU2+EgrDT4Acb+NDRxKqYpFDG1GKMHnbRD 0hOzcYye60WYv+0FGb/xMPT5xtWYk0ffUpKk7Rw15UtyJG1IEpr234H2HZ2iluFRe7 63/8v0lmeWWxw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 646776841A; Tue, 11 Nov 2025 05:42:07 -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 10026) with ESMTP id FcQzl86cTmU8; Tue, 11 Nov 2025 05:42:07 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864923; bh=YWdprSSLyIgATvbm3CiEa11IaX53oU6La/BXLvqsE9s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QbHdtdosGq5vN3W00j6MI0Ctooa8+x5jD8YZy3FgEOGWzH39kmjeBhxSRHisP7Ua4 ufpb9lKy4yKAKNaAP3Nep4bpjjlsmjWZGGPhmMQiV3PkpBXdnyByggh0JYalfGA08U AGxlmZTjIrkFFfqjsGBXGW89hneMCJIVk2wZ21fJtRFSvK2KOEgCANsk2hIODk9yDT 7GegkP7aO6LsW8IYo8ifiQj6KXDm1vlhgmV6Lz78ZTOeHi081zGYguqZ0LPgno5xJe Cwc5rTBWGObjDPKUaqCulr0OcuIwvU52lfOXxcod3acmw7SkOXlwP4MPywX7zauYSY IQz9hGMZ2+7JQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 0DC2F6846C; Tue, 11 Nov 2025 05:42:02 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:07 -0700 Message-ID: <20251111124131.1198930-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: T6HXFSGFDYZOVISXD76PH2GSWZB7TJCP X-Message-ID-Hash: T6HXFSGFDYZOVISXD76PH2GSWZB7TJCP 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 01/15] mbedtls: Allow use of XTS functions 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 Add a few Kconfig options to support XTS (XEX Tweakable Block Ciphertext Stealing). Co-developed-by: Claude Signed-off-by: Simon Glass --- lib/mbedtls/Makefile | 4 ++++ lib/mbedtls/mbedtls_def_config.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/lib/mbedtls/Makefile b/lib/mbedtls/Makefile index 0506a5a6b3e..257f585c013 100644 --- a/lib/mbedtls/Makefile +++ b/lib/mbedtls/Makefile @@ -37,6 +37,10 @@ mbedtls_lib_crypto-$(CONFIG_$(PHASE_)HKDF_MBEDTLS) += \ $(MBEDTLS_LIB_DIR)/hkdf.o mbedtls_lib_crypto-$(CONFIG_$(PHASE_)PKCS5_MBEDTLS) += \ $(MBEDTLS_LIB_DIR)/pkcs5.o +mbedtls_lib_crypto-$(CONFIG_$(PHASE_)BLK_LUKS) += \ + $(MBEDTLS_LIB_DIR)/aes.o \ + $(MBEDTLS_LIB_DIR)/cipher.o \ + $(MBEDTLS_LIB_DIR)/cipher_wrap.o # MbedTLS X509 library obj-$(CONFIG_$(XPL_)MBEDTLS_LIB_X509) += mbedtls_lib_x509.o diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h index 9e3beed07f4..a0578d33ba6 100644 --- a/lib/mbedtls/mbedtls_def_config.h +++ b/lib/mbedtls/mbedtls_def_config.h @@ -64,6 +64,12 @@ #define MBEDTLS_PKCS5_C #endif +#if CONFIG_IS_ENABLED(BLK_LUKS) +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CIPHER_MODE_XTS +#define MBEDTLS_AES_C +#endif + #if CONFIG_IS_ENABLED(MBEDTLS_LIB_X509) #if CONFIG_IS_ENABLED(X509_CERTIFICATE_PARSER) @@ -104,6 +110,7 @@ #define MBEDTLS_SSL_CLI_C #define MBEDTLS_SSL_TLS_C #define MBEDTLS_CIPHER_C +#define MBEDTLS_CIPHER_MODE_XTS #define MBEDTLS_MD_C #define MBEDTLS_CTR_DRBG_C #define MBEDTLS_AES_C From patchwork Tue Nov 11 12:41:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 675 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=1762864930; bh=P2WPLBYj37KQZV7+a9sgcl+eFPGD78rIy2S0I9BtFzQ=; 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=UrP4Ys2ATb0/pwd+cqtRFxY8rndImgk2zSgGe5Um0gZKIzV+vLO7qiPHZkkMbYVq/ Tr5hDiJZr5YsVHlcwCN3M1mC6+6HMY3VbKrrmqi+mafu3GbKjsDORkzsISBpVDQQ59 hcm5BOS+mt1kqDrtgBJ9PRk4/3StThyxUJ+8ffmXLexeLKLEbHqI7Gm3dFGFH1uG3Z /qrQZLhVZIYfLqUW4nXLWhee3yjnfqBeU1p+IyuX7I8KhTs6w55SvTLejMf+WSgnbx DEU0dsc+G5yqA9AjXJBgHKjY8VuntWRRi+G5tsPlc4ktYveW4Ijwi5XuNR7N7jhnx4 /F5GWLCmxdbew== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E945E684E5 for ; Tue, 11 Nov 2025 05:42:10 -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 woLV9MbUE1m0 for ; Tue, 11 Nov 2025 05:42:10 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864929; bh=P2WPLBYj37KQZV7+a9sgcl+eFPGD78rIy2S0I9BtFzQ=; 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=bgaD3HB/ZoM2IxipVvaiNMMdvq+EpyGaysFpzgDfyzrgCxb+X1W0YWtXlpzEmsHY7 qhu9OnkgvCRLoSXXGWQFi9zy2bNWYyqbqgoQDrtlr/cfPZrFzCs6BFTWB0eckpWgPi EOJLa5aCZF+bxL1HOxC4RyZ6HlPJcJDWXBuaEgwXXPIWyL062clZ2mLUrsq/rgJA2O NIhgDFQm1V1/Uo6n6MlxUTSETDQd86STXPW1X14DbSlKCPkGNkMdxrqXd49vdg9eCp /pKFQ1GprWCG+GbVD/F4Q8lXA6Tmgi8dG1dNXVI+AW5EGjhNRwXLawMzOLG47B7+lg fD1UrChxoKbwg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id CF2D4684C9 for ; Tue, 11 Nov 2025 05:42:09 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864928; bh=CnUwgwDgQLEbJKqXZ1XUVh5DUCRFpSsNJm56vZ60wZg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L916h5pDZoeEKd35TiggdytWnlUQY9t0kpXVSjr1wAbk5yOKIzMsuzeKBTgyfXtX4 RMK+aiwcq2BIofgBQNP8wQRh9Z21PLoBoGqFGf+xR/byihyrsM6oRAevtm0Dv/FrOQ O+r9Ci78zXsqOb4vwIx23xrY8vS7cLyc5NRP2+XUWRvhaxcPO7C5XpD/GEQesZuVXv fP851fxnRvpGpiFyquttg5hiprxu203ePGySK6+1MLIJ6wSgnUZ3ZSXIAqmOW/H3tg piaDNC9evYQiTF1ioRvHNXcmzdOxwVuw8+l/bNBaBGjL1zijQs9ek89GEVIogzMxjH UIIOgEo2eRMGw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 65DBB684B7; Tue, 11 Nov 2025 05:42:08 -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 10026) with ESMTP id DWK7v4Wu9Jot; Tue, 11 Nov 2025 05:42:08 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864928; bh=YL8vRacqchhJP2wMG2wR8eXysCmnzM+XJoABRDg+y3U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EB7mIwp//GYJSjpRszXPdhKh69jzLtBXiaRNbVYv/XCmBkI5M5/xDH3JYfjlffGhJ eocYNC0TcMjoshJ47xKoI/ixlyxiWRrHaOtbQGqZS1ur32lsghg8HuDlkT0cHr8Nrd Aj38r98VfjypWT7RpviPDqLxM2GcQSUHAf6CDbBcak1BAHmaEjoHASUXTldl2PfYoH R0YMa/LBhcTeilqOel5I0qLl7K2vINCyhQnAadAKKx1WI4EHrxO5O9dPnbEO2IYWZs sQ+BEbJSMHn++2sH9Ae8bqnqmKIK8KMoMhxt62cUKnzAsZwt5klNEohj013bk0OmFZ YZ5cqVcI8unzQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id A74016846C; Tue, 11 Nov 2025 05:42:07 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:08 -0700 Message-ID: <20251111124131.1198930-3-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 2HDQRNMASU3OU7HKZRRCM3OKIU3LJF56 X-Message-ID-Hash: 2HDQRNMASU3OU7HKZRRCM3OKIU3LJF56 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 02/15] mbedtls: Allow use of base64 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 Add a configuration and a Makefile rule to provide access to the mbedtls base64 support. Co-developed-by: Claude Signed-off-by: Simon Glass --- lib/mbedtls/Makefile | 1 + lib/mbedtls/mbedtls_def_config.h | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/mbedtls/Makefile b/lib/mbedtls/Makefile index 257f585c013..5b3f664073c 100644 --- a/lib/mbedtls/Makefile +++ b/lib/mbedtls/Makefile @@ -39,6 +39,7 @@ mbedtls_lib_crypto-$(CONFIG_$(PHASE_)PKCS5_MBEDTLS) += \ $(MBEDTLS_LIB_DIR)/pkcs5.o mbedtls_lib_crypto-$(CONFIG_$(PHASE_)BLK_LUKS) += \ $(MBEDTLS_LIB_DIR)/aes.o \ + $(MBEDTLS_LIB_DIR)/base64.o \ $(MBEDTLS_LIB_DIR)/cipher.o \ $(MBEDTLS_LIB_DIR)/cipher_wrap.o diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h index a0578d33ba6..d4e35ddeb61 100644 --- a/lib/mbedtls/mbedtls_def_config.h +++ b/lib/mbedtls/mbedtls_def_config.h @@ -65,6 +65,7 @@ #endif #if CONFIG_IS_ENABLED(BLK_LUKS) +#define MBEDTLS_BASE64_C #define MBEDTLS_CIPHER_C #define MBEDTLS_CIPHER_MODE_XTS #define MBEDTLS_AES_C From patchwork Tue Nov 11 12:41:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 676 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=1762864933; bh=6JkATnVqJiBuvns3Evigq127aPxZx/NwUu4iZ1it9Ns=; 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=LkfegNLFMT9h0PKaOYcH9/OsWn0qE+TsUQGNNwLSM5KxxKjFxMp8GnKJMsefSeyVq pv8e5MudpK4am5vnku5vTFJRMMuKf1SxMHhUeCne5hYb0CWvWXVfwsFwEo4+Sfp+74 MudYZVY3T5VaPy8rdRfP2qi44LENN2NxLrj5xRWN2hWXK+6E0kOr5KMTmhocwOd9zz eM1zKNCw+8C41GThbthgKR6U/aooaI6K6GAFhWC/mTNRULJPOLbIXruAQpMhblmPFZ fKPe26ShhcmCOEnVinNBcKVzVhlPNfzsF3eEVFZGM2BHBiVKVaE00uTGlI4V6X1u9f aFsX2sEGSyI7A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5764268484 for ; Tue, 11 Nov 2025 05:42:13 -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 JkWjvxTieduA for ; Tue, 11 Nov 2025 05:42:13 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864933; bh=6JkATnVqJiBuvns3Evigq127aPxZx/NwUu4iZ1it9Ns=; 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=LkfegNLFMT9h0PKaOYcH9/OsWn0qE+TsUQGNNwLSM5KxxKjFxMp8GnKJMsefSeyVq pv8e5MudpK4am5vnku5vTFJRMMuKf1SxMHhUeCne5hYb0CWvWXVfwsFwEo4+Sfp+74 MudYZVY3T5VaPy8rdRfP2qi44LENN2NxLrj5xRWN2hWXK+6E0kOr5KMTmhocwOd9zz eM1zKNCw+8C41GThbthgKR6U/aooaI6K6GAFhWC/mTNRULJPOLbIXruAQpMhblmPFZ fKPe26ShhcmCOEnVinNBcKVzVhlPNfzsF3eEVFZGM2BHBiVKVaE00uTGlI4V6X1u9f aFsX2sEGSyI7A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 40E31684B7 for ; Tue, 11 Nov 2025 05:42:13 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864930; bh=atD/6K74sevk69fkxsPvFMRd26pl+fcPG2j5QWjuIMk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nqT779DbzR5tEO5mSWVs9TAMaFZKfAexJ/PUOmTy4p7zKFK6xkNQIZLyzf2J5h1zA fXFjrufeAjUhXYSu4UaPEBZ1SKLdAkR8Jh02naYLyzQBg907yF1isAPMotk7dZ3h8F LrtVrfX7x4SUsoqiPPn4fAcQ+hKVHGJ73ZqVDxWmgMbQLZTZc3Gm1k0Y7zanwmxpQe JUiRDLpOyNS1KJUVrnOoQ531BPgz/zEALhqwilVGVzWAoW577O7VBlBehvl8NnPEWi N1rAEqIYqJJqtfFV4TNyV+g9+SVvbah8kXKFnbgFprqutErH7THzvzYHdEw2igPjFH EAd6JbcB/q8Ew== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D4277684B7; Tue, 11 Nov 2025 05:42:10 -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 10026) with ESMTP id iZScerVXa1iD; Tue, 11 Nov 2025 05:42:10 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864929; bh=zPk1MTNqzbnlzkgt4RQyVsoz3SI5CR+aVr0G9FXL0ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ma+S7G/cx/vTCyipq5p5QEKoGETCekfJI5Ik3I/Kgk7yBlRQVU+iKF3ABOBuIjywV uYYQyMH6GCHviz4jb51NorvS70wkD1TNyP4RuXMF0sYrpU+4BDty1y9+9AGlqiWptp +lmEIEArpRwAlfzY96ceDA7QhwMZN+53HzNFI31vszQSmfBIkxwZVPDFEh6uEXUdAw UMrs2h163Qsjn5DMyq2xv9ml4qHexTfR7hTmAcO8xWKdGzZ6ZuqXmX/gKymZ3/yIBk 2xkrc8PsZr/Q6lgo0fmnTZ2XSOo2UXdmigRHV2EqfmJtIXQhz6KH3v6eSlru6/d1Fh Gnuk0kdOE01DQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id A75B068518; Tue, 11 Nov 2025 05:42:08 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:09 -0700 Message-ID: <20251111124131.1198930-4-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 3YFCDPCJ2HZXMQ6YDA7N6FXS4MLSM7Y5 X-Message-ID-Hash: 3YFCDPCJ2HZXMQ6YDA7N6FXS4MLSM7Y5 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 03/15] test: Check for null string in assert functions 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 Update ut_asserteq_str() and ut_asserteq_strn() to check for NULL. This allows tests to avoid doing this. Co-developed-by: Claude Signed-off-by: Simon Glass --- include/test/ut.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/include/test/ut.h b/include/test/ut.h index 6731b43dba9..70eaaea5e0e 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -206,7 +206,15 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes); const char *_val1 = (expr1), *_val2 = (expr2); \ int __ret = 0; \ \ - if (strcmp(_val1, _val2)) { \ + if (!_val1 || !_val2) { \ + ut_failf(uts, __FILE__, __LINE__, __func__, \ + #expr1 " = " #expr2, \ + "Expected \"%s\", got \"%s\"", \ + _val1 ? _val1 : "(null)", \ + _val2 ? _val2 : "(null)"); \ + if (!uts->soft_fail) \ + return CMD_RET_FAILURE; \ + } else if (strcmp(_val1, _val2)) { \ ut_failf(uts, __FILE__, __LINE__, __func__, \ #expr1 " = " #expr2, \ "Expected \"%s\", got \"%s\"", _val1, _val2); \ @@ -222,16 +230,26 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes); */ #define ut_asserteq_strn(expr1, expr2) ({ \ const char *_val1 = (expr1), *_val2 = (expr2); \ - int _len = strlen(_val1); \ int __ret = 0; \ \ - if (memcmp(_val1, _val2, _len)) { \ + if (!_val1 || !_val2) { \ ut_failf(uts, __FILE__, __LINE__, __func__, \ #expr1 " = " #expr2, \ - "Expected \"%.*s\", got \"%.*s\"", \ - _len, _val1, _len, _val2); \ + "Expected \"%s\", got \"%s\"", \ + _val1 ? _val1 : "(null)", \ + _val2 ? _val2 : "(null)"); \ if (!uts->soft_fail) \ return CMD_RET_FAILURE; \ + } else { \ + int _len = strlen(_val1); \ + if (memcmp(_val1, _val2, _len)) { \ + ut_failf(uts, __FILE__, __LINE__, __func__, \ + #expr1 " = " #expr2, \ + "Expected \"%.*s\", got \"%.*s\"", \ + _len, _val1, _len, _val2); \ + if (!uts->soft_fail) \ + return CMD_RET_FAILURE; \ + } \ } \ __ret; \ }) From patchwork Tue Nov 11 12:41:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 686 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=1762889902; bh=oPvH35XdMy/o+R3mufRCaqVWoi9l1gUVLpXVzpkuxSw=; 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=Nt5h9m1vH8NSihzBMPxUihvqwbXKE49VkUVRKxv+NBGbrGW3YyGNyYdoglUzTYxfP fpuVaOFXpPmctMms7+nAi5YZlHG4pZSflRKf0hmdn/hIyygpJn1ZnomCZQDhNeba6r BCd2PIlVORRyScX9RSAKGxssczlyHuTOQND4hbwhqpzsGLPZBB3P6T2q13PyNxhmSv G8NUdKXHucIU+ygrbMi6/P+Ey2v0Pl2mfRkowSr5N3UGHXj4/fmM/otK26pHizuQZy 4i0dF4euHNutal/yaPQb2N4AIdIz+bsLppiKYi/wEm9sCqRjvOoryAN7YgntSF0bwl do8QHgv7n3Fwg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id F171468535 for ; Tue, 11 Nov 2025 12:38:21 -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 e3MrX9oquzxC for ; Tue, 11 Nov 2025 12:38:21 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762889901; bh=oPvH35XdMy/o+R3mufRCaqVWoi9l1gUVLpXVzpkuxSw=; 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=iGYO8/FSxc1BWaKv6BlUaW6wG2ivZX06J+1fG1IaJg7Oeumtl/2hzzu3JnDtfllP5 9mzt/7OFSQWrgU/h9wm7WpC9mmBJlMKuHYK7MWwDcuGr+au8zlNRVXoK+mH1o6eSAa vK0Bp6W6Oh5FkaTmYJkUXoiu+lP55CMaTCG9l/QHKnKktJbegFAWaqey2UOXJZGqOF WgCkyXW7Quo2cPnQXrRl4MDQjkb3Wy3eP6GiosSZLyEW9ilHr+31IUoplj4WvJfKCo bL2nhNCJ+mZ7fBKXVy2j3S/Dew7pN8qc6ZT4Xa8uo6t8RWf/9y1zAbyTBmxI/gqaS4 ew9K9B5kwkvNA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D8392684C7 for ; Tue, 11 Nov 2025 12:38:21 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864938; bh=8ehMcDElkRRrIQJciOd/+OwZ4b5Dh50+mdkixJKrvyQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H6Fsgxw5VDIxE/C28Lad8Hfa7LEGM76H3De/6C4rWzrpHx0HgPQlJJLg20rnaOHA+ CvItRc92S5rrJp5ROu90zqg5wiVJBodo0VQMobCQZ5IlsHFNR/3BCYxZp9/kYS1KJZ S+EVt3XCIx0kvM7zMf/sv36LwN96A81LKj6MHkQxgqpnwXOr5jmr/ODMlDwyGcL8IO h+RaLhEOslvR+7aWtcdgDGtbdHut4wliv1hBHRbexFg7kbfNMYwuits0tSr7ZinK9F PlVITrYD9Cjy0u3W+95fyc/UgtV1uxFr+O3zDdwSFzWUdX9gea5sD/s/DX2gEynUXW zrLqBT10G+JDQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 58CC66841A; Tue, 11 Nov 2025 05:42:18 -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 10026) with ESMTP id AKq1QH6Yasi3; Tue, 11 Nov 2025 05:42:18 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864931; bh=NLRZA55T2ePaSXeCTVEZ1Zd/OcnJVDPvcyu8fSRz9MI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Stph7VQtfDM5gLWc7Ea75RflIUXlCsXI/oOv9n9p81zsaSSg/YO3tVKFYKE0iO60P 1I6XcRQdtRde3c/eCluD4LOOJgokNOBwkhVZtYWyHgxwHutMedkzhuc5DLeZPXGCzr +SLkoJ3zW2JIE5STdK6bjkjB/rRuQ8xdNte5CtDDyGIS7hYZXBnbWAsPALf9+AhRFm XlbHqZ7xwB8hBc0WdfyD9SrgWDETZ8Tpn2gfCT4zrqJi0J+YLl4xcq4/EtGmBpDg1o OT54kacKXkc2w5eTJiNrCrpGNd/q4+qg8ngOvMyQE2GwJqdes5jGE8isVgPLE6feqH vGt429CdeNF4w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 4429A68378; Tue, 11 Nov 2025 05:42:11 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:11 -0700 Message-ID: <20251111124131.1198930-6-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Hits: max-size X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; news-moderation; no-subject; digests; suspicious-header Message-ID-Hash: ZBO3J4MUVVZ4OE6EAVE5OS4L4O6PQIAK X-Message-ID-Hash: ZBO3J4MUVVZ4OE6EAVE5OS4L4O6PQIAK X-Mailman-Approved-At: Tue, 11 Nov 2025 19:38:19 -0700 CC: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 05/15] lib: Bring in argon2 library 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 This library is used for full-disk encryption with LUKS, so bring it in from https://github.com/P-H-C/phc-winner-argon2 commit: f57e61e Merge pull request #321 from bittorf/fix-spelling-mistakes Co-developed-by: Claude Signed-off-by: Simon Glass --- lib/argon2/argon2.c | 452 +++++++++++++++++++ lib/argon2/argon2.h | 437 ++++++++++++++++++ lib/argon2/blake2/blake2-impl.h | 156 +++++++ lib/argon2/blake2/blake2.h | 89 ++++ lib/argon2/blake2/blake2b.c | 390 ++++++++++++++++ lib/argon2/blake2/blamka-round-ref.h | 56 +++ lib/argon2/core.c | 648 +++++++++++++++++++++++++++ lib/argon2/core.h | 228 ++++++++++ lib/argon2/ref.c | 194 ++++++++ 9 files changed, 2650 insertions(+) create mode 100644 lib/argon2/argon2.c create mode 100644 lib/argon2/argon2.h create mode 100644 lib/argon2/blake2/blake2-impl.h create mode 100644 lib/argon2/blake2/blake2.h create mode 100644 lib/argon2/blake2/blake2b.c create mode 100644 lib/argon2/blake2/blamka-round-ref.h create mode 100644 lib/argon2/core.c create mode 100644 lib/argon2/core.h create mode 100644 lib/argon2/ref.c diff --git a/lib/argon2/argon2.c b/lib/argon2/argon2.c new file mode 100644 index 00000000000..34da3d6b4ac --- /dev/null +++ b/lib/argon2/argon2.c @@ -0,0 +1,452 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +#include "argon2.h" +#include "encoding.h" +#include "core.h" + +const char *argon2_type2string(argon2_type type, int uppercase) { + switch (type) { + case Argon2_d: + return uppercase ? "Argon2d" : "argon2d"; + case Argon2_i: + return uppercase ? "Argon2i" : "argon2i"; + case Argon2_id: + return uppercase ? "Argon2id" : "argon2id"; + } + + return NULL; +} + +int argon2_ctx(argon2_context *context, argon2_type type) { + /* 1. Validate all inputs */ + int result = validate_inputs(context); + uint32_t memory_blocks, segment_length; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (Argon2_d != type && Argon2_i != type && Argon2_id != type) { + return ARGON2_INCORRECT_TYPE; + } + + /* 2. Align memory size */ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + memory_blocks = context->m_cost; + + if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) { + memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes; + } + + segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS); + /* Ensure that all segments have equal length */ + memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS); + + instance.version = context->version; + instance.memory = NULL; + instance.passes = context->t_cost; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + + if (instance.threads > instance.lanes) { + instance.threads = instance.lanes; + } + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + result = fill_memory_blocks(&instance); + + if (ARGON2_OK != result) { + return result; + } + /* 5. Finalization */ + finalize(context, &instance); + + return ARGON2_OK; +} + +int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version){ + + argon2_context context; + int result; + uint8_t *out; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (saltlen > ARGON2_MAX_SALT_LENGTH) { + return ARGON2_SALT_TOO_LONG; + } + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (hashlen < ARGON2_MIN_OUTLEN) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + out = malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *)out; + context.outlen = (uint32_t)hashlen; + context.pwd = CONST_CAST(uint8_t *)pwd; + context.pwdlen = (uint32_t)pwdlen; + context.salt = CONST_CAST(uint8_t *)salt; + context.saltlen = (uint32_t)saltlen; + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = t_cost; + context.m_cost = m_cost; + context.lanes = parallelism; + context.threads = parallelism; + context.allocate_cbk = NULL; + context.free_cbk = NULL; + context.flags = ARGON2_DEFAULT_FLAGS; + context.version = version; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + clear_internal_memory(out, hashlen); + free(out); + return result; + } + + /* if raw hash requested, write it */ + if (hash) { + memcpy(hash, out, hashlen); + } + + /* if encoding requested, write it */ + if (encoded && encodedlen) { + if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { + clear_internal_memory(out, hashlen); /* wipe buffers if error */ + clear_internal_memory(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + clear_internal_memory(out, hashlen); + free(out); + + return ARGON2_OK; +} + +int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_i, + ARGON2_VERSION_NUMBER); +} + +int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_d, + ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { + size_t i; + uint8_t d = 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int)((1 & ((d - 1) >> 8)) - 1); +} + +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) { + + argon2_context ctx; + uint8_t *desired_result = NULL; + + int ret = ARGON2_OK; + + size_t encoded_len; + uint32_t max_field_len; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (encoded == NULL) { + return ARGON2_DECODING_FAIL; + } + + encoded_len = strlen(encoded); + if (encoded_len > UINT32_MAX) { + return ARGON2_DECODING_FAIL; + } + + /* No field can be longer than the encoded length */ + max_field_len = (uint32_t)encoded_len; + + ctx.saltlen = max_field_len; + ctx.outlen = max_field_len; + + ctx.salt = malloc(ctx.saltlen); + ctx.out = malloc(ctx.outlen); + if (!ctx.salt || !ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ctx.pwd = (uint8_t *)pwd; + ctx.pwdlen = (uint32_t)pwdlen; + + ret = decode_string(&ctx, encoded, type); + if (ret != ARGON2_OK) { + goto fail; + } + + /* Set aside the desired result, and get a new buffer. */ + desired_result = ctx.out; + ctx.out = malloc(ctx.outlen); + if (!ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ret = argon2_verify_ctx(&ctx, (char *)desired_result, type); + if (ret != ARGON2_OK) { + goto fail; + } + +fail: + free(ctx.salt); + free(ctx.out); + free(desired_result); + + return ret; +} + +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_d); +} + +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_id); +} + +int argon2d_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_d); +} + +int argon2i_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_i); +} + +int argon2id_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_id); +} + +int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type) { + int ret = argon2_ctx(context, type); + if (ret != ARGON2_OK) { + return ret; + } + + if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) { + return ARGON2_VERIFY_MISMATCH; + } + + return ARGON2_OK; +} + +int argon2d_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_d); +} + +int argon2i_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_i); +} + +int argon2id_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_id); +} + +const char *argon2_error_message(int error_code) { + switch (error_code) { + case ARGON2_OK: + return "OK"; + case ARGON2_OUTPUT_PTR_NULL: + return "Output pointer is NULL"; + case ARGON2_OUTPUT_TOO_SHORT: + return "Output is too short"; + case ARGON2_OUTPUT_TOO_LONG: + return "Output is too long"; + case ARGON2_PWD_TOO_SHORT: + return "Password is too short"; + case ARGON2_PWD_TOO_LONG: + return "Password is too long"; + case ARGON2_SALT_TOO_SHORT: + return "Salt is too short"; + case ARGON2_SALT_TOO_LONG: + return "Salt is too long"; + case ARGON2_AD_TOO_SHORT: + return "Associated data is too short"; + case ARGON2_AD_TOO_LONG: + return "Associated data is too long"; + case ARGON2_SECRET_TOO_SHORT: + return "Secret is too short"; + case ARGON2_SECRET_TOO_LONG: + return "Secret is too long"; + case ARGON2_TIME_TOO_SMALL: + return "Time cost is too small"; + case ARGON2_TIME_TOO_LARGE: + return "Time cost is too large"; + case ARGON2_MEMORY_TOO_LITTLE: + return "Memory cost is too small"; + case ARGON2_MEMORY_TOO_MUCH: + return "Memory cost is too large"; + case ARGON2_LANES_TOO_FEW: + return "Too few lanes"; + case ARGON2_LANES_TOO_MANY: + return "Too many lanes"; + case ARGON2_PWD_PTR_MISMATCH: + return "Password pointer is NULL, but password length is not 0"; + case ARGON2_SALT_PTR_MISMATCH: + return "Salt pointer is NULL, but salt length is not 0"; + case ARGON2_SECRET_PTR_MISMATCH: + return "Secret pointer is NULL, but secret length is not 0"; + case ARGON2_AD_PTR_MISMATCH: + return "Associated data pointer is NULL, but ad length is not 0"; + case ARGON2_MEMORY_ALLOCATION_ERROR: + return "Memory allocation error"; + case ARGON2_FREE_MEMORY_CBK_NULL: + return "The free memory callback is NULL"; + case ARGON2_ALLOCATE_MEMORY_CBK_NULL: + return "The allocate memory callback is NULL"; + case ARGON2_INCORRECT_PARAMETER: + return "Argon2_Context context is NULL"; + case ARGON2_INCORRECT_TYPE: + return "There is no such version of Argon2"; + case ARGON2_OUT_PTR_MISMATCH: + return "Output pointer mismatch"; + case ARGON2_THREADS_TOO_FEW: + return "Not enough threads"; + case ARGON2_THREADS_TOO_MANY: + return "Too many threads"; + case ARGON2_MISSING_ARGS: + return "Missing arguments"; + case ARGON2_ENCODING_FAIL: + return "Encoding failed"; + case ARGON2_DECODING_FAIL: + return "Decoding failed"; + case ARGON2_THREAD_FAIL: + return "Threading failure"; + case ARGON2_DECODING_LENGTH_FAIL: + return "Some of encoded parameters are too long or too short"; + case ARGON2_VERIFY_MISMATCH: + return "The password does not match the supplied hash"; + default: + return "Unknown error code"; + } +} + +size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, + uint32_t saltlen, uint32_t hashlen, argon2_type type) { + return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) + + numlen(t_cost) + numlen(m_cost) + numlen(parallelism) + + b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1; +} diff --git a/lib/argon2/argon2.h b/lib/argon2/argon2.h new file mode 100644 index 00000000000..3980bb352f2 --- /dev/null +++ b/lib/argon2/argon2.h @@ -0,0 +1,437 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_H +#define ARGON2_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Symbols visibility control */ +#ifdef A2_VISCTL +#define ARGON2_PUBLIC __attribute__((visibility("default"))) +#define ARGON2_LOCAL __attribute__ ((visibility ("hidden"))) +#elif defined(_MSC_VER) +#define ARGON2_PUBLIC __declspec(dllexport) +#define ARGON2_LOCAL +#else +#define ARGON2_PUBLIC +#define ARGON2_LOCAL +#endif + +/* + * Argon2 input parameter restrictions + */ + +/* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(4) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +/* Flags to determine which fields are securely wiped (default = no wipe). */ +#define ARGON2_DEFAULT_FLAGS UINT32_C(0) +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) + +/* Global flag to determine if we are wiping internal memory buffers. This flag + * is defined in core.c and defaults to 1 (wipe internal memory). */ +extern int FLAG_clear_internal_memory; + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Memory allocator types --- for external allocation */ +typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); +typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); + +/* Argon2 external data structures */ + +/* + ***** + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with + * 4 parallel lanes. + * You want to erase the password, but you're OK with last pass not being + * erased. You want to use the default memory allocator. + * Then you initialize: + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t version; /* version number */ + + allocate_fptr allocate_cbk; /* pointer to memory allocator */ + deallocate_fptr free_cbk; /* pointer to memory deallocator */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { + Argon2_d = 0, + Argon2_i = 1, + Argon2_id = 2 +} argon2_type; + +/* Version of the algorithm */ +typedef enum Argon2_version { + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13, + ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 +} argon2_version; + +/* + * Function that gives the string representation of an argon2_type. + * @param type The argon2_type that we want the string for + * @param uppercase Whether the string should have the first letter uppercase + * @return NULL if invalid type, otherwise the string representation. + */ +ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase); + +/* + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type); + +/** + * Hashes a password with Argon2i, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +/** + * Hashes a password with Argon2i, producing a raw hash at @hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash - updated by the function + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd, + const size_t pwdlen, argon2_type type); + +/** + * Argon2d: Version of Argon2 that picks memory blocks depending + * on the password and salt. Only for side-channel-free + * environment!! + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_ctx(argon2_context *context); + +/** + * Argon2i: Version of Argon2 that picks memory blocks + * independent on the password and salt. Good for side-channels, + * but worse w.r.t. tradeoff attacks if only one pass is used. + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_ctx(argon2_context *context); + +/** + * Argon2id: Version of Argon2 where the first half-pass over memory is + * password-independent, the rest are password-dependent (on the password and + * salt). OK against side channels (they reduce to 1/2-pass Argon2i), and + * better with w.r.t. tradeoff attacks (similar to Argon2d). + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_ctx(argon2_context *context); + +/** + * Verify if a given password is correct for Argon2d hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2i hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2id hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context, + const char *hash); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type); + +/** + * Get the associated error message for given error code + * @return The error message associated with the given error code + */ +ARGON2_PUBLIC const char *argon2_error_message(int error_code); + +/** + * Returns the encoded hash length for the given input parameters + * @param t_cost Number of iterations + * @param m_cost Memory usage in kibibytes + * @param parallelism Number of threads; used to compute lanes + * @param saltlen Salt size in bytes + * @param hashlen Hash size in bytes + * @param type The argon2_type that we want the encoded length for + * @return The encoded hash length in bytes + */ +ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, + uint32_t parallelism, uint32_t saltlen, + uint32_t hashlen, argon2_type type); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/lib/argon2/blake2/blake2-impl.h b/lib/argon2/blake2/blake2-impl.h new file mode 100644 index 00000000000..86d0d5cfa9b --- /dev/null +++ b/lib/argon2/blake2/blake2-impl.h @@ -0,0 +1,156 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef PORTABLE_BLAKE2_IMPL_H +#define PORTABLE_BLAKE2_IMPL_H + +#include +#include + +#ifdef _WIN32 +#define BLAKE2_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define BLAKE2_INLINE __inline__ +#else +#define BLAKE2_INLINE +#endif + +/* Argon2 Team - Begin Code */ +/* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. +*/ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif +/* Argon2 Team - End Code */ + +static BLAKE2_INLINE uint32_t load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static BLAKE2_INLINE uint64_t load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static BLAKE2_INLINE void store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE void store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE uint64_t load48(const void *src) { + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static BLAKE2_INLINE void store48(void *dst, uint64_t w) { + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +} + +static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +void clear_internal_memory(void *v, size_t n); + +#endif diff --git a/lib/argon2/blake2/blake2.h b/lib/argon2/blake2/blake2.h new file mode 100644 index 00000000000..501c6a3186d --- /dev/null +++ b/lib/argon2/blake2/blake2.h @@ -0,0 +1,89 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef PORTABLE_BLAKE2_H +#define PORTABLE_BLAKE2_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +#pragma pack(push, 1) +typedef struct __blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} blake2b_param; +#pragma pack(pop) + +typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; +} blake2b_state; + +/* Ensure param structs have not been wrongly padded */ +/* Poor man's static_assert */ +enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) +}; + +/* Streaming API */ +ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen); +ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen); +ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P); +ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen); +ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen); + +/* Simple API */ +ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen); + +/* Argon2 Team - Begin Code */ +ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); +/* Argon2 Team - End Code */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/lib/argon2/blake2/blake2b.c b/lib/argon2/blake2/blake2b.c new file mode 100644 index 00000000000..3b519ddb4d0 --- /dev/null +++ b/lib/argon2/blake2/blake2b.c @@ -0,0 +1,390 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)}; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) { + S->f[1] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) { + if (S->last_node) { + blake2b_set_lastnode(S); + } + S->f[0] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S, + uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) { + clear_internal_memory(S, sizeof(*S)); /* wipe */ + blake2b_set_lastblock(S); /* invalidate for further use */ +} + +static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) { + memset(S, 0, sizeof(*S)); + memcpy(S->h, blake2b_IV, sizeof(S->h)); +} + +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { + const unsigned char *p = (const unsigned char *)P; + unsigned int i; + + if (NULL == P || NULL == S) { + return -1; + } + + blake2b_init0(S); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); + } + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +int blake2b_init(blake2b_state *S, size_t outlen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for unkeyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = 0; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + return blake2b_init_param(S, &P); +} + +int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for keyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = (uint8_t)keylen; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + if (blake2b_init_param(S, &P) < 0) { + blake2b_invalidate_state(S); + return -1; + } + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + /* Burn the key from stack */ + clear_internal_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +static void blake2b_compress(blake2b_state *S, const uint8_t *block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i, r; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + + for (r = 0; r < 12; ++r) { + ROUND(r); + } + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef G +#undef ROUND +} + +int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { + const uint8_t *pin = (const uint8_t *)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (S == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += (unsigned int)inlen; + return 0; +} + +int blake2b_final(blake2b_state *S, void *out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + unsigned int i; + + /* Sanity checks */ + if (S == NULL || out == NULL || outlen < S->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + } + + memcpy(out, buffer, S->outlen); + clear_internal_memory(buffer, sizeof(buffer)); + clear_internal_memory(S->buf, sizeof(S->buf)); + clear_internal_memory(S->h, sizeof(S->h)); + return 0; +} + +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen) { + blake2b_state S; + int ret = -1; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + goto fail; + } + + if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { + goto fail; + } + + if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { + goto fail; + } + + if (keylen > 0) { + if (blake2b_init_key(&S, outlen, key, keylen) < 0) { + goto fail; + } + } else { + if (blake2b_init(&S, outlen) < 0) { + goto fail; + } + } + + if (blake2b_update(&S, in, inlen) < 0) { + goto fail; + } + ret = blake2b_final(&S, out, outlen); + +fail: + clear_internal_memory(&S, sizeof(S)); + return ret; +} + +/* Argon2 Team - Begin Code */ +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { + uint8_t *out = (uint8_t *)pout; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = {0}; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; + } + + /* Ensure little-endian byte order! */ + store32(outlen_bytes, (uint32_t)outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void)0, 0) + + if (outlen <= BLAKE2B_OUTBYTES) { + TRY(blake2b_init(&blake_state, outlen)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out, outlen)); + } else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + BLAKE2B_OUTBYTES, NULL, 0)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + 0)); + memcpy(out, out_buffer, toproduce); + } +fail: + clear_internal_memory(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} +/* Argon2 Team - End Code */ diff --git a/lib/argon2/blake2/blamka-round-ref.h b/lib/argon2/blake2/blamka-round-ref.h new file mode 100644 index 00000000000..16cfc1c74af --- /dev/null +++ b/lib/argon2/blake2/blamka-round-ref.h @@ -0,0 +1,56 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef BLAKE_ROUND_MKA_H +#define BLAKE_ROUND_MKA_H + +#include "blake2.h" +#include "blake2-impl.h" + +/* designed by the Lyra PHC team */ +static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void)0, 0) + +#endif diff --git a/lib/argon2/core.c b/lib/argon2/core.c new file mode 100644 index 00000000000..e697882eb96 --- /dev/null +++ b/lib/argon2/core.c @@ -0,0 +1,648 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +/*For memory wiping*/ +#ifdef _WIN32 +#include +#include /* For SecureZeroMemory */ +#endif +#if defined __STDC_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#define VC_GE_2005(version) (version >= 1400) + +/* for explicit_bzero() on glibc */ +#define _DEFAULT_SOURCE + +#include +#include +#include + +#include "core.h" +#include "thread.h" +#include "blake2/blake2.h" +#include "blake2/blake2-impl.h" + +#ifdef GENKAT +#include "genkat.h" +#endif + +#if defined(__clang__) +#if __has_attribute(optnone) +#define NOT_OPTIMIZED __attribute__((optnone)) +#endif +#elif defined(__GNUC__) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40400 +#define NOT_OPTIMIZED __attribute__((optimize("O0"))) +#endif +#endif +#ifndef NOT_OPTIMIZED +#define NOT_OPTIMIZED +#endif + +/***************Instance and Position constructors**********/ +void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } + +void copy_block(block *dst, const block *src) { + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +void xor_block(block *dst, const block *src) { + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +static void load_block(block *dst, const void *input) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i])); + } +} + +static void store_block(void *output, const block *src) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory functions*****************/ + +int allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size) { + size_t memory_size = num*size; + if (memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 1. Check for multiplication overflow */ + if (size != 0 && memory_size / size != num) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 2. Try to allocate with appropriate allocator */ + if (context->allocate_cbk) { + (context->allocate_cbk)(memory, memory_size); + } else { + *memory = malloc(memory_size); + } + + if (*memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + return ARGON2_OK; +} + +void free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size) { + size_t memory_size = num*size; + clear_internal_memory(memory, memory_size); + if (context->free_cbk) { + (context->free_cbk)(memory, memory_size); + } else { + free(memory); + } +} + +#if defined(__OpenBSD__) +#define HAVE_EXPLICIT_BZERO 1 +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2,25) +#define HAVE_EXPLICIT_BZERO 1 +#endif +#endif + +void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) || defined(__MINGW32__) + SecureZeroMemory(v, n); +#elif defined memset_s + memset_s(v, n, 0, n); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(v, n); +#else + static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; + memset_sec(v, 0, n); +#endif +} + +/* Memory clear flag defaults to true. */ +int FLAG_clear_internal_memory = 1; +void clear_internal_memory(void *v, size_t n) { + if (FLAG_clear_internal_memory && v) { + secure_wipe_memory(v, n); + } +} + +void finalize(const argon2_context *context, argon2_instance_t *instance) { + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + copy_block(&blockhash, instance->memory + instance->lane_length - 1); + + /* XOR the last blocks */ + for (l = 1; l < instance->lanes; ++l) { + uint32_t last_block_in_lane = + l * instance->lane_length + (instance->lane_length - 1); + xor_block(&blockhash, instance->memory + last_block_in_lane); + } + + /* Hash the result */ + { + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + store_block(blockhash_bytes, &blockhash); + blake2b_long(context->out, context->outlen, blockhash_bytes, + ARGON2_BLOCK_SIZE); + /* clear blockhash and blockhash_bytes */ + clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE); + clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); + } + +#ifdef GENKAT + print_tag(context->out, context->outlen); +#endif + + free_memory(context, (uint8_t *)instance->memory, + instance->memory_blocks, sizeof(block)); + } +} + +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) { + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (0 == position->pass) { + /* First pass */ + if (0 == position->slice) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (0 != position->pass) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +/* Single-threaded version for p=1 case */ +static int fill_memory_blocks_st(argon2_instance_t *instance) { + uint32_t r, s, l; + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position = {r, l, (uint8_t)s, 0}; + fill_segment(instance, position); + } + } +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + return ARGON2_OK; +} + +#if !defined(ARGON2_NO_THREADS) + +#ifdef _WIN32 +static unsigned __stdcall fill_segment_thr(void *thread_data) +#else +static void *fill_segment_thr(void *thread_data) +#endif +{ + argon2_thread_data *my_data = thread_data; + fill_segment(my_data->instance_ptr, my_data->pos); + argon2_thread_exit(); + return 0; +} + +/* Multi-threaded version for p > 1 case */ +static int fill_memory_blocks_mt(argon2_instance_t *instance) { + uint32_t r, s; + argon2_thread_handle_t *thread = NULL; + argon2_thread_data *thr_data = NULL; + int rc = ARGON2_OK; + + /* 1. Allocating space for threads */ + thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t)); + if (thread == NULL) { + rc = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + thr_data = calloc(instance->lanes, sizeof(argon2_thread_data)); + if (thr_data == NULL) { + rc = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + uint32_t l, ll; + + /* 2. Calling threads */ + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position; + + /* 2.1 Join a thread if limit is exceeded */ + if (l >= instance->threads) { + if (argon2_thread_join(thread[l - instance->threads])) { + rc = ARGON2_THREAD_FAIL; + goto fail; + } + } + + /* 2.2 Create thread */ + position.pass = r; + position.lane = l; + position.slice = (uint8_t)s; + position.index = 0; + thr_data[l].instance_ptr = + instance; /* preparing the thread input */ + memcpy(&(thr_data[l].pos), &position, + sizeof(argon2_position_t)); + if (argon2_thread_create(&thread[l], &fill_segment_thr, + (void *)&thr_data[l])) { + /* Wait for already running threads */ + for (ll = 0; ll < l; ++ll) + argon2_thread_join(thread[ll]); + rc = ARGON2_THREAD_FAIL; + goto fail; + } + + /* fill_segment(instance, position); */ + /*Non-thread equivalent of the lines above */ + } + + /* 3. Joining remaining threads */ + for (l = instance->lanes - instance->threads; l < instance->lanes; + ++l) { + if (argon2_thread_join(thread[l])) { + rc = ARGON2_THREAD_FAIL; + goto fail; + } + } + } + +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + +fail: + if (thread != NULL) { + free(thread); + } + if (thr_data != NULL) { + free(thr_data); + } + return rc; +} + +#endif /* ARGON2_NO_THREADS */ + +int fill_memory_blocks(argon2_instance_t *instance) { + if (instance == NULL || instance->lanes == 0) { + return ARGON2_INCORRECT_PARAMETER; + } +#if defined(ARGON2_NO_THREADS) + return fill_memory_blocks_st(instance); +#else + return instance->threads == 1 ? + fill_memory_blocks_st(instance) : fill_memory_blocks_mt(instance); +#endif +} + +int validate_inputs(const argon2_context *context) { + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password (required param) */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + + /* Validate salt (required param) */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + + /* Validate secret (optional param) */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data (optional param) */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + + if (NULL != context->allocate_cbk && NULL == context->free_cbk) { + return ARGON2_FREE_MEMORY_CBK_NULL; + } + + if (NULL == context->allocate_cbk && NULL != context->free_cbk) { + return ARGON2_ALLOCATE_MEMORY_CBK_NULL; + } + + return ARGON2_OK; +} + +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { + uint32_t l; + /* Make the first and second block in each lane as G(H0||0||i) or + G(H0||1||i) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 0], + blockhash_bytes); + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type) { + blake2b_state BlakeHash; + uint8_t value[sizeof(uint32_t)]; + + if (NULL == context || NULL == blockhash) { + return; + } + + blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + + store32(&value, context->lanes); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->outlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->m_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->t_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->version); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, (uint32_t)type); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->pwdlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->pwd != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + secure_wipe_memory(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + } + + store32(&value, context->saltlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->salt != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->salt, + context->saltlen); + } + + store32(&value, context->secretlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->secret != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + secure_wipe_memory(context->secret, context->secretlen); + context->secretlen = 0; + } + } + + store32(&value, context->adlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->ad != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + context->adlen); + } + + blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); +} + +int initialize(argon2_instance_t *instance, argon2_context *context) { + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) + return ARGON2_INCORRECT_PARAMETER; + instance->context_ptr = context; + + /* 1. Memory allocation */ + result = allocate_memory(context, (uint8_t **)&(instance->memory), + instance->memory_blocks, sizeof(block)); + if (result != ARGON2_OK) { + return result; + } + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - + ARGON2_PREHASH_DIGEST_LENGTH); + +#ifdef GENKAT + initial_kat(blockhash, context, instance->type); +#endif + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} diff --git a/lib/argon2/core.h b/lib/argon2/core.h new file mode 100644 index 00000000000..59e25646cbc --- /dev/null +++ b/lib/argon2/core.h @@ -0,0 +1,228 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_CORE_H +#define ARGON2_CORE_H + +#include "argon2.h" + +#define CONST_CAST(x) (x)(uintptr_t) + +/**********************Argon2 internal constants*******************************/ + +enum argon2_core_constants { + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32, + ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data types***********************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +void init_block_value(block *b, uint8_t in); + +/* Copy block @src to block @dst */ +void copy_block(block *dst, const block *src); + +/* XOR @src onto @dst bytewise */ +void xor_block(block *dst, const block *src); + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block *memory; /* Memory pointer */ + uint32_t version; + uint32_t passes; /* Number of passes */ + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ + argon2_context *context_ptr; /* points back to original context */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core functions********************************/ + +/* Allocates memory to the given pointer, uses the appropriate allocator as + * specified in the context. Total allocated memory is num*size. + * @param context argon2_context which specifies the allocator + * @param memory pointer to the pointer to the memory + * @param size the size in bytes for each element to be allocated + * @param num the number of elements to be allocated + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +int allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size); + +/* + * Frees memory at the given pointer, uses the appropriate deallocator as + * specified in the context. Also cleans the memory using clear_internal_memory. + * @param context argon2_context which specifies the deallocator + * @param memory pointer to buffer to be freed + * @param size the size in bytes for each element to be deallocated + * @param num the number of elements to be deallocated + */ +void free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size); + +/* Function that securely cleans the memory. This ignores any flags set + * regarding clearing memory. Usually one just calls clear_internal_memory. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void secure_wipe_memory(void *v, size_t n); + +/* Function that securely clears the memory if FLAG_clear_internal_memory is + * set. If the flag isn't set, this function does nothing. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void clear_internal_memory(void *v, size_t n); + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane); + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +int validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +int initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param context current context + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return ARGON2_OK if successful, @context->state + */ +int fill_memory_blocks(argon2_instance_t *instance); + +#endif diff --git a/lib/argon2/ref.c b/lib/argon2/ref.c new file mode 100644 index 00000000000..10e45eba64e --- /dev/null +++ b/lib/argon2/ref.c @@ -0,0 +1,194 @@ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +#include "argon2.h" +#include "core.h" + +#include "blake2/blamka-round-ref.h" +#include "blake2/blake2-impl.h" +#include "blake2/blake2.h" + + +/* + * Function fills a new memory block and optionally XORs the old block over the new one. + * @next_block must be initialized. + * @param prev_block Pointer to the previous block + * @param ref_block Pointer to the reference block + * @param next_block Pointer to the block to be constructed + * @param with_xor Whether to XOR into the new block (1) or just overwrite (0) + * @pre all block pointers must be valid + */ +static void fill_block(const block *prev_block, const block *ref_block, + block *next_block, int with_xor) { + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */ + if (with_xor) { + /* Saving the next block contents for XOR over: */ + xor_block(&block_tmp, next_block); + /* Now blockR = ref_block + prev_block and + block_tmp = ref_block + prev_block + next_block */ + } + + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +static void next_addresses(block *address_block, block *input_block, + const block *zero_block) { + input_block->v[6]++; + fill_block(zero_block, input_block, address_block, 0); + fill_block(zero_block, address_block, address_block, 0); +} + +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position) { + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block, zero_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = + (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + init_block_value(&zero_block, 0); + init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block, &zero_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block, &zero_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + if (ARGON2_VERSION_10 == instance->version) { + /* version 1.2.1 and earlier: overwrite, not XOR */ + fill_block(instance->memory + prev_offset, ref_block, curr_block, 0); + } else { + if(0 == position.pass) { + fill_block(instance->memory + prev_offset, ref_block, + curr_block, 0); + } else { + fill_block(instance->memory + prev_offset, ref_block, + curr_block, 1); + } + } + } +} From patchwork Tue Nov 11 12:41:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 677 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=1762864942; bh=hyKKcEN1gAaBuDvCy7NebcKFJv2IM3FhJoGLrGshjE4=; 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=QT0WUTQNSdwIdb8EVJpJpInBx3o75ACG8c9g/qpvLT+7a34rfvBlrO3v08vkEGHr9 1MC9PUB9UNBFCTQ4FIWMjRUB35902Su3UAYvjVnkhy7SINKdrB9lYqzrlNrXAXaV9y U4ylMFTS+sO+zXR0UQpkZNeI2tEZ6o3ubBKXaItDZRZEg7dB/TABWoF7AQ9q4XIfHD vS8SwzW1AAL3SDuoTRBpL6NXrVZE7Wm05rbxA9E3ck4Jjazb3pPAZ1v6Lxm5EgpeqD XH1Hh02lG/aNNIE4Ys3BARs/39woBuBlgCGeKzrJXkBOcGnZzMHPMBUkG9Oc36SNgf kmZzTZqGfq8AQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9EB8268378 for ; Tue, 11 Nov 2025 05:42:22 -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 LuLQNZknv-lv for ; Tue, 11 Nov 2025 05:42:22 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864942; bh=hyKKcEN1gAaBuDvCy7NebcKFJv2IM3FhJoGLrGshjE4=; 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=QT0WUTQNSdwIdb8EVJpJpInBx3o75ACG8c9g/qpvLT+7a34rfvBlrO3v08vkEGHr9 1MC9PUB9UNBFCTQ4FIWMjRUB35902Su3UAYvjVnkhy7SINKdrB9lYqzrlNrXAXaV9y U4ylMFTS+sO+zXR0UQpkZNeI2tEZ6o3ubBKXaItDZRZEg7dB/TABWoF7AQ9q4XIfHD vS8SwzW1AAL3SDuoTRBpL6NXrVZE7Wm05rbxA9E3ck4Jjazb3pPAZ1v6Lxm5EgpeqD XH1Hh02lG/aNNIE4Ys3BARs/39woBuBlgCGeKzrJXkBOcGnZzMHPMBUkG9Oc36SNgf kmZzTZqGfq8AQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8DAEB68484 for ; Tue, 11 Nov 2025 05:42:22 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864940; bh=DW2l6Ney1IPlobiZHtPIIEug6H2rtJ43+ufI2vc6mu8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FqmfH005q7PUxwwu39gxIl8H8ujSF+Zd02Qs5NuHjtzWndITLzVWhO+oNKujT6r1d xnCWVLcSnLfeKi5GKYId1IJ97llHPjw9RRkjXzppeHOU0hUia1ZXdOfsOOOEQ/Eexs BkSMETY0LQnIs/MgxCUEFiSdksTC1e4rIKd9NHsNFmR3X4apeFW9sCwobSudQOi1Ux /u///ykM7DRUGyhNUUBJG9ZRsy5tqvHFXBd5O+qpPlhPOAiOZvc07lTpFOkHOGehrY 90cUPcAoXGiz3MhF9uNfyFg8QXmOsAdIrzskDxVV2xbDamul6/pbr9LDkWE29AcX6r uCu3rTmveNjkg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E7CE168378; Tue, 11 Nov 2025 05:42:20 -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 10026) with ESMTP id pbf3kUJTseJK; Tue, 11 Nov 2025 05:42:20 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864936; bh=uibUjZaVAvZBzYSYqqt6txxsUQuvDIjZUS4QSXkadE8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X5yq7GSf5495IJ+b3sN8DyOt9rhX9Dh2X/UzwT5+9g+XuzSYg0HX7qoPKqv/j9TNp ccxWqAie7py6No3WNf1o8ObiKTBYDmkT4E5F5xdOpHlXmOjdc7oorKom8r7wgrS/8e rDpF/RM0W14lAIJPj/MXEMc6Y2aSM2PUhaYDpF77tjdDvsP5hUOfOoxMAjFCbOYEeG kLDwXt0ZDdbke8Psz4PcD0Rw9yfZnt9MejDeRTjjGSXGWqI5PDZVL3J45JXU7D2XQL KmmKq5HMR6GKcse2D1KcTakLNV51ZRB2TVrMDGXrHSnoPmvgvJDjKHlMTo9XtVERXy cr4+uoho6lVHw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 88E0D684E0; Tue, 11 Nov 2025 05:42:16 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:12 -0700 Message-ID: <20251111124131.1198930-7-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: GWLSLQ5VW5ILXBJ52YTNTEHTVLQQ37UG X-Message-ID-Hash: GWLSLQ5VW5ILXBJ52YTNTEHTVLQQ37UG 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 06/15] lib: Adapt argon2 library for U-Boot 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 Rename argon.c to argon_wrapper.c so we can use 'argon' as the library name. Move the include file into the normal place. Add SPDX tags but otherwise keep the files as is. The code style uses spaces instead of tabs and has other differences with U-Boot Co-developed-by: Claude Signed-off-by: Simon Glass --- {lib/argon2 => include}/argon2.h | 15 ++++++-- lib/argon2/Makefile | 10 ++++++ lib/argon2/{argon2.c => argon2_wrapper.c} | 25 +++++++++++--- lib/argon2/blake2/blake2-impl.h | 10 +++--- lib/argon2/blake2/blake2.h | 1 + lib/argon2/blake2/blake2b.c | 7 ++-- lib/argon2/blake2/blamka-round-ref.h | 1 + lib/argon2/core.c | 42 +++-------------------- lib/argon2/core.h | 1 + lib/argon2/ref.c | 7 ++-- 10 files changed, 65 insertions(+), 54 deletions(-) rename {lib/argon2 => include}/argon2.h (98%) create mode 100644 lib/argon2/Makefile rename lib/argon2/{argon2.c => argon2_wrapper.c} (95%) diff --git a/lib/argon2/argon2.h b/include/argon2.h similarity index 98% rename from lib/argon2/argon2.h rename to include/argon2.h index 3980bb352f2..977739f555b 100644 --- a/lib/argon2/argon2.h +++ b/include/argon2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 */ /* * Argon2 reference source code package - reference C implementations * @@ -18,10 +19,20 @@ #ifndef ARGON2_H #define ARGON2_H -#include -#include +#include #include +/* U-Boot: Define missing integer constant macros */ +#ifndef UINT32_C +#define UINT32_C(c) c ## U +#endif +#ifndef UINT64_C +#define UINT64_C(c) c ## ULL +#endif + +/* U-Boot: Disable threading */ +#define ARGON2_NO_THREADS + #if defined(__cplusplus) extern "C" { #endif diff --git a/lib/argon2/Makefile b/lib/argon2/Makefile new file mode 100644 index 00000000000..c9f729d27e6 --- /dev/null +++ b/lib/argon2/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2025 Canonical Ltd +# +# Argon2 password hashing library +# Based on PHC winner: https://github.com/P-H-C/phc-winner-argon2 + +obj-$(CONFIG_ARGON2) += argon2.o + +argon2-y := argon2_wrapper.o core.o ref.o blake2/blake2b.o diff --git a/lib/argon2/argon2.c b/lib/argon2/argon2_wrapper.c similarity index 95% rename from lib/argon2/argon2.c rename to lib/argon2/argon2_wrapper.c index 34da3d6b4ac..2c1882165f1 100644 --- a/lib/argon2/argon2.c +++ b/lib/argon2/argon2_wrapper.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 /* * Argon2 reference source code package - reference C implementations * @@ -15,12 +16,12 @@ * software. If not, they may be obtained at the above URLs. */ -#include -#include -#include +/* U-Boot: Use U-Boot headers */ +#include +#include +#include #include "argon2.h" -#include "encoding.h" #include "core.h" const char *argon2_type2string(argon2_type type, int uppercase) { @@ -161,6 +162,15 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, memcpy(hash, out, hashlen); } + /* U-Boot: encoding not supported (requires encoding.c) */ +#ifdef __UBOOT__ + /* Return error if encoding requested */ + if (encoded && encodedlen) { + clear_internal_memory(out, hashlen); + free(out); + return ARGON2_ENCODING_FAIL; + } +#else /* if encoding requested, write it */ if (encoded && encodedlen) { if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { @@ -170,6 +180,7 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, return ARGON2_ENCODING_FAIL; } } +#endif clear_internal_memory(out, hashlen); free(out); @@ -236,6 +247,8 @@ int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, ARGON2_VERSION_NUMBER); } +/* U-Boot: verify functions not needed */ +#ifndef __UBOOT__ static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { size_t i; uint8_t d = 0U; @@ -364,6 +377,7 @@ int argon2i_verify_ctx(argon2_context *context, const char *hash) { int argon2id_verify_ctx(argon2_context *context, const char *hash) { return argon2_verify_ctx(context, hash, Argon2_id); } +#endif /* U-Boot: verify functions */ const char *argon2_error_message(int error_code) { switch (error_code) { @@ -444,9 +458,12 @@ const char *argon2_error_message(int error_code) { } } +/* U-Boot: encodedlen not needed */ +#ifndef __UBOOT__ size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, uint32_t saltlen, uint32_t hashlen, argon2_type type) { return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) + numlen(t_cost) + numlen(m_cost) + numlen(parallelism) + b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1; } +#endif /* U-Boot: encodedlen */ diff --git a/lib/argon2/blake2/blake2-impl.h b/lib/argon2/blake2/blake2-impl.h index 86d0d5cfa9b..5cdb2fc8b4f 100644 --- a/lib/argon2/blake2/blake2-impl.h +++ b/lib/argon2/blake2/blake2-impl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 */ /* * Argon2 reference source code package - reference C implementations * @@ -18,12 +19,11 @@ #ifndef PORTABLE_BLAKE2_IMPL_H #define PORTABLE_BLAKE2_IMPL_H -#include -#include +/* U-Boot includes */ +#include +#include -#ifdef _WIN32 -#define BLAKE2_INLINE __inline -#elif defined(__GNUC__) || defined(__clang__) +#if defined(__GNUC__) || defined(__clang__) #define BLAKE2_INLINE __inline__ #else #define BLAKE2_INLINE diff --git a/lib/argon2/blake2/blake2.h b/lib/argon2/blake2/blake2.h index 501c6a3186d..6c7bb6625fe 100644 --- a/lib/argon2/blake2/blake2.h +++ b/lib/argon2/blake2/blake2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 */ /* * Argon2 reference source code package - reference C implementations * diff --git a/lib/argon2/blake2/blake2b.c b/lib/argon2/blake2/blake2b.c index 3b519ddb4d0..f0e78a5c671 100644 --- a/lib/argon2/blake2/blake2b.c +++ b/lib/argon2/blake2/blake2b.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 /* * Argon2 reference source code package - reference C implementations * @@ -15,9 +16,9 @@ * software. If not, they may be obtained at the above URLs. */ -#include -#include -#include +/* U-Boot includes */ +#include +#include #include "blake2.h" #include "blake2-impl.h" diff --git a/lib/argon2/blake2/blamka-round-ref.h b/lib/argon2/blake2/blamka-round-ref.h index 16cfc1c74af..3b60c384b38 100644 --- a/lib/argon2/blake2/blamka-round-ref.h +++ b/lib/argon2/blake2/blamka-round-ref.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 */ /* * Argon2 reference source code package - reference C implementations * diff --git a/lib/argon2/core.c b/lib/argon2/core.c index e697882eb96..4662cf05bf5 100644 --- a/lib/argon2/core.c +++ b/lib/argon2/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 /* * Argon2 reference source code package - reference C implementations * @@ -15,32 +16,14 @@ * software. If not, they may be obtained at the above URLs. */ -/*For memory wiping*/ -#ifdef _WIN32 -#include -#include /* For SecureZeroMemory */ -#endif -#if defined __STDC_LIB_EXT1__ -#define __STDC_WANT_LIB_EXT1__ 1 -#endif -#define VC_GE_2005(version) (version >= 1400) - -/* for explicit_bzero() on glibc */ -#define _DEFAULT_SOURCE - -#include -#include -#include +/* U-Boot includes */ +#include +#include #include "core.h" -#include "thread.h" #include "blake2/blake2.h" #include "blake2/blake2-impl.h" -#ifdef GENKAT -#include "genkat.h" -#endif - #if defined(__clang__) #if __has_attribute(optnone) #define NOT_OPTIMIZED __attribute__((optnone)) @@ -123,25 +106,10 @@ void free_memory(const argon2_context *context, uint8_t *memory, } } -#if defined(__OpenBSD__) -#define HAVE_EXPLICIT_BZERO 1 -#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) -#if __GLIBC_PREREQ(2,25) -#define HAVE_EXPLICIT_BZERO 1 -#endif -#endif - void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { -#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) || defined(__MINGW32__) - SecureZeroMemory(v, n); -#elif defined memset_s - memset_s(v, n, 0, n); -#elif defined(HAVE_EXPLICIT_BZERO) - explicit_bzero(v, n); -#else + /* Use volatile pointer to prevent compiler optimization */ static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; memset_sec(v, 0, n); -#endif } /* Memory clear flag defaults to true. */ diff --git a/lib/argon2/core.h b/lib/argon2/core.h index 59e25646cbc..0c27fc6541d 100644 --- a/lib/argon2/core.h +++ b/lib/argon2/core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 */ /* * Argon2 reference source code package - reference C implementations * diff --git a/lib/argon2/ref.c b/lib/argon2/ref.c index 10e45eba64e..d67292c856f 100644 --- a/lib/argon2/ref.c +++ b/lib/argon2/ref.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 /* * Argon2 reference source code package - reference C implementations * @@ -15,9 +16,9 @@ * software. If not, they may be obtained at the above URLs. */ -#include -#include -#include +/* U-Boot includes */ +#include +#include #include "argon2.h" #include "core.h" From patchwork Tue Nov 11 12:41:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 678 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=1762864947; bh=Rv7sNc1ZZyW9IdM1VXW3xf2deX3NNJwnjiVZH207auI=; 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=SRiiFD/Daizp9JARxKcHqken/A1IwWg7sZ7jBW9Dt1JTYj2Rmc4iRCoXGH81Qywzb iz2eK9VLRnRdMZIiTO04qAFctcsRq+OeCdADrXrBp5GFYX8c3AS8/ppnIW3I9/gQ6h SHC88ax/Lwb4I/H5ao+ENx1Eo7SnJQ1EtoTMp7eb7KfZUwbyCVcdFUfwry/iNpILMN OBtZex1qUq+FnTPzm3ROgJTW8H54rRpXiliYjWdBBYeCd9trbPpx4xFqe2BeDN1LCY 2ugv21BpX1QBOD8b06H763TSV7sgmg5IDc34d15DqInQ7DLFLIpjC7Vr1XnjN9rX0h BFaN4WjtltRXA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 31794684E5 for ; Tue, 11 Nov 2025 05:42:27 -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 5rsBWzoMQq3k for ; Tue, 11 Nov 2025 05:42:27 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864947; bh=Rv7sNc1ZZyW9IdM1VXW3xf2deX3NNJwnjiVZH207auI=; 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=SRiiFD/Daizp9JARxKcHqken/A1IwWg7sZ7jBW9Dt1JTYj2Rmc4iRCoXGH81Qywzb iz2eK9VLRnRdMZIiTO04qAFctcsRq+OeCdADrXrBp5GFYX8c3AS8/ppnIW3I9/gQ6h SHC88ax/Lwb4I/H5ao+ENx1Eo7SnJQ1EtoTMp7eb7KfZUwbyCVcdFUfwry/iNpILMN OBtZex1qUq+FnTPzm3ROgJTW8H54rRpXiliYjWdBBYeCd9trbPpx4xFqe2BeDN1LCY 2ugv21BpX1QBOD8b06H763TSV7sgmg5IDc34d15DqInQ7DLFLIpjC7Vr1XnjN9rX0h BFaN4WjtltRXA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 20C6D68472 for ; Tue, 11 Nov 2025 05:42:27 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864945; bh=yHh4NR6nF6anO53//t6mBrR9w+RNY8fGJq9fX85M55E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kJ6lKyPedwYNmE/KRwvP19O89m0OYcknDlD6MIxIRfYGKZrhNKR3C4RORGUUvYgUC SVEMsfpfyzMuaYFr3CGPd0ZA7IvvhM9HNXWCOjkCpbj8tt1VLE5faXXq8ZvzyCn18O Ebdkn4tySlbjGb/p6eECx8SYwOBC+639Lpyn7fVbrGNnikBoUkA+1Si7SQnRN0oOrG 145yly3e8EwhftPdsY/1kQY4w5t43/nH4zRJLYooaAl7JLAteQHN55HOaTByZYtnjN VGKXGx+WMwqFAsYHDHYZg5eYvCPlNcbbVQH/DjNggX7KoWNj0DQ0hOTCl+j+Q0JpnX 5q0eXy7JTPI5g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8AA7868378; Tue, 11 Nov 2025 05:42:25 -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 10026) with ESMTP id QJvE1RRqkSDK; Tue, 11 Nov 2025 05:42:25 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864941; bh=Y1nR77+k+XBhBd0Y6j6iW5TDIS6roGz9V6fYSMvYSMk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TVBU1G7cWM/FcllWgZF1G7RlU3JnhjSyOeOL5G3ye85OHbQApvprv900IQeVHFlm4 dlMNNqOrEa3XnZCctVMmloeWSkVFn3CwOeB6VrzL5dm3goj1LUbTPIZXQf+d7hTiGO TrJsLcJnChN2qxXTQjoMBtD1ZLRuW2xiBkN1D4XtSRQ9CB8sDOfwmG7oAdSjp+cEc4 7GUliF+vyVkAAfQPHmw35sr8rp6tvhdPkXMntfYWFlHudxQnK+5QcoRrIQTEPbJgJC 9B+ljhQdSFkKHEvIfgcImUesRx3ZT9yB877z0FIxmBzRDMCq70tadoKf5a0WSD9iNy Bs1LUW0rfIb1w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 34D326841A; Tue, 11 Nov 2025 05:42:21 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:13 -0700 Message-ID: <20251111124131.1198930-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: JWSBUUWOBGMEXGRCELN35OS6TKZXDA3O X-Message-ID-Hash: JWSBUUWOBGMEXGRCELN35OS6TKZXDA3O 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 07/15] lib: Plumb in argon2 library 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 Add a Kconfig optiion to enable this library and add it to the lib/ Makefile, being careful to avoid a conflict with the existing blake2b implementation. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/misc/Kconfig | 2 +- fs/btrfs/Kconfig | 2 +- lib/Kconfig | 14 +++++++++++++- lib/Makefile | 4 ++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a352fa5fee0..7a217ad055d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -37,7 +37,7 @@ config TKEY bool "TKey security token support" depends on DM default y if SANDBOX - select BLAKE2 + select BLAKE2 if !ARGON2 help Enable driver model support for Tillitis TKey security tokens. This provides a common interface for TKey operations including diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index e31afe595f3..c6430f83452 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -6,7 +6,7 @@ config FS_BTRFS select ZSTD select RBTREE select SHA256 - select BLAKE2 + select BLAKE2 if !ARGON2 help This provides a single-device read-only BTRFS support. BTRFS is a next-generation Linux file system based on the copy-on-write diff --git a/lib/Kconfig b/lib/Kconfig index c8bf4b4b049..662b1a44d45 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -542,11 +542,12 @@ menu "Hashing Support" config BLAKE2 bool "Enable BLAKE2 support" + depends on !ARGON2 help This option enables support of hashing using BLAKE2B algorithm. The hash is calculated in software. The BLAKE2 algorithm produces a hash value (digest) between 1 and - 64 bytes. + 64 bytes. Note: ARGON2 includes its own BLAKE2 implementation. config SHA1 bool "Enable SHA1 support" @@ -983,6 +984,17 @@ config JSON printing functions. JSON is used for structured data representation, such as LUKS2 metadata. +config ARGON2 + bool "Enable Argon2 password hashing" + help + This enables the Argon2 password hashing algorithm, winner of the + Password Hashing Competition (PHC). Argon2 is used for key derivation + in LUKS2 encrypted volumes. It provides better resistance to GPU + cracking attacks compared to PBKDF2. + + Note: This option includes its own BLAKE2 implementation and is + mutually exclusive with CONFIG_BLAKE2. + config OF_LIBFDT bool "Enable the FDT library" default y if OF_CONTROL diff --git a/lib/Makefile b/lib/Makefile index 71c9c0d1766..5cbf3071f96 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -80,7 +80,10 @@ obj-$(CONFIG_$(PHASE_)ACPI) += acpi/ obj-$(CONFIG_ECDSA) += ecdsa/ obj-$(CONFIG_$(PHASE_)RSA) += rsa/ obj-$(CONFIG_HASH) += hash-checksum.o + +# argon2 provides its own blake2b; just build blake2s when ARGON2 is enabled obj-$(CONFIG_BLAKE2) += blake2/blake2b.o blake2/blake2s.o +obj-$(CONFIG_ARGON2) += blake2/blake2s.o obj-$(CONFIG_$(PHASE_)MD5_LEGACY) += md5.o obj-$(CONFIG_$(PHASE_)SHA1_LEGACY) += sha1.o @@ -89,6 +92,7 @@ obj-$(CONFIG_$(PHASE_)SHA256_LEGACY) += sha256.o obj-$(CONFIG_$(PHASE_)SHA512_LEGACY) += sha512.o obj-$(CONFIG_CRYPT_PW) += crypt/ +obj-$(CONFIG_ARGON2) += argon2/ obj-$(CONFIG_$(PHASE_)ASN1_DECODER_LEGACY) += asn1_decoder.o obj-$(CONFIG_$(PHASE_)ZLIB) += zlib/ From patchwork Tue Nov 11 12:41:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 679 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=1762864951; bh=Kj8klNcgg7geafHvza4FAQhM/3ciZ6Ir94pBGsyzbIc=; 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=eyvI9O2iB5GZssuy5oDPocjdzMNk6d3DBjFHUV6T8ERk4rU3dAvAadAwgC+GCUjoY JDHJ594hq1tGwR+3S+va1RdBT3h3y1TcVeu6bitW8R3E+U2D04caCAAcJ8NC1X8M6P /bFr4d7anKBWMKfZk5/OIjPJqYTwIKIBpTO4v9BYUAH9WcMftCz7Q82aK6G456X8gC eWTAM+4N0+Gu6E7MVKAl67CUwitT9mdC0+4FbKQxXDP38ZD5fre3fxgdDP4cfmMj4E +TsU3Q0hQ82GhNfA0wydb1HhRX72HC4zeem3zlGuer4OLOR9MtdGs0/eujREtgIPzu CmcuRn4L18KIQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id ECDA2684E7 for ; Tue, 11 Nov 2025 05:42:31 -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 kRwioWRha9NK for ; Tue, 11 Nov 2025 05:42:31 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864951; bh=Kj8klNcgg7geafHvza4FAQhM/3ciZ6Ir94pBGsyzbIc=; 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=eyvI9O2iB5GZssuy5oDPocjdzMNk6d3DBjFHUV6T8ERk4rU3dAvAadAwgC+GCUjoY JDHJ594hq1tGwR+3S+va1RdBT3h3y1TcVeu6bitW8R3E+U2D04caCAAcJ8NC1X8M6P /bFr4d7anKBWMKfZk5/OIjPJqYTwIKIBpTO4v9BYUAH9WcMftCz7Q82aK6G456X8gC eWTAM+4N0+Gu6E7MVKAl67CUwitT9mdC0+4FbKQxXDP38ZD5fre3fxgdDP4cfmMj4E +TsU3Q0hQ82GhNfA0wydb1HhRX72HC4zeem3zlGuer4OLOR9MtdGs0/eujREtgIPzu CmcuRn4L18KIQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DBB2868484 for ; Tue, 11 Nov 2025 05:42:31 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864950; bh=DvglxEdc6yPAbGFLmK0OjSj95cA6CxUTEJqNqUUHwrQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=abSk6Bs3kwNnS6Oe18Xb6V2bYW6zSB+GTKZQMFqo3VagIHEiSPiTv9oF4hvXv6ZPJ KOi9XT0XnXiUa59yYGkWyqEN4Y61jd/Uh0l/BRQdXD7E/lir8r4NaDtRK6jlRcfdpf 0MtcS+iLQG0sKwKmITmdLQqvm7JkRRuZFosrTBdvdhOs46iLtqVGgbeQTmm1jZnhEL CnnSlaIkAa/Ej1cnhgaWk2QgB8Z/LqDV4YClfvqFPy8PFcUFrA7QyZlANSvxhAaB2y ZxK/LheFFpn5Im78ei7gVgzBGU62DxolTpnlr97SfkJH6BomfLKc4atCjO1/IRvrBR INlCNe7Jk0Vxw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 32F1D68484; Tue, 11 Nov 2025 05:42:30 -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 10026) with ESMTP id uhSIUw-Gwtfn; Tue, 11 Nov 2025 05:42:30 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864946; bh=F7/g58lu819hNQLiYLEleoBZ5zYXX9dQ/ZsHSikOuZU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ufnbdgmWv7ozZcrMjTV/e9craAnDkARxQFuCpA7e/42skgMSP99n7OxFKRvaWOCkG K8pW3BUq21/ScWV6R5v7frYTOU3CbaDltceDacqttPRE6nvkh5HRG90rKTA1EkiuP1 KEDc3hMf95AK7awRisDPGmspd+eq0nB5OXB5ucX/fmriMjRXxJy9chWDbNBHecsjmv NsxVSiLCXMh6yIB88rZfIWa6otjE76ky8UoqXw0FZNGziqj8ptzrp37Xb8Aq0cN6Qq tdLWVpqzXumaxxA1uZRxFg+vpQa9sgCCDCt3QWGrt42UT9zCA5qRMgY8EqxmfVeGwF L3ICLRMXG4lXA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id CCA886841A; Tue, 11 Nov 2025 05:42:25 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:14 -0700 Message-ID: <20251111124131.1198930-9-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: DIPQMVEK4ONPHB7RLUU6KGEQDI3VRXTG X-Message-ID-Hash: DIPQMVEK4ONPHB7RLUU6KGEQDI3VRXTG 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: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 08/15] test: Shorten the encrypt_passphrase parameter for FsHelper 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 This is very long and the 'encrypt' part is implied by the passphrase. Shorten it to just 'passphrase'. Signed-off-by: Simon Glass --- doc/usage/luks.rst | 2 +- test/py/img/common.py | 2 +- test/py/tests/fs_helper.py | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/usage/luks.rst b/doc/usage/luks.rst index a87abe140db..24be8d1ea81 100644 --- a/doc/usage/luks.rst +++ b/doc/usage/luks.rst @@ -232,7 +232,7 @@ See ``test/py/tests/fs_helper.py`` for the ``FsHelper`` class:: # Create encrypted filesystem with FsHelper(config, 'ext4', 30, 'test', part_mb=60, - encrypt_passphrase='mypassword') as fsh: + passphrase='mypassword') as fsh: # Add files to fsh.srcdir with open(os.path.join(fsh.srcdir, 'hello.txt'), 'w') as f: f.write('Hello from LUKS!\n') diff --git a/test/py/img/common.py b/test/py/img/common.py index 3b3fdb2734b..f5a7fcba804 100644 --- a/test/py/img/common.py +++ b/test/py/img/common.py @@ -82,7 +82,7 @@ def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, ext4 = FsHelper(config, 'ext4', max(1, part2_size - 30), prefix=basename, part_mb=part2_size, - encrypt_passphrase='test' if use_fde else None, + passphrase='test' if use_fde else None, luks_version=use_fde if use_fde else 2) ext4.setup() diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index 914de09e381..4812d3f053b 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -41,7 +41,7 @@ class FsHelper: To create an encrypted LUKS2 partition (default): with FsHelper(ubman.config, 'ext4', 10, 'mmc1', - encrypt_passphrase='test') as fsh: + passphrase='test') as fsh: # create files in the fsh.srcdir directory fsh.mk_fs() # Creates and encrypts the filesystem with LUKS2 ... @@ -49,7 +49,7 @@ class FsHelper: To create an encrypted LUKS1 partition: with FsHelper(ubman.config, 'ext4', 10, 'mmc1', - encrypt_passphrase='test', luks_version=1) as fsh: + passphrase='test', luks_version=1) as fsh: # create files in the fsh.srcdir directory fsh.mk_fs() # Creates and encrypts the filesystem with LUKS1 ... @@ -59,7 +59,7 @@ class FsHelper: default value but can be overwritten """ def __init__(self, config, fs_type, size_mb, prefix, part_mb=None, - encrypt_passphrase=None, luks_version=2): + passphrase=None, luks_version=2): """Set up a new object Args: @@ -71,7 +71,7 @@ class FsHelper: part_mb (int, optional): Size of partition in MB. If None, defaults to size_mb. This can be used to make the partition larger than the filesystem, to create space for disk-encryption metadata - encrypt_passphrase (str, optional): If provided, encrypt the + passphrase (str, optional): If provided, encrypt the filesystem with LUKS using this passphrase luks_version (int): LUKS version to use (1 or 2). Defaults to 2. """ @@ -85,7 +85,7 @@ class FsHelper: self.partition_mb = part_mb if part_mb is not None else size_mb self.prefix = prefix self.quiet = True - self.encrypt_passphrase = encrypt_passphrase + self.passphrase = passphrase self.luks_version = luks_version # Use a default filename; the caller can adjust it @@ -159,8 +159,8 @@ class FsHelper: shell=True) # Encrypt the filesystem if requested - if self.encrypt_passphrase: - self.encrypt_luks(self.encrypt_passphrase) + if self.passphrase: + self.encrypt_luks(self.passphrase) def setup(self): """Set up the srcdir ready to receive files""" From patchwork Tue Nov 11 12:41:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 680 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=1762864954; bh=BjJriXhsd/i3FV/rTHq2syvLvq1mJ8BWOon5NYYvvA8=; 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=IkecAJcrNbDHFFFj734Uf/LTjw2cgpy8DKvoo++jQmIkfO26vvlOlHEtxF11i2J3v KsQFldAzUxkfUiM8Kd6SmD3wWyvXZfsqgKhQYk6LszSlbo7rhoWSkA1p3nfrlfhDB8 CVEdLXcGevtsGvENt5L3KsykNKeWOFHfJwC5uXD70K2YmYVWEwewPhPy3SCs5e+5jT 5hD7g90bmxMyuxqu0UNrx8R2eAOatms5yScQaixxAIN6pB4hYOcmZ5e3/ww2XFIR2f 4QXO35+60pAcF3c8gEFlPg5EZ2EtlFsonS/9xTn/Yo9HPEoIeolelgzR4vx7EiuOZe EghDq3RBGPdCw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 69002684E7 for ; Tue, 11 Nov 2025 05:42:34 -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 dNodlt8RmZIf for ; Tue, 11 Nov 2025 05:42:34 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864952; bh=BjJriXhsd/i3FV/rTHq2syvLvq1mJ8BWOon5NYYvvA8=; 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=CFLltSxzq9BqCOK0aZmSH99hTUwLGe8wq9tsZDajKs8he6+b/kC6Y38hcsQij+Hk9 AVW5qQZ48lneRhdxiaGWgoL8/UH2UU8obhpdL3gAxkD8RxzgUJlQtX1zRoWKlqfj/H 4YQif5MEAU+LBWbnvZ806QvCqJaZRv+wF60bT13tHnf44VO29hevOSeKmd9XC/RSmF IVFrCc5LEl0uZE6QCan1zkijLToO/JofZCyGxWMlm7Vx3hTZmY8MRDVx2gSHv0xJtS JLm9SAdsaQ5Ju/HxR5GAv4jhkUHrM465pLiXRSbnqajAdqE/iQ091EMR6gpIOyowtY W2gZwrcgLjgdw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 673DB68484 for ; Tue, 11 Nov 2025 05:42:32 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864951; bh=qLeefS57+ZrGbueB8QRNGuca6rxsLdUfp43aHyKWQSs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UsWpT+SuTkjRqhrHHXbJoy0EffHSpmqW0mmUBj4WImgfMJKSkq7j3Zw+KT5iy29DI 7d6aR1MjahGFtLEl5fSXyEwIZJoq7HBQphIHRCgDrMZ+zUBP2O9hEFeyacAtkYwvRQ Y3i5GC1Mw/mSfwcBTE9/t/aAuOyl/Q5LjgQIe1ksSKfok8fM9BxeDmg9L37pbxnQSk rXh3fkzbl3fkXKmlDs8o1SKI76ZFl2ap0ZMTm8bydn0UIkeLdTWm3vuTup4eLiC/Kc pk51NV9gBobXS7ZCsl+GAXKo1Z2TCxwHdUdwcubsYmkPrHREkYeea64IfgiY+dJWNz hIaZOu3Wl8mJg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 0BCDB684C9; Tue, 11 Nov 2025 05:42:31 -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 10026) with ESMTP id KAdYqqaHsD2n; Tue, 11 Nov 2025 05:42:30 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864950; bh=wH+CEiD7mGW7UPjTvouxu1Z6sR8yv9mryuMMP+miNHg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=l5TeBau055gFsmsmQ1FW51k5DFdJ1Nu7UytVX4KNZG6DOHnyTeG0Ihh2tO26aUOdv Q/N3Odeu6ZBT1BXmL2hcIOIBB2ZfIs/fO0rwg1/s/gKTErv5z15khjIxhgOsZTzXCb yr5epxJXlVHkllXa6k8lYZd6Ftn44xkGKZ92fkqRaNp2auVlaU3cWtC8hepHbTC0Ns Ks2D0XqEKpARvIcIBm0BIjmIUgHSww8OYqvB8foBH8wienczOgYeHr6ZTwtKoQwxOi RfT4Iakq1I+3B4jrizOOcIcquGNV7IcQIV2QFJPNNNfuJnsc5M2aXugdytMXaRIppv y9bZQegX/vxWA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 72A566841A; Tue, 11 Nov 2025 05:42:30 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:15 -0700 Message-ID: <20251111124131.1198930-10-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: WUSCD2RFHOKRR5OWSUWZZHE2D6CEBU5T X-Message-ID-Hash: WUSCD2RFHOKRR5OWSUWZZHE2D6CEBU5T 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 09/15] test: Add a way to create a LUKS2 partition with XTS 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 For LUKS version 2, argon is normally used in preference to pbkdf2. Add an argument to specify this when creating a filesystem. Co-developed-by: Claude Signed-off-by: Simon Glass --- test/py/tests/fs_helper.py | 40 ++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index 4812d3f053b..d88cc270b95 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -54,12 +54,20 @@ class FsHelper: fsh.mk_fs() # Creates and encrypts the filesystem with LUKS1 ... + To create an encrypted LUKS2 partition with Argon2id: + + with FsHelper(ubman.config, 'ext4', 10, 'mmc1', + passphrase='test', luks_kdf='argon2id') as fsh: + # create files in the fsh.srcdir directory + fsh.mk_fs() # Creates and encrypts the FS with LUKS2+Argon2 + ... + Properties: fs_img (str): Filename for the filesystem image; this is set to a default value but can be overwritten """ def __init__(self, config, fs_type, size_mb, prefix, part_mb=None, - passphrase=None, luks_version=2): + passphrase=None, luks_version=2, luks_kdf='pbkdf2'): """Set up a new object Args: @@ -74,6 +82,8 @@ class FsHelper: passphrase (str, optional): If provided, encrypt the filesystem with LUKS using this passphrase luks_version (int): LUKS version to use (1 or 2). Defaults to 2. + luks_kdf (str): Key derivation function for LUKS2: 'pbkdf2' or + 'argon2id'. Defaults to 'pbkdf2'. Ignored for LUKS1. """ if ('fat' not in fs_type and 'ext' not in fs_type and fs_type not in ['exfat', 'fs_generic']): @@ -87,6 +97,7 @@ class FsHelper: self.quiet = True self.passphrase = passphrase self.luks_version = luks_version + self.luks_kdf = luks_kdf # Use a default filename; the caller can adjust it leaf = f'{prefix}.{fs_type}.img' @@ -238,13 +249,26 @@ class FsHelper: try: # Format as LUKS (version determined by luks_type) - run(['cryptsetup', 'luksFormat', - '--type', luks_type, - '--cipher', cipher, - '--key-size', key_size_str, - '--hash', hash_alg, - '--iter-time', '10', # Very fast for testing (low security) - luks_img], + cmd = ['cryptsetup', 'luksFormat', + '--type', luks_type, + '--cipher', cipher, + '--key-size', key_size_str, + '--hash', hash_alg, + '--iter-time', '10'] # Very fast for testing (low security) + + # For LUKS2, specify the KDF (pbkdf2 or argon2id) + if self.luks_version == 2: + cmd.extend(['--pbkdf', self.luks_kdf]) + # For Argon2, use low memory/time settings suitable for testing + if self.luks_kdf == 'argon2id': + cmd.extend([ + '--pbkdf-memory', '65536', # 64MB + '--pbkdf-parallel', '4', + ]) + + cmd.append(luks_img) + + run(cmd, input=f'{passphrase}\n'.encode(), stdout=DEVNULL if self.quiet else None, stderr=DEVNULL if self.quiet else None, From patchwork Tue Nov 11 12:41:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 681 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=1762864958; bh=XKj56XiLFi/PqLr9mERZHDXKhij14IpPie7F8BbE564=; 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=Fs85O5YLMf0K1MX0dgOwnphh+2D7nBNi2eCV2dnwJV+yMccNFJklFX7F8W5DM6gTm nnOUcJjmt4+vi89Q/0VlN2bHg1GzTTeMoGoPehoyXa/GAa40DzlmGTVOxYlsd/HUuV gte84uIXg4zYv9ZaeN/iFi7QU8edZM+KgTDiyo6OIl0sXwArZd7sI0KdRWjMNz3NHJ hYDnWEjAtsPh73iY6Vebj5cmP7QJ2mO77HuPcHhJDkbIWlHfkPIe8nxSRaRxhxDc3p qyvsqOnPMEtvjZ/kHecng/DN5v+wYt9spVOzkjNOtt1JIlUMZDIaKsLdD87+B9xDD3 SBELw1H+c0/Cw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B0EB668484 for ; Tue, 11 Nov 2025 05:42:38 -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 tOetjqXDQ9YT for ; Tue, 11 Nov 2025 05:42:38 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864958; bh=XKj56XiLFi/PqLr9mERZHDXKhij14IpPie7F8BbE564=; 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=Fs85O5YLMf0K1MX0dgOwnphh+2D7nBNi2eCV2dnwJV+yMccNFJklFX7F8W5DM6gTm nnOUcJjmt4+vi89Q/0VlN2bHg1GzTTeMoGoPehoyXa/GAa40DzlmGTVOxYlsd/HUuV gte84uIXg4zYv9ZaeN/iFi7QU8edZM+KgTDiyo6OIl0sXwArZd7sI0KdRWjMNz3NHJ hYDnWEjAtsPh73iY6Vebj5cmP7QJ2mO77HuPcHhJDkbIWlHfkPIe8nxSRaRxhxDc3p qyvsqOnPMEtvjZ/kHecng/DN5v+wYt9spVOzkjNOtt1JIlUMZDIaKsLdD87+B9xDD3 SBELw1H+c0/Cw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 99E9D68472 for ; Tue, 11 Nov 2025 05:42:38 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864956; bh=o+kdP0+QcXA7J+L1YzamG0nOxq5bX5XfsFYRoaLXoSw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WoSfJKLhf0VtC7NycupXswTgjRL18axLNiAkq4RRUwyFv8IDJlbkc+TCRwY2IxhJj 71VVmfQ8UPal1ZFR3nPy45Wa+TiEN04FoMs9aXoUl9BRGQdMf/eVDYZuBRUBi/f9D4 XJqTYx6F2ml64Z9XZ3diBHYZqft+JPTBjH5h6wdUhBv1qZ4u/zxwcJpaZ59pSiHsVp Y7kYZreDiIKz62W2YXELxz0nPIT1yRdQu82vREqk5twJXRSjVi4bweWQIeKiS+KMsO DkuYG0XZ8H2vuNSCgHqWTr04EYRpDm414E9tTy8V3DPnk7pGGvIP0wdYMg1JpO/Ay6 TtZYz+nxdzPNA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id BFA8268484; Tue, 11 Nov 2025 05:42:36 -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 10026) with ESMTP id mW2xbR4Av5Y1; Tue, 11 Nov 2025 05:42:36 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864951; bh=A2I7epQHKWovgP2RQYVVKn0bJipV5kXAxZMN5fGMG/U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nzjLZUXtGefL/eFqf9vRXfZVUfPeZEUD8t2X+23RNGKdQVYmZ3WwrCUldu7I0t4Uk M2IqbgjbG4QzbSwr7xe+QGrcxmU6PjUmK0SkWxQb+fqlhzGon7i5CRV2/ZDqxvUoD2 pheEg3LVK8f8cCzTRn/so/jpfjxLSekao3AdM+Z4Me8RyGjVav3pyXH20ySbUfFbHp nYomkYmIinns0l57Tbz8IcaenybKe/EKdrJF31rANJH4hQWnzwXYDRkpAbv0HQZBhJ 2wE9ygUZXwnA0JOC2fyxUgSwxdFtpdyj0bbBtATet/ZoS6FNlj7cqaFx4mz70exqvO E4Js/9CxBAMsA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 498006841A; Tue, 11 Nov 2025 05:42:31 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:16 -0700 Message-ID: <20251111124131.1198930-11-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 64XJT3TQL7H5AFETJN4XYHEAUDHBFQCY X-Message-ID-Hash: 64XJT3TQL7H5AFETJN4XYHEAUDHBFQCY 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: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 10/15] test: Switch mmc12 over to use argon2id 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 Use the more common argon2id algorithm for this disk so that we can test the implementation. Signed-off-by: Simon Glass --- test/py/img/common.py | 7 +++++-- test/py/img/ubuntu.py | 6 ++++-- test/py/tests/test_ut.py | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test/py/img/common.py b/test/py/img/common.py index f5a7fcba804..74ea04771c7 100644 --- a/test/py/img/common.py +++ b/test/py/img/common.py @@ -33,7 +33,7 @@ def copy_partition(ubman, fsfile, outname): def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, - script, part2_size=1, use_fde=0): + script, part2_size=1, use_fde=0, luks_kdf='pbkdf2'): """Create a 20MB disk image with a single FAT partition Args: @@ -47,6 +47,8 @@ def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, script (str): Script to place in the extlinux.conf file part2_size (int): Size of second partition in MB (default: 1) use_fde (int): LUKS version for full-disk encryption (0=none, 1=LUKS1, 2=LUKS2) + luks_kdf (str): Key derivation function for LUKS2: 'pbkdf2' or 'argon2id'. + Defaults to 'pbkdf2'. Ignored for LUKS1. """ fsh = FsHelper(config, 'vfat', 18, prefix=basename) fsh.setup() @@ -83,7 +85,8 @@ def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, ext4 = FsHelper(config, 'ext4', max(1, part2_size - 30), prefix=basename, part_mb=part2_size, passphrase='test' if use_fde else None, - luks_version=use_fde if use_fde else 2) + luks_version=use_fde if use_fde else 2, + luks_kdf=luks_kdf) ext4.setup() bindir = os.path.join(ext4.srcdir, 'bin') diff --git a/test/py/img/ubuntu.py b/test/py/img/ubuntu.py index b783f7eb3cf..243fa38d021 100644 --- a/test/py/img/ubuntu.py +++ b/test/py/img/ubuntu.py @@ -7,7 +7,7 @@ from img.common import setup_extlinux_image def setup_ubuntu_image(config, log, devnum, basename, version='24.04.1 LTS', - use_fde=0): + use_fde=0, luks_kdf='pbkdf2'): """Create a Ubuntu disk image with a FAT partition and ext4 partition This creates a FAT partition containing extlinux files, kernel, etc. and a @@ -19,6 +19,8 @@ def setup_ubuntu_image(config, log, devnum, basename, version='24.04.1 LTS', devnum (int): Device number to use, e.g. 1 basename (str): Base name to use in the filename, e.g. 'mmc' use_fde (int): LUKS version for full-disk encryption (0=none, 1=LUKS1, 2=LUKS2) + luks_kdf (str): Key derivation function for LUKS2: 'pbkdf2' or 'argon2id'. + Defaults to 'pbkdf2'. Ignored for LUKS1. """ vmlinux = 'vmlinuz-6.8.0-53-generic' initrd = 'initrd.img-6.8.0-53-generic' @@ -50,4 +52,4 @@ label l0r ''' % ((version, vmlinux, initrd) * 2) setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, script, part2_size=60 if use_fde else 1, - use_fde=use_fde) + use_fde=use_fde, luks_kdf=luks_kdf) diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 94d98b3b73b..e2b4d49a2e0 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -84,7 +84,8 @@ def test_ut_dm_init_bootstd(u_boot_config, u_boot_log): setup_localboot_image(u_boot_config, u_boot_log) setup_vbe_image(u_boot_config, u_boot_log) setup_ubuntu_image(u_boot_config, u_boot_log, 11, 'mmc', use_fde=1) - setup_ubuntu_image(u_boot_config, u_boot_log, 12, 'mmc', use_fde=2) + setup_ubuntu_image(u_boot_config, u_boot_log, 12, 'mmc', use_fde=2, + luks_kdf='argon2id') def test_ut(ubman, ut_subtest): """Execute a "ut" subtest. From patchwork Tue Nov 11 12:41:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 682 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=1762864965; bh=9qno9R2tCQ8dUo/P5qnqNKRNwZkgKonmrzBsjaefTWc=; 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=LN849sNK0725PvCZR1heT395nYM9DbQYFH6A5eoNND4b418yJPz/jzmPR6BKJ3+J/ XPY+ps8gHOyPOXaebXY1sEd3nhb2JNlPLdgP3aT4cKpwp8x0bmFjf8F6S0iV3C19bb LG3Cs94lpSI3CFcxQP2mW7hwjodawfS5hsm5wHbRuihR0UZmEomvr5ON4MQi5w8gcd f2ZScOsIPesJrI3dXCjSy0uxjmRQxlZYJvUna1qYQcrZ0FtAs9cTOjd1qyMfZ298Jd 3DciOY+xlCwGPZ0fHBgb0Bn0OByEQcD/4fVKt3LUg16tYRRcHtFLlD3KyNJIZJQqiK GzryvfE8bWZeA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5939D684C7 for ; Tue, 11 Nov 2025 05:42:45 -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 VqOI2S4o6Qsa for ; Tue, 11 Nov 2025 05:42:45 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864965; bh=9qno9R2tCQ8dUo/P5qnqNKRNwZkgKonmrzBsjaefTWc=; 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=LN849sNK0725PvCZR1heT395nYM9DbQYFH6A5eoNND4b418yJPz/jzmPR6BKJ3+J/ XPY+ps8gHOyPOXaebXY1sEd3nhb2JNlPLdgP3aT4cKpwp8x0bmFjf8F6S0iV3C19bb LG3Cs94lpSI3CFcxQP2mW7hwjodawfS5hsm5wHbRuihR0UZmEomvr5ON4MQi5w8gcd f2ZScOsIPesJrI3dXCjSy0uxjmRQxlZYJvUna1qYQcrZ0FtAs9cTOjd1qyMfZ298Jd 3DciOY+xlCwGPZ0fHBgb0Bn0OByEQcD/4fVKt3LUg16tYRRcHtFLlD3KyNJIZJQqiK GzryvfE8bWZeA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 3D3876846C for ; Tue, 11 Nov 2025 05:42:45 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864963; bh=ZeVnNYPJdzooYP9nOsoA8BPENMU9keon6+YkVAifSEM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jsUtLJG2qIT0LuOICercXFqOLrsXSgggGRgKe7K3Yh8IwWJpdiYI5yGl+SoDUDt65 +CE/uPmKlx5tProyQJrPzmQczq9ggU2k7qzCI9lplGponR8pvoCHBU4paSOVIwYms+ F6Dd71cbpgaE4gPr6BTC16zLYLHQlR3zRomXfI28uiWES/e2sSHj3LziaKSfVk3D0i Sx6pMMNoYhjxmPBehz6i9Fm2gH6XZgzbobOF9eIwyw2wIOn/9Kg8YkGWOrWquTiQgG LBuHBk5RiIMDI2t7RUvnBIgQjMz5Ly12T8yZpgrfjiC/YAWPPvF62QRev3KhYYqlQK +pk4tEtpjNdvg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 314116841A; Tue, 11 Nov 2025 05:42:43 -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 10026) with ESMTP id vuB751qtSIOU; Tue, 11 Nov 2025 05:42:43 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864956; bh=7VEwlzLB3S/vJbqM/paDucmY+sWC38ET4Skz6v4fSwo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=isOBfXKdaZ8QZAgbrb3zGlaGJ7rQPeEoyRcTSr3yXnNECqY7+jTcWreOsaTVZSz3q UrWA9EcqnSpUYPPrD0T6J4R5tOkCusYgdEmJjUbj+rEcTITD2szj02JyE9Q81HZfr8 LwQo/d9+bBZd+0Vqp3d39i5NghQHMvtEw0zJsKgNGq8IocanjzLkA3lTJGyI92RXxu KZAlNC6hFIhgxNAKPB2uM/KLKD5s9+M5GTtYDdqzPqS2h+abyPKnrSHjU48Itz8b/z oq3PZPiBA2fXDrOBzKZggOGARJ8tvmpb/AK+Mt2oNtJ5UqsljT6EoWEA3U0Q13vYVI ZKVA62soklvWg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 065B26846C; Tue, 11 Nov 2025 05:42:35 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:17 -0700 Message-ID: <20251111124131.1198930-12-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: V2NUBIBWQSOXEONK2U2WRI75MFFZJ3YB X-Message-ID-Hash: V2NUBIBWQSOXEONK2U2WRI75MFFZJ3YB 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 11/15] luks: Export the af_merge() 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: From: Simon Glass Provide this function through an internal header, so that luks2 will be able to use it. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/block/luks.c | 5 +++-- drivers/block/luks_internal.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 drivers/block/luks_internal.h diff --git a/drivers/block/luks.c b/drivers/block/luks.c index 4400f1cfd84..826fe062757 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -25,6 +25,7 @@ #include #include #include +#include "luks_internal.h" int luks_get_version(struct udevice *blk, struct disk_partition *pinfo) { @@ -206,8 +207,8 @@ static int af_hash(struct hash_algo *algo, size_t key_size, u8 *block_buf) * @hash_spec: Hash algorithm name (e.g., "sha256") * Return: 0 on success, -ve on error */ -static int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, - const char *hash_spec) +int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, + const char *hash_spec) { struct hash_algo *algo; u8 block_buf[128]; diff --git a/drivers/block/luks_internal.h b/drivers/block/luks_internal.h new file mode 100644 index 00000000000..32714787550 --- /dev/null +++ b/drivers/block/luks_internal.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * LUKS (Linux Unified Key Setup) internal interfaces + * + * Copyright (C) 2025 Canonical Ltd + */ + +#ifndef __LUKS_INTERNAL_H__ +#define __LUKS_INTERNAL_H__ + +#include + +/** + * af_merge() - Merge anti-forensic split key into original key + * + * This performs the LUKS AF-merge operation to recover the original key from + * its AF-split representation. The algorithm XORs all stripes together, + * applying diffusion between each stripe. Used by both LUKS1 and LUKS2. + * + * @src: AF-split key material (key_size * stripes bytes) + * @dst: Output buffer for merged key (key_size bytes) + * @key_size: Size of the original key + * @stripes: Number of anti-forensic stripes + * @hash_spec: Hash algorithm name (e.g., "sha256") + * Return: 0 on success, -ve on error + */ +int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, + const char *hash_spec); + +#endif /* __LUKS_INTERNAL_H__ */ From patchwork Tue Nov 11 12:41:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 683 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=1762864965; bh=hFuTbxk39Tnmxdmpo4h0vPuW+JaEUbR+FnQA7N56fqE=; 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=GIeV8gpQmdemZlXCwUxlLenCrW2s1kct0uu/XMLKWw+xcUTfpnixR4BOyMH/GC0/V DFiY7UNW4FSlbQSzkfcM+MPJHa5cPTMc29Iaqlyuuc4To/rFkWgX8tjVNFnfa8l0Eh O4RcBh+dxiuBPzWnyGc0fo72pyrVNyXfl1kt11cx5ixK21xJi22kjMtKAviQk2CiHP mkGnX3Q1CwtfT1KDSVGdbPF66l+zou82vRZDuAlX6s2HWWhn92ohwuRh8dzBk226Uy wReX1xvtyQa1At7o1iNUNsf+qRtYcOG/q1MrFBWibxy1lFUEuexRDBRTfU2mULr99Z RY/4kZqflCfUQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DFE0D68535 for ; Tue, 11 Nov 2025 05:42:45 -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 mFEZ2ldfr7zi for ; Tue, 11 Nov 2025 05:42:45 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864965; bh=hFuTbxk39Tnmxdmpo4h0vPuW+JaEUbR+FnQA7N56fqE=; 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=GIeV8gpQmdemZlXCwUxlLenCrW2s1kct0uu/XMLKWw+xcUTfpnixR4BOyMH/GC0/V DFiY7UNW4FSlbQSzkfcM+MPJHa5cPTMc29Iaqlyuuc4To/rFkWgX8tjVNFnfa8l0Eh O4RcBh+dxiuBPzWnyGc0fo72pyrVNyXfl1kt11cx5ixK21xJi22kjMtKAviQk2CiHP mkGnX3Q1CwtfT1KDSVGdbPF66l+zou82vRZDuAlX6s2HWWhn92ohwuRh8dzBk226Uy wReX1xvtyQa1At7o1iNUNsf+qRtYcOG/q1MrFBWibxy1lFUEuexRDBRTfU2mULr99Z RY/4kZqflCfUQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C330E68378 for ; Tue, 11 Nov 2025 05:42:45 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864963; bh=ZBW2uJJoiDflTrsehGPLiV5SkZIML+JmTuMhdy1MtBk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=V+5md/ESnN20noFTcUnThB1leCO4xQKpwinqduz63cUpvs5QAzhqNBgaTz2J5eCdn 1D3kSP3GxQxaxAo9fXMa9eCaz5boiZlsflw++ihHH6bSQTemB7TdC+6LltTWI3O/iW 9t8bDqNW7Zix+1QoikZ/MfHB8sGAFeJuUrAcD87w+dJLP4IoDgBkbCH99Ama8PdSIg 1Ld/cu5MPkj//Kj7IXzieFYBnndqn2xB+H+mOf10olQzzhRCAxpx9glXbp4iqVzXYb aCagRcIaidgUmuhWH3cN0aFU1ueGSj2GR2leopd0o4ksvPdHCqoEVDEbkpHlCoOby5 B7ZnljZtQKt8g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 493D96846C; Tue, 11 Nov 2025 05:42:43 -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 10026) with ESMTP id sbXCp1FW1TZW; Tue, 11 Nov 2025 05:42:43 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864960; bh=nfyRJ5qeZWKvQm0w+zfPuwQ2tzVevgKi9GceEc2mYX4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wlSNFtZMIQHSaPZFSpIVkzzewy9orB3S0ty3P4fgvhH3qVpMmzkZLD/HQd3C0RUql qgTWrMzwp6JE3N3taj8XZmv2MrBQty0IgYwWiKZG1b38k+bbKt4+NPr0CmICG15QNA We1OlqeNlrW5/encQ9OH+5+ZCTNgMTxizg2hshEZ9NKDvQDgSYCXX9AyU62hPDsfM2 3ArqTMdaszghvCNymYUocVuwsSi7JFKwqxabW9/iGPGB/QS86wQ9Vhg26KsVcntX3n ZkuGGzmkbovJXyJdtbllEfPH061LCPEBlsjbRMfdPU0Um8pq7LrYZ/Y//9YErwsBlP qQFoDJDwCpxBQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 9F79968378; Tue, 11 Nov 2025 05:42:40 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:18 -0700 Message-ID: <20251111124131.1198930-13-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: ISY3YA3I2SU44T2IQQTEBN4GOXJPOGHA X-Message-ID-Hash: ISY3YA3I2SU44T2IQQTEBN4GOXJPOGHA 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: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 12/15] luks: Tidy up the code style in the block driver 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 In preparation for luks v2, make a few code-style tweaks: - shorter vars in some cases - 80cols in a few places - drop an unwanted blank line - use 'pass' instead of 'passphrase' - unnecessary assignments to NULL Signed-off-by: Simon Glass --- drivers/block/luks.c | 112 +++++++++++++++++++++---------------------- include/luks.h | 4 +- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/drivers/block/luks.c b/drivers/block/luks.c index 826fe062757..05df5b12c53 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -33,7 +33,6 @@ int luks_get_version(struct udevice *blk, struct disk_partition *pinfo) ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, desc->blksz); int version; - /* Read first block of the partition */ if (blk_read(blk, pinfo->start, 1, buffer) != 1) { log_debug("Error: failed to read LUKS header\n"); @@ -114,19 +113,19 @@ int luks_show_info(struct udevice *blk, struct disk_partition *pinfo) if (IS_ENABLED(CONFIG_JSON)) { u64 json_size; char *json_start; - int blocks; + int count; /* Read the full header to get JSON area */ - blocks = (hdr_size + desc->blksz - 1) / desc->blksz; - ALLOC_CACHE_ALIGN_BUFFER(unsigned char, full_hdr, blocks * desc->blksz); + count = (hdr_size + desc->blksz - 1) / desc->blksz; + ALLOC_CACHE_ALIGN_BUFFER(u8, hdr, count * desc->blksz); - if (blk_read(blk, pinfo->start, blocks, full_hdr) != blocks) { - printf("Error: failed to read full LUKS2 header\n"); + if (blk_read(blk, pinfo->start, count, hdr) != count) { + printf("Error: can't read full LUKS2 header\n"); return -EIO; } /* JSON starts after the 4096-byte binary header */ - json_start = (char *)(full_hdr + 4096); + json_start = (char *)(hdr + 4096); json_size = hdr_size - 4096; printf("\nJSON metadata (%llx bytes):\n", json_size); @@ -196,9 +195,9 @@ static int af_hash(struct hash_algo *algo, size_t key_size, u8 *block_buf) /** * af_merge() - Merge anti-forensic split key into original key * - * This performs the LUKS AF-merge operation to recover the original key from its - * AF-split representation. The algorithm XORs all stripes together, applying - * diffusion between each stripe. + * This performs the LUKS AF-merge operation to recover the original key from + * its AF-split representation. The algorithm XORs all stripes together, + * applying diffusion between each stripe. * * @src: AF-split key material (key_size * stripes bytes) * @dst: Output buffer for merged key (key_size bytes) @@ -248,25 +247,6 @@ int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, return 0; } -/** - * try_keyslot() - Unlock a LUKS key slot with a passphrase - * - * @blk: Block device - * @pinfo: Partition information - * @hdr: LUKS header - * @slot_idx: Key slot index to try - * @passphrase: Passphrase to try - * @md_type: Hash algorithm type - * @key_size: Size of the key - * @derived_key: Buffer for derived key (key_size bytes) - * @km: Buffer for encrypted key material - * @km_blocks: Size of km buffer in blocks - * @split_key: Buffer for AF-split key - * @candidate_key: Buffer to receive decrypted master key - * - * Return: 0 on success (correct passphrase), -EPROTO on mbedtls error, -ve on - * other error - */ /** * essiv_decrypt() - Decrypt key material using ESSIV mode * @@ -282,8 +262,8 @@ int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, * @km_blocks: Number of blocks of key material * @blksz: Block size in bytes */ -static void essiv_decrypt(u8 *derived_key, uint key_size, u8 *expkey, - u8 *km, u8 *split_key, uint km_blocks, uint blksz) +static void essiv_decrypt(u8 *derived_key, uint key_size, u8 *expkey, u8 *km, + u8 *split_key, uint km_blocks, uint blksz) { u8 essiv_expkey[AES256_EXPAND_KEY_LENGTH]; u8 essiv_key_material[SHA256_SUM_LEN]; @@ -333,14 +313,33 @@ static void essiv_decrypt(u8 *derived_key, uint key_size, u8 *expkey, } } +/** + * try_keyslot() - Unlock a LUKS key slot with a passphrase + * + * @blk: Block device + * @pinfo: Partition information + * @hdr: LUKS header + * @slot_idx: Key slot index to try + * @pass: Passphrase to try + * @md_type: Hash algorithm type + * @key_size: Size of the key + * @derived_key: Buffer for derived key (key_size bytes) + * @km: Buffer for encrypted key material + * @km_blocks: Size of km buffer in blocks + * @split_key: Buffer for AF-split key + * @candidate_key: Buffer to receive decrypted master key + * + * Return: 0 on success (correct passphrase), -EPROTO on mbedtls error, -ve on + * other error + */ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, struct luks1_phdr *hdr, int slot_idx, - const char *passphrase, mbedtls_md_type_t md_type, + const char *pass, mbedtls_md_type_t md_type, uint key_size, u8 *derived_key, u8 *km, uint km_blocks, u8 *split_key, u8 *candidate_key) { struct luks1_keyslot *slot = &hdr->key_slot[slot_idx]; - uint iterations, km_offset, stripes, split_key_size; + uint iters, km_offset, stripes, split_key_size; struct blk_desc *desc = dev_get_uclass_plat(blk); u8 expkey[AES256_EXPAND_KEY_LENGTH]; u8 key_digest[LUKS_DIGESTSIZE]; @@ -353,21 +352,20 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, log_debug("trying key slot %d...\n", slot_idx); - iterations = be32_to_cpu(slot->iterations); + iters = be32_to_cpu(slot->iterations); km_offset = be32_to_cpu(slot->key_material_offset); stripes = be32_to_cpu(slot->stripes); split_key_size = key_size * stripes; /* Derive key from passphrase using PBKDF2 */ - log_debug("PBKDF2(pass '%s'[len %zu], ", passphrase, - strlen(passphrase)); + log_debug("PBKDF2(pass '%s'[len %zu], ", pass, strlen(pass)); log_debug_hex("salt[0-7]", (u8 *)slot->salt, 8); - log_debug("iter %u, keylen %u)\n", iterations, key_size); - ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, (const u8 *)passphrase, - strlen(passphrase), + log_debug("iter %u, keylen %u)\n", iters, key_size); + ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, (const u8 *)pass, + strlen(pass), (const u8 *)slot->salt, - LUKS_SALTSIZE, iterations, - key_size, derived_key); + LUKS_SALTSIZE, iters, key_size, + derived_key); if (ret) { log_debug("PBKDF2 failed: %d\n", ret); return -EPROTO; @@ -389,7 +387,6 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, log_debug_hex("input key (derived_key) full:", derived_key, key_size); aes_expand_key(derived_key, key_size * 8, expkey); - log_debug_hex("expanded key [0-15]:", expkey, 16); /* Decrypt with CBC mode: first check if ESSIV is used */ @@ -433,7 +430,7 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, log_debug_hex("mk_digest[0-7]", (u8 *)hdr->mk_digest, 8); /* Check if the digest matches */ - if (memcmp(key_digest, hdr->mk_digest, LUKS_DIGESTSIZE) == 0) { + if (!memcmp(key_digest, hdr->mk_digest, LUKS_DIGESTSIZE)) { log_debug("Uunlocked with key slot %d\n", slot_idx); return 0; } @@ -443,20 +440,18 @@ static int try_keyslot(struct udevice *blk, struct disk_partition *pinfo, } int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, - const char *passphrase, u8 *master_key, u32 *key_size) + const char *pass, u8 *master_key, u32 *key_size) { uint version, split_key_size, km_blocks, hdr_blocks; + 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; - u8 candidate_key[128]; - u8 *split_key = NULL; - u8 *derived_key = NULL; - u8 *km = NULL; - int i, ret = -EINVAL; + int i, ret; - if (!blk || !pinfo || !passphrase || !master_key || !key_size) + if (!blk || !pinfo || !pass || !master_key || !key_size) return -EINVAL; desc = dev_get_uclass_plat(blk); @@ -482,14 +477,15 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); if (version != LUKS_VERSION_1) { - log_debug("only LUKS1 decryption is currently supported\n"); + 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("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 */ @@ -518,7 +514,7 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, break; } } - if (stripes == 0) { + if (!stripes) { log_debug("no active key slots found\n"); return -ENOENT; } @@ -541,7 +537,7 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, /* Try each key slot */ for (i = 0; i < LUKS_NUMKEYS; i++) { - ret = try_keyslot(blk, pinfo, hdr, i, passphrase, md_type, + ret = try_keyslot(blk, pinfo, hdr, i, pass, md_type, *key_size, derived_key, km, km_blocks, split_key, candidate_key); @@ -586,12 +582,12 @@ out: * @master_key: Unlocked master key * @key_size: Size of the master key in bytes * @label: Label for the blkmap device - * @blkmap_dev: Output pointer for created blkmap device + * @blkmapp: Output pointer for created blkmap device * Return: 0 on success, -ve on error */ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, const u8 *master_key, u32 key_size, const char *label, - struct udevice **blkmap_dev) + struct udevice **blkmapp) { u8 essiv_key[SHA256_SUM_LEN]; /* SHA-256 output */ struct luks1_phdr *hdr; @@ -601,7 +597,7 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, bool use_essiv; int ret; - if (!blk || !pinfo || !master_key || !label || !blkmap_dev) + if (!blk || !pinfo || !master_key || !label || !blkmapp) return -EINVAL; desc = dev_get_uclass_plat(blk); @@ -651,7 +647,7 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, /* Wipe ESSIV key from stack */ if (use_essiv) memset(essiv_key, '\0', sizeof(essiv_key)); - *blkmap_dev = dev; + *blkmapp = dev; return 0; } diff --git a/include/luks.h b/include/luks.h index f8fda27e132..2c52cc48689 100644 --- a/include/luks.h +++ b/include/luks.h @@ -145,13 +145,13 @@ int luks_show_info(struct udevice *blk, struct disk_partition *pinfo); * * @blk: Block device * @pinfo: Partition information - * @passphrase: Passphrase to unlock the partition + * @pass: Passphrase to unlock the partition * @master_key: Buffer to receive the decrypted master key * @key_size: Size of the master_key buffer * Return: 0 on success, -ve on error */ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, - const char *passphrase, u8 *master_key, u32 *key_size); + const char *pass, u8 *master_key, u32 *key_size); /** * luks_create_blkmap() - Create a blkmap device for a LUKS partition From patchwork Tue Nov 11 12:41: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: 684 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=1762864968; bh=Mg+EC8VbaRy4uzZyn67ydrwv+QBeNrnFa+RrbGDEyRo=; 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=B7kfYCb3QrBq/vJJgCk+77vTi6hbiT2cVP8jN9mY5fQtwwuZJQPeFZW2VBqDIzKyl SSJEauppP3Kg5lf4mhC2MvVLtyYCS0Bj8oOlomTpcn6NgjtGesnenGiJF5PPsS0qny myoc6/XKKSMMRsuCyh/19k6ZzUG04XtBX49s0007zm+fEIQ5s5oPgsPWhwQtUX3G0Q 72dKGpFm6IhyKqrsAEAmbcdtr0n/dQjz8CSJIrnwrYJSf6npOmSLaCrxq5vvjZ64rc VoSNxColCfQULgEjRYZV33qMbZIqdLraMhxcjrRUF0QCCqTJwwPcbSsnf1Dnomn2lT Up2HLGgaul/Qg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E406C68378 for ; Tue, 11 Nov 2025 05:42:48 -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 UmXlPGUVQ4zJ for ; Tue, 11 Nov 2025 05:42:48 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864966; bh=Mg+EC8VbaRy4uzZyn67ydrwv+QBeNrnFa+RrbGDEyRo=; 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=Qd5Cs+yQw09bpThy6p1Zbj7cKtENRTYChtl5olgyuNPbkl5VSnrIDXI0ggOU1Ss5s ZzizQ1Ow8YqJX1RkGGCK5h6ccvhmhVVXb5/vFaSNOIRdGKGnlVPCxnpT6RpGgCwYLD MJiQfZSjZ8rxBDuUWtjp8RcBTV4MUMJ5f4hmCDqqHMkjXjw2FpWzk6IgfEj/QES2EN n8luKoiSlM5ok6IbzzMlMZ2hA8XUq5LqH6PyE6h3/smCAvi4fEyoJzny/yRycn5mdJ alJlfoF7ppIJer3a5Q7nUPMyT6P3vGBsutNY1f0SsYKNlvUV8+TcjBKwd47IGnbeur ZtHYSI1W1cokQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E3B176841A for ; Tue, 11 Nov 2025 05:42:46 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864963; bh=C48COo3vH7EQzVWk6UwgoRKK/rH0otytf+j9ePyD/4U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JRNGPoKjvTnjJZMomzMfCHxwjBeI9dkJdMIAnxfTqeVILZncP8YAHR8CkQFTHl2O9 sZz19Io3NoJvpy10gyd9Hr8OuKCVUwNFGRfRpAY8rSiSyNlb5+5qE5ZeYLV0Q58E/7 gRghw5cTQsVdLREbDFXj4bq12G7piyzQnDtH4mSQao+cC0VDEDL9JEkYEw8CHgemYb VKq4bPRVcWLLkbOFP718cACsg7RiDJJEhXL23KF4LTcAzY8zjbEUYDJiDITUEyhgXo 4TODGP+s+0nPFGtTjQkp3NdYzLJ0tmyV9US6U9zCSbWHjsPHHmnHKvFrlXsjtZWQ53 GQpp95ruv2ubg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6C17368378; Tue, 11 Nov 2025 05:42:43 -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 10026) with ESMTP id y77ic2ca2Pbl; Tue, 11 Nov 2025 05:42:43 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864962; bh=g9KLNCmGWku45hHMhj/boep+jSewTnn8CAl1CT4kVuY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Us2O7jObaoiC76XYwHqRwR9ZepK16x4TdjOmTM/6gUEviQTIGrhMhDghABMhVvOCf 1JPYwlNyFlQW/B77c6c4IFZrUDjvD4Rxrd1y6wpUxIwE+/ICXTRXN23PbgWgYpL0rY a3wHhX/8Tx9bozOO7F6BuO0mz29QmMvF6rjSrEs8glEA71Sn5D10W2tRXaW+rwKFBc KBASX9peo5+UNNuTdZzJ43zC6P+YuCOFGh3skiXZTc59uuZh3l3VhBRXTJfYsri8/D Zp4IziMuQJWEc/LxULD36MQVWeYVfYNVtvAGKfy8GX/9YJvj6mlSeuY0HwJ1h74dHD Nx/inUZHiUvOA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id BA22168472; Tue, 11 Nov 2025 05:42:41 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:19 -0700 Message-ID: <20251111124131.1198930-14-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: RZB3G7TSOLOHAMTOSYSJR7C5LSRSHVBG X-Message-ID-Hash: RZB3G7TSOLOHAMTOSYSJR7C5LSRSHVBG 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: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 13/15] luks: Provide an implementation of luks2 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 Add supports for luks v2 which is a more common version used on modern systems. This makes use of Argon2 and also the JSON->FDT parser. Enable this feature for sandbox, tidying up the defconfig while we are here. Co-developed-by: Claude Signed-off-by: Simon Glass --- configs/sandbox_defconfig | 4 +- drivers/block/Makefile | 2 +- drivers/block/luks.c | 116 +++- drivers/block/luks2.c | 974 ++++++++++++++++++++++++++++++++++ drivers/block/luks_internal.h | 13 + 5 files changed, 1100 insertions(+), 9 deletions(-) create mode 100644 drivers/block/luks2.c diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6a4b3e4363a..006c6916af6 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -169,7 +169,6 @@ CONFIG_ADC=y CONFIG_ADC_SANDBOX=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y -CONFIG_BLKMAP=y CONFIG_SYS_IDE_MAXBUS=1 CONFIG_SYS_ATA_BASE_ADDR=0x100 CONFIG_SYS_ATA_STRIDE=4 @@ -177,6 +176,7 @@ CONFIG_SYS_ATA_DATA_OFFSET=0 CONFIG_SYS_ATA_REG_OFFSET=1 CONFIG_SYS_ATA_ALT_OFFSET=2 CONFIG_SYS_ATA_IDE0_OFFSET=0 +CONFIG_BLK_LUKS=y CONFIG_BOOTCOUNT_LIMIT=y CONFIG_DM_BOOTCOUNT=y CONFIG_DM_BOOTCOUNT_RTC=y @@ -362,12 +362,12 @@ 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 CONFIG_ERRNO_STR=y CONFIG_GETOPT=y +CONFIG_ARGON2=y CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y diff --git a/drivers/block/Makefile b/drivers/block/Makefile index b428a5cfb78..538b602790d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,7 +11,7 @@ endif ifndef CONFIG_XPL_BUILD obj-$(CONFIG_IDE) += ide.o -obj-$(CONFIG_BLK_LUKS) += luks.o +obj-$(CONFIG_BLK_LUKS) += luks.o luks2.o obj-$(CONFIG_RKMTD) += rkmtd.o endif obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o diff --git a/drivers/block/luks.c b/drivers/block/luks.c index 05df5b12c53..3bdfd7dba61 100644 --- a/drivers/block/luks.c +++ b/drivers/block/luks.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -476,6 +479,9 @@ int luks_unlock(struct udevice *blk, struct disk_partition *pinfo, } version = be16_to_cpu(*(__be16 *)(buffer + LUKS_MAGIC_LEN)); + if (version == LUKS_VERSION_2) + return unlock_luks2(blk, pinfo, pass, master_key, key_size); + if (version != LUKS_VERSION_1) { log_debug("unsupported LUKS version %d\n", version); return -ENOTSUPP; @@ -591,11 +597,12 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, { u8 essiv_key[SHA256_SUM_LEN]; /* SHA-256 output */ struct luks1_phdr *hdr; + struct luks2_hdr *hdr2; struct blk_desc *desc; struct udevice *dev; uint payload_offset; + int ret, version; bool use_essiv; - int ret; if (!blk || !pinfo || !master_key || !label || !blkmapp) return -EINVAL; @@ -608,7 +615,107 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, log_debug("failed to read LUKS header\n"); return -EIO; } - hdr = (struct luks1_phdr *)buf; + + /* Check version */ + version = be16_to_cpu(*(__be16 *)(buf + LUKS_MAGIC_LEN)); + + if (version == LUKS_VERSION_2) { + /* LUKS2: Parse JSON for segment offset */ + char *json_data; + u64 hdr_size, segment_offset; + int blocks; + struct abuf fdt_buf; + oftree tree; + ofnode root, segments_node, segment0_node; + const char *offset_str, *encryption; + + abuf_init(&fdt_buf); + + hdr2 = (struct luks2_hdr *)buf; + hdr_size = be64_to_cpu(hdr2->hdr_size); + + /* Read full header with JSON */ + blocks = (hdr_size + desc->blksz - 1) / desc->blksz; + json_data = malloc_cache_aligned(blocks * desc->blksz); + if (!json_data) + return -ENOMEM; + + if (blk_read(blk, pinfo->start, blocks, json_data) != blocks) { + free(json_data); + return -EIO; + } + + /* Convert JSON to FDT */ + ret = json_to_fdt(json_data + 4096, &fdt_buf); + if (ret) { + log_err("Failed to convert JSON to FDT: %d\n", ret); + free(json_data); + return -EINVAL; + } + + /* Create oftree from FDT */ + tree = oftree_from_fdt(abuf_data(&fdt_buf)); + if (!oftree_valid(tree)) { + abuf_uninit(&fdt_buf); + free(json_data); + return -EINVAL; + } + + /* Get root node */ + root = oftree_root(tree); + if (!ofnode_valid(root)) { + abuf_uninit(&fdt_buf); + free(json_data); + return -EINVAL; + } + + /* Navigate to segments node */ + segments_node = ofnode_find_subnode(root, "segments"); + if (!ofnode_valid(segments_node)) { + abuf_uninit(&fdt_buf); + free(json_data); + return -EINVAL; + } + + /* Get first segment (segment 0) */ + segment0_node = ofnode_find_subnode(segments_node, "0"); + if (!ofnode_valid(segment0_node)) { + abuf_uninit(&fdt_buf); + free(json_data); + return -EINVAL; + } + + /* Get offset (string in LUKS2 JSON) */ + offset_str = ofnode_read_string(segment0_node, "offset"); + if (!offset_str) { + abuf_uninit(&fdt_buf); + free(json_data); + return -EINVAL; + } + segment_offset = simple_strtoull(offset_str, NULL, 10); + + /* Convert byte offset to sectors */ + payload_offset = segment_offset / desc->blksz; + + /* Check if ESSIV mode is used */ + encryption = ofnode_read_string(segment0_node, "encryption"); + if (encryption) + use_essiv = strstr(encryption, "essiv"); + else + use_essiv = false; + + abuf_uninit(&fdt_buf); + free(json_data); + } else { + /* LUKS1 */ + hdr = (struct luks1_phdr *)buf; + + /* Check if ESSIV mode is used */ + use_essiv = strstr(hdr->cipher_mode, "essiv"); + + /* Get payload offset */ + payload_offset = be32_to_cpu(hdr->payload_offset); + } /* Create blkmap device */ ret = blkmap_create(label, &dev); @@ -617,9 +724,7 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, return ret; } - /* Check if ESSIV mode is used */ - use_essiv = strstr(hdr->cipher_mode, "essiv"); - + /* Compute ESSIV key if needed */ if (use_essiv) { int hash_size = SHA256_SUM_LEN; @@ -632,7 +737,6 @@ int luks_create_blkmap(struct udevice *blk, struct disk_partition *pinfo, } /* Map the encrypted partition to the blkmap device */ - payload_offset = be32_to_cpu(hdr->payload_offset); log_debug("mapping blkmap: blknr 0 blkcnt %lx payload_offset %x essiv %d\n", (ulong)pinfo->size, payload_offset, use_essiv); ret = blkmap_map_crypt(dev, 0, pinfo->size, blk, pinfo->start, diff --git a/drivers/block/luks2.c b/drivers/block/luks2.c new file mode 100644 index 00000000000..4720f9d92ce --- /dev/null +++ b/drivers/block/luks2.c @@ -0,0 +1,974 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LUKS2 (Linux Unified Key Setup version 2) support + * + * Copyright (C) 2025 Canonical Ltd + */ + +/* #define LOG_DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "luks_internal.h" + +/** + * enum luks2_kdf_type - LUKS2 KDF type + * + * @LUKS2_KDF_PBKDF2: PBKDF2 key derivation function + * @LUKS2_KDF_ARGON2I: Argon2i key derivation function + * @LUKS2_KDF_ARGON2ID: Argon2id key derivation function + */ +enum luks2_kdf_type { + LUKS2_KDF_PBKDF2, + LUKS2_KDF_ARGON2I, + LUKS2_KDF_ARGON2ID, +}; + +/** + * struct luks2_digest - LUKS2 digest information + * + * @type: Digest KDF type + * @hash: Hash algorithm name (e.g., "sha256") + * @iters: PBKDF2 iteration count (valid if type == LUKS2_KDF_PBKDF2) + * @time: Argon2 time cost parameter (valid if type == LUKS2_KDF_ARGON2*) + * @memory: Argon2 memory cost parameter in KB (type == LUKS2_KDF_ARGON2*) + * @cpus: Argon2 parallelism/lanes parameter (type == LUKS2_KDF_ARGON2*) + * @salt: Decoded salt value + * @salt_len: Actual length of decoded salt + * @digest: Decoded digest (master key verification value) + * @digest_len: Actual length of decoded digest + */ +struct luks2_digest { + enum luks2_kdf_type type; + const char *hash; + u32 iters; + u32 time; + u32 memory; + u32 cpus; + u8 salt[LUKS_SALTSIZE]; + int salt_len; + u8 digest[128]; + int digest_len; +}; + +/** + * struct luks2_kdf - LUKS2 keyslot KDF parameters + * @type: KDF type + * @salt: Decoded KDF salt + * @salt_len: Actual length of decoded salt + * @iters: PBKDF2 iteration count (valid if type == LUKS2_KDF_PBKDF2) + * @time: Argon2 time cost parameter (valid if type == LUKS2_KDF_ARGON2*) + * @memory: Argon2 memory cost parameter in KB (type == LUKS2_KDF_ARGON2*) + * @cpus: Argon2 parallelism/lanes parameter (type == LUKS2_KDF_ARGON2*) + */ +struct luks2_kdf { + enum luks2_kdf_type type; + u8 salt[LUKS_SALTSIZE]; + int salt_len; + u32 iters; + u32 time; + u32 memory; + u32 cpus; +}; + +/** + * struct luks2_area - LUKS2 keyslot encrypted area parameters + * @offset: Byte offset from partition start where key material is stored + * @size: Size of encrypted key material in bytes + * @encryption: Encryption mode string (e.g., "aes-xts-plain64") + * @key_size: Encryption key size in bytes (32 for AES-256, 64 for XTS-512) + */ +struct luks2_area { + u64 offset; + u64 size; + const char *encryption; + u32 key_size; +}; + +/** + * struct luks2_af - LUKS2 keyslot anti-forensic parameters + * @stripes: Number of anti-forensic stripes (typically 4000) + * @hash: Hash algorithm name for AF merge operation + */ +struct luks2_af { + u32 stripes; + const char *hash; +}; + +/** + * struct luks2_keyslot - LUKS2 keyslot information + * @type: Keyslot type (should be "luks2") + * @key_size: Size of the master key in bytes + * @kdf: Key derivation function parameters + * @af: Anti-forensic parameters + * @area: Encrypted key material area parameters + */ +struct luks2_keyslot { + const char *type; + u32 key_size; + struct luks2_kdf kdf; + struct luks2_af af; + struct luks2_area area; +}; + +/** + * str_to_kdf_type() - Convert KDF type string to enum + * + * @type_str: KDF type string ("pbkdf2", "argon2i", or "argon2id") + * Return: enum luks2_kdf_type value, or negative error code if unknown type + */ +static int str_to_kdf_type(const char *type_str) +{ + if (!type_str) + return -EINVAL; + + if (!strcmp(type_str, "pbkdf2")) + return LUKS2_KDF_PBKDF2; + if (!strcmp(type_str, "argon2i")) + return LUKS2_KDF_ARGON2I; + if (!strcmp(type_str, "argon2id")) + return LUKS2_KDF_ARGON2ID; + + return -ENOTSUPP; +} + +/* Base64 decode wrapper for LUKS2 */ +static int base64_decode(const char *in, u8 *out, int out_len) +{ + size_t olen; + int ret; + + ret = mbedtls_base64_decode(out, out_len, &olen, + (const unsigned char *)in, strlen(in)); + if (ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + return -ENOSPC; + if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) + return -EINVAL; + if (ret) + return -EINVAL; + + return olen; +} + +/** + * read_digest_info() - Read LUKS2 digest information from ofnode + * + * @digest_node: ofnode for the digest (e.g., digest "0") + * @digest: Pointer to digest structure to fill + * Return: 0 on success, -ve on error + */ +static int read_digest_info(ofnode digest_node, struct luks2_digest *digest) +{ + const char *salt_b64, *digest_b64; + + const char *type_str; + int ret; + + memset(digest, '\0', sizeof(*digest)); + + /* Read and convert digest type */ + type_str = ofnode_read_string(digest_node, "type"); + ret = str_to_kdf_type(type_str); + if (ret < 0) { + log_debug("LUKS2: unsupported digest type %s\n", type_str); + return ret; + } + digest->type = ret; + + /* Check if Argon2 is supported if needed */ + if ((digest->type == LUKS2_KDF_ARGON2I || + digest->type == LUKS2_KDF_ARGON2ID) && + !IS_ENABLED(CONFIG_ARGON2)) { + log_debug("LUKS2: Argon2 not supported\n"); + return -ENOTSUPP; + } + + /* Read hash algorithm */ + digest->hash = ofnode_read_string(digest_node, "hash"); + if (!digest->hash) + return -EINVAL; + + /* Read KDF-specific parameters */ + if (digest->type == LUKS2_KDF_PBKDF2) { + /* PBKDF2 */ + if (ofnode_read_u32(digest_node, "iterations", &digest->iters)) + return -EINVAL; + } else { + /* Argon2 */ + if (ofnode_read_u32(digest_node, "time", &digest->time) || + ofnode_read_u32(digest_node, "memory", &digest->memory) || + ofnode_read_u32(digest_node, "cpus", &digest->cpus)) + return -EINVAL; + } + + /* Read and decode salt */ + salt_b64 = ofnode_read_string(digest_node, "salt"); + if (!salt_b64) + return -EINVAL; + digest->salt_len = base64_decode(salt_b64, digest->salt, + sizeof(digest->salt)); + if (digest->salt_len <= 0) + return -EINVAL; + + /* Read and decode digest */ + digest_b64 = ofnode_read_string(digest_node, "digest"); + if (!digest_b64) + return -EINVAL; + digest->digest_len = base64_decode(digest_b64, digest->digest, + sizeof(digest->digest)); + if (digest->digest_len <= 0) + return -EINVAL; + + return 0; +} + +/** + * read_keyslot_info() - Read LUKS2 keyslot information from ofnode + * + * @keyslot_node: ofnode for the keyslot (e.g., keyslot "0") + * @keyslot: Pointer to keyslot structure to fill + * @hash_name: Hash name to use for AF (from digest) + * Return: 0 on success, -ve on error + */ +static int read_keyslot_info(ofnode keyslot_node, struct luks2_keyslot *keyslot, + const char *hash_name) +{ + const char *salt_b64, *offset_str, *size_str; + ofnode kdf_node, af_node, area_node; + int ret; + + memset(keyslot, '\0', sizeof(*keyslot)); + + /* Read keyslot type */ + keyslot->type = ofnode_read_string(keyslot_node, "type"); + if (!keyslot->type || strcmp(keyslot->type, "luks2")) + return -EINVAL; + + /* Read key size */ + if (ofnode_read_u32(keyslot_node, "key_size", &keyslot->key_size)) + return -EINVAL; + + /* Navigate to and read KDF node */ + kdf_node = ofnode_find_subnode(keyslot_node, "kdf"); + if (!ofnode_valid(kdf_node)) + return -EINVAL; + + offset_str = ofnode_read_string(kdf_node, "type"); + ret = str_to_kdf_type(offset_str); + if (ret < 0) { + log_debug("LUKS2: unsupported KDF type %s\n", offset_str); + return ret; + } + keyslot->kdf.type = ret; + + /* Check if Argon2 is supported if needed */ + if ((keyslot->kdf.type == LUKS2_KDF_ARGON2I || + keyslot->kdf.type == LUKS2_KDF_ARGON2ID) && + !IS_ENABLED(CONFIG_ARGON2)) { + log_debug("LUKS2: Argon2 not supported\n"); + return -ENOTSUPP; + } + + /* Read KDF salt */ + salt_b64 = ofnode_read_string(kdf_node, "salt"); + if (!salt_b64) + return -EINVAL; + keyslot->kdf.salt_len = base64_decode(salt_b64, keyslot->kdf.salt, + sizeof(keyslot->kdf.salt)); + if (keyslot->kdf.salt_len <= 0) + return -EINVAL; + + /* Read KDF-specific parameters */ + if (keyslot->kdf.type == LUKS2_KDF_PBKDF2) { + if (ofnode_read_u32(kdf_node, "iterations", &keyslot->kdf.iters)) + return -EINVAL; + } else { + /* Argon2 */ + if (ofnode_read_u32(kdf_node, "time", &keyslot->kdf.time) || + ofnode_read_u32(kdf_node, "memory", &keyslot->kdf.memory) || + ofnode_read_u32(kdf_node, "cpus", &keyslot->kdf.cpus)) + return -EINVAL; + } + + /* Navigate to and read AF node */ + af_node = ofnode_find_subnode(keyslot_node, "af"); + if (!ofnode_valid(af_node)) + return -EINVAL; + + if (ofnode_read_u32(af_node, "stripes", &keyslot->af.stripes)) + keyslot->af.stripes = 4000; /* Default */ + keyslot->af.hash = hash_name; + + /* Navigate to and read area node */ + area_node = ofnode_find_subnode(keyslot_node, "area"); + if (!ofnode_valid(area_node)) + return -EINVAL; + + /* Read offset and size (strings in LUKS2 JSON) */ + offset_str = ofnode_read_string(area_node, "offset"); + if (!offset_str) + return -EINVAL; + keyslot->area.offset = simple_strtoull(offset_str, NULL, 10); + + size_str = ofnode_read_string(area_node, "size"); + if (!size_str) + return -EINVAL; + keyslot->area.size = simple_strtoull(size_str, NULL, 10); + + /* Read encryption mode */ + keyslot->area.encryption = ofnode_read_string(area_node, "encryption"); + if (!keyslot->area.encryption) + return -EINVAL; + + /* Read area key size */ + if (ofnode_read_u32(area_node, "key_size", &keyslot->area.key_size)) + return -EINVAL; + + return 0; +} + +/** + * read_luks2_info() - Read and parse LUKS2 header and metadata + * + * @blk: Block device + * @pinfo: Partition information + * @fdt_buf: Buffer to hold the converted FDT (caller must uninit) + * @digest: Pointer to digest structure to fill + * @md_type: Pointer to receive mbedtls MD type + * @keyslots_node: Pointer to receive keyslots ofnode + * Return: 0 on success, -ve on error + */ +static int read_luks2_info(struct udevice *blk, struct disk_partition *pinfo, + struct abuf *fdt_buf, struct luks2_digest *digest, + mbedtls_md_type_t *md_typep, ofnode *keyslots_nodep) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + ALLOC_CACHE_ALIGN_BUFFER(u8, buffer, desc->blksz); + ofnode root, digests_node, digest0; + struct hash_algo *hash_algo; + mbedtls_md_type_t md_type; + struct luks2_hdr *hdr; + ofnode keyslots_node; + char *json_data; + int count, ret; + u64 hdr_size; + oftree tree; + + abuf_init(fdt_buf); + + /* Read LUKS2 header */ + if (blk_read(blk, pinfo->start, 1, buffer) != 1) + return -EIO; + + hdr = (struct luks2_hdr *)buffer; + hdr_size = be64_to_cpu(hdr->hdr_size); + + log_debug("LUKS2: header size %llu bytes\n", hdr_size); + + /* Allocate and read full header with JSON */ + count = (hdr_size + desc->blksz - 1) / desc->blksz; + json_data = malloc_cache_aligned(count * desc->blksz); + if (!json_data) + return -ENOMEM; + + if (blk_read(blk, pinfo->start, count, json_data) != count) { + ret = -EIO; + goto out; + } + + ret = -EINVAL; + + /* JSON starts after a 4K binary header: convert to FDT */ + if (json_to_fdt(json_data + 4096, fdt_buf)) { + log_err("Failed to convert JSON to FDT\n"); + goto out; + } + + /* Create oftree from FDT */ + tree = oftree_from_fdt(abuf_data(fdt_buf)); + if (!oftree_valid(tree)) + goto out; + + /* Get root node */ + root = oftree_root(tree); + if (!ofnode_valid(root)) + goto out; + + /* Navigate to digests node and get digest 0 */ + digests_node = ofnode_find_subnode(root, "digests"); + if (!ofnode_valid(digests_node)) + goto out; + + digest0 = ofnode_find_subnode(digests_node, "0"); + if (!ofnode_valid(digest0)) + goto out; + + /* Read digest information */ + ret = read_digest_info(digest0, digest); + if (ret) + goto out; + + /* Get hash algorithm */ + ret = hash_lookup_algo(digest->hash, &hash_algo); + if (ret) { + log_debug("Unsupported hash: %s\n", digest->hash); + ret = -ENOTSUPP; + goto out; + } + md_type = hash_mbedtls_type(hash_algo); + + /* Navigate to keyslots node */ + keyslots_node = ofnode_find_subnode(root, "keyslots"); + if (!ofnode_valid(keyslots_node)) { + ret = -EINVAL; + goto out; + } + + *md_typep = md_type; + *keyslots_nodep = keyslots_node; + +out: + memset(json_data, '\0', count * desc->blksz); + free(json_data); + if (ret) + abuf_uninit(fdt_buf); + + return ret; +} + +/** + * essiv_decrypt() - Decrypt key material using ESSIV mode + * + * ESSIV (Encrypted Salt-Sector Initialization Vector) mode generates a unique + * IV for each sector by encrypting the sector number with a key derived from + * hashing the encryption key. + * + * @derived_key: Key derived from passphrase + * @key_size: Size of the encryption key in bytes + * @expkey: Expanded AES key for decryption + * @km: Encrypted key material buffer + * @split_key: Output buffer for decrypted key material + * @km_blocks: Number of blocks of key material + * @blksz: Block size in bytes + */ +static void essiv_decrypt(u8 *derived_key, uint key_size, u8 *expkey, + u8 *km, u8 *split_key, uint km_blocks, uint blksz) +{ + u8 essiv_expkey[AES256_EXPAND_KEY_LENGTH]; + u8 essiv_key_material[SHA256_SUM_LEN]; + u32 num_sectors = km_blocks; + u8 iv[AES_BLOCK_LENGTH]; + uint rel_sect; + + /* Generate ESSIV key by hashing the encryption key */ + log_debug("using ESSIV mode\n"); + sha256_csum_wd(derived_key, key_size, essiv_key_material, + CHUNKSZ_SHA256); + + log_debug_hex("ESSIV key[0-7]:", essiv_key_material, 8); + + /* Expand ESSIV key for AES */ + aes_expand_key(essiv_key_material, 256, essiv_expkey); + + /* + * Decrypt each sector with its own IV + * NOTE: sector number is relative to the key material buffer, + * not an absolute disk sector + */ + for (rel_sect = 0; rel_sect < num_sectors; rel_sect++) { + u8 sector_iv[AES_BLOCK_LENGTH]; + + /* Create IV: little-endian sector number padded to 16 bytes */ + memset(sector_iv, '\0', AES_BLOCK_LENGTH); + put_unaligned_le32(rel_sect, sector_iv); + + /* Encrypt sector number with ESSIV key to get IV */ + aes_encrypt(256, sector_iv, essiv_expkey, iv); + + /* Show the first sector for debugging */ + if (!rel_sect) { + log_debug("rel_sect %x, ", rel_sect); + log_debug_hex("IV[0-7]:", iv, 8); + } + + /* Decrypt this sector */ + aes_cbc_decrypt_blocks(key_size * 8, expkey, iv, + km + (rel_sect * blksz), + split_key + (rel_sect * blksz), + blksz / AES_BLOCK_LENGTH); + } +} + +/** + * decrypt_km_xts() - Decrypt key material using XTS mode + * + * Decrypts LUKS2 keyslot key material encrypted with AES-XTS mode. + * XTS mode uses 512-byte sectors with sector numbers as tweaks. + * + * @derived_key: Key derived from passphrase using KDF + * @key_size: Size of the derived key in bytes (32 or 64 for XTS) + * @km: Encrypted key material buffer + * @split_key: Output buffer for decrypted split key + * @size: Size of the split key in bytes + * Return: 0 on success, negative error code on failure + */ +static int decrypt_km_xts(const u8 *derived_key, uint key_size, const u8 *km, + u8 *split_key, int size) +{ + mbedtls_aes_xts_context ctx; + const int blksize = 512; + u8 data_unit[16]; + u64 sector; + int ret; + + /* Verify key size is valid for XTS (32 or 64 bytes) */ + if (key_size != 32 && key_size != 64) { + log_err("Unsupported XTS key size: %u\n", key_size); + return -EINVAL; + } + + mbedtls_aes_xts_init(&ctx); + ret = mbedtls_aes_xts_setkey_dec(&ctx, derived_key, key_size * 8); + if (ret) { + log_err("Failed to set XTS key: %d\n", ret); + mbedtls_aes_xts_free(&ctx); + return -EINVAL; + } + + /* + * XTS uses data unit (sector) as tweak + * LUKS2 uses 512-byte sectors for keyslot area + * Sector number is relative to start of keyslot area (not absolute) + */ + sector = 0; + + /* + * Decrypt in chunks (XTS requires whole sectors) + * Each sector has its own data_unit/tweak value + */ + for (u64 pos = 0; pos < size; pos += blksize) { + uint todo; + + todo = (size - pos > blksize) ? blksize : (size - pos); + + /* Prepare data_unit (sector number in little-endian) */ + memset(data_unit, '\0', sizeof(data_unit)); + for (int i = 0; i < 8; i++) + data_unit[i] = (sector >> (i * 8)) & 0xFF; + + ret = mbedtls_aes_crypt_xts(&ctx, MBEDTLS_AES_DECRYPT, todo, + data_unit, km + pos, + split_key + pos); + if (ret) { + log_err("XTS decryption failed at sector %llu: %d\n", + sector, ret); + mbedtls_aes_xts_free(&ctx); + return -EINVAL; + } + sector++; + } + + mbedtls_aes_xts_free(&ctx); + + return 0; +} + +/** + * decrypt_km_cbc() - Decrypt key material using CBC mode + * + * Decrypts LUKS keyslot key material encrypted with AES-CBC mode. + * Supports both ESSIV mode and plain CBC with zero IV. + * + * @derived_key: Key derived from passphrase using KDF + * @key_size: Size of the derived key in bytes + * @encrypt: Encryption-specification string (may contain "essiv") + * @km: Encrypted key material buffer + * @split_key: Output buffer for decrypted split key + * @size: Size of the split key in bytes + * @km_blocks: Number of blocks in key material + * @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) +{ + u8 expkey[AES256_EXPAND_KEY_LENGTH]; + + aes_expand_key(derived_key, key_size * 8, expkey); + + /* Check if ESSIV mode is used */ + if (strstr(encrypt, "essiv")) { + essiv_decrypt(derived_key, key_size, expkey, km, split_key, + km_blocks, blksz); + } else { + /* Plain CBC with zero IV */ + u8 iv[AES_BLOCK_LENGTH]; + + memset(iv, '\0', sizeof(iv)); + aes_cbc_decrypt_blocks(key_size * 8, expkey, iv, km, split_key, + size / AES_BLOCK_LENGTH); + } + + return 0; +} + +/* LUKS2-specific: Unlock using PBKDF2 keyslot */ +/** + * try_keyslot_pbkdf2() - Try to decrypt a LUKS2 keyslot using PBKDF2 + * + * Attempts to decrypt a LUKS2 keyslot using the PBKDF2 key derivation function. + * This involves deriving a key from the passphrase, reading the encrypted key + * material from disk, decrypting it (using either XTS or CBC mode), and + * recovering the candidate key through anti-forensic splitting. + * + * @blk: Block device containing the LUKS2 volume + * @pinfo: Partition information for the LUKS2 volume + * @ks: Keyslot information including KDF parameters and encryption area + * @pass: User passphrase to try + * @md_type: mbedtls message digest type for PBKDF2 + * @cand_key: Output buffer for the recovered candidate key + * Return: 0 on success, negative error code on failure + */ +static int try_keyslot_pbkdf2(struct udevice *blk, struct disk_partition *pinfo, + const struct luks2_keyslot *ks, const char *pass, + mbedtls_md_type_t md_type, u8 *cand_key) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + int ret, km_blocks, size; + u8 derived_key[128]; + u8 *split_key, *km; + + log_debug("LUKS2: trying keyslot with %u iters\n", ks->kdf.iters); + + /* Derive key from passphrase */ + ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, (const u8 *)pass, + strlen(pass), ks->kdf.salt, + ks->kdf.salt_len, ks->kdf.iters, + ks->area.key_size, derived_key); + if (ret) + return -EPROTO; + + size = ks->key_size * ks->af.stripes; + km_blocks = (size + desc->blksz - 1) / desc->blksz; + + /* Allocate buffers */ + split_key = malloc(size); + km = malloc_cache_aligned(km_blocks * desc->blksz); + if (!split_key || !km) { + ret = -ENOMEM; + goto out; + } + + /* Read encrypted key material */ + ret = blk_read(blk, pinfo->start + (ks->area.offset / desc->blksz), + km_blocks, km); + if (ret != km_blocks) { + ret = -EIO; + goto out; + } + + /* Decrypt key material */ + if (strstr(ks->area.encryption, "xts")) + ret = decrypt_km_xts(derived_key, ks->area.key_size, km, + split_key, size); + else + ret = decrypt_km_cbc(derived_key, ks->area.key_size, + ks->area.encryption, km, split_key, size, + km_blocks, desc->blksz); + + if (ret) + goto out; + + /* AF-merge to recover candidate key */ + ret = af_merge(split_key, cand_key, ks->key_size, ks->af.stripes, + ks->af.hash); + +out: + if (split_key) { + memset(split_key, '\0', size); + free(split_key); + } + if (km) { + memset(km, '\0', km_blocks * desc->blksz); + free(km); + } + memset(derived_key, '\0', sizeof(derived_key)); + + return ret; +} + +/* Unlock using Argon2 keyslot */ +static int try_keyslot_argon2(struct udevice *blk, struct disk_partition *pinfo, + const struct luks2_keyslot *ks, const char *pass, + u8 *cand_key) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + int ret, km_blocks, size; + u8 derived_key[128]; + u8 *split_key, *km; + + log_debug("LUKS2: trying keyslot with Argon2id (t=%u, m=%u, p=%u)\n", + ks->kdf.time, ks->kdf.memory, ks->kdf.cpus); + + /* Derive key from passphrase using Argon2id */ + log_debug("LUKS2 Argon2: passphrase='%s', t=%u, m=%u, p=%u, saltlen=%d, keylen=%u\n", + pass, ks->kdf.time, ks->kdf.memory, ks->kdf.cpus, + ks->kdf.salt_len, ks->area.key_size); + ret = argon2id_hash_raw(ks->kdf.time, ks->kdf.memory, ks->kdf.cpus, + pass, strlen(pass), ks->kdf.salt, + ks->kdf.salt_len, derived_key, + ks->area.key_size); + if (ret) { + log_err("Argon2id failed: %s\n", argon2_error_message(ret)); + return -EPROTO; + } + log_debug("LUKS2 Argon2: key derivation succeeded\n"); + + size = ks->key_size * ks->af.stripes; + km_blocks = (size + desc->blksz - 1) / desc->blksz; + + /* Allocate buffers */ + split_key = malloc(size); + km = malloc_cache_aligned(km_blocks * desc->blksz); + if (!split_key || !km) { + ret = -ENOMEM; + goto out; + } + + /* Read encrypted key material */ + ret = blk_read(blk, pinfo->start + (ks->area.offset / desc->blksz), + km_blocks, km); + if (ret != km_blocks) { + ret = -EIO; + goto out; + } + + log_debug("LUKS2 Argon2: read %d blocks from offset %llu, encryption=%s\n", + km_blocks, ks->area.offset, ks->area.encryption); + + /* Decrypt key material */ + if (strstr(ks->area.encryption, "xts")) + ret = decrypt_km_xts(derived_key, ks->area.key_size, + km, split_key, size); + else + ret = decrypt_km_cbc(derived_key, ks->area.key_size, + ks->area.encryption, km, split_key, + size, km_blocks, desc->blksz); + + if (ret) + goto out; + log_debug("LUKS2 Argon2: decryption completed successfully\n"); + + /* AF-merge to recover candidate key */ + log_debug("LUKS2 Argon2: calling AF-merge with key_size=%u, stripes=%u, hash=%s\n", + ks->key_size, ks->af.stripes, ks->af.hash); + ret = af_merge(split_key, cand_key, ks->key_size, ks->af.stripes, + ks->af.hash); + log_debug("LUKS2 Argon2: AF-merge returned %d\n", ret); + +out: + if (split_key) { + memset(split_key, '\0', size); + free(split_key); + } + if (km) { + memset(km, '\0', km_blocks * desc->blksz); + free(km); + } + memset(derived_key, '\0', sizeof(derived_key)); + + return ret; +} + +/** + * verify_master_key() - Verify a candidate master key against the digest + * + * This function takes a candidate master key (successfully derived from a + * keyslot) and verifies it matches the stored digest using the appropriate KDF. + * + * @digest: Digest information (KDF type, parameters, expected digest value) + * @md_type: mbedtls message digest type (for PBKDF2) + * @cand_key: The candidate master key to verify + * @key_size: Size of the candidate key + * @master_key: Output buffer for verified master key + * @key_sizep: Output pointer for key size + * Return: 0 if verified and copied to master_key, -EACCES if mismatch, -ve on + * error + */ +static int verify_master_key(const struct luks2_digest *digest, + mbedtls_md_type_t md_type, + const u8 *cand_key, uint key_size, u8 *master_key, + uint *key_sizep) +{ + u8 calculated_digest[128]; + int ret; + + log_debug("LUKS2: keyslot unlock succeeded, verifying digest (type=%d)\n", + digest->type); + + /* Verify against digest using the appropriate KDF */ + if (digest->type == LUKS2_KDF_PBKDF2) { + /* PBKDF2 digest verification */ + log_debug("LUKS2: verifying with PBKDF2 (iters=%u, saltlen=%d, digestlen=%d)\n", + digest->iters, digest->salt_len, digest->digest_len); + ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, cand_key, + key_size, digest->salt, + digest->salt_len, + digest->iters, + digest->digest_len, + calculated_digest); + if (ret) { + log_debug("PBKDF2 digest hash failed: %d\n", ret); + return -EACCES; + } + } else { + /* Argon2 digest verification */ + log_debug("LUKS2: verifying with Argon2 (t=%u, m=%u, p=%u)\n", + digest->time, digest->memory, digest->cpus); + ret = argon2id_hash_raw(digest->time, digest->memory, + digest->cpus, cand_key, key_size, + digest->salt, digest->salt_len, + calculated_digest, digest->digest_len); + if (ret) { + log_debug("Argon2 digest hash failed: %s\n", + argon2_error_message(ret)); + return -EACCES; + } + } + + log_debug("LUKS2: digest calculated, comparing...\n"); + if (memcmp(calculated_digest, digest->digest, digest->digest_len)) { + log_debug("LUKS2: digest mismatch!\n"); + return -EACCES; + } + + log_debug("LUKS2: digest match, unlock successful\n"); + memcpy(master_key, cand_key, key_size); + *key_sizep = key_size; + + return 0; /* Success! */ +} + +/** + * try_unlock_keyslot() - Try to unlock a single keyslot and verify master key + * + * This function attempts to unlock one keyslot by: + * 1. Reading keyslot metadata from ofnode + * 2. Deriving the candidate master key using the appropriate KDF + * 3. Verifying the candidate key against the stored digest + * + * @blk: Block device containing the LUKS partition + * @pinfo: Partition information + * @keyslot_node: ofnode for this specific keyslot + * @digest: Digest information for verification + * @md_type: mbedtls message digest type (for PBKDF2) + * @pass: User-provided 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 + */ +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 char *pass, + u8 *master_key, uint *key_sizep) +{ + struct luks2_keyslot keyslot; + u8 cand_key[128]; + uint key_size; + int ret; + + /* Read keyslot information */ + ret = read_keyslot_info(keyslot_node, &keyslot, digest->hash); + if (ret) { + /* Skip unsupported or invalid keyslots */ + return -EAGAIN; + } + + 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, 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, cand_key); + } + log_debug("LUKS2: keyslot try returned %d\n", ret); + + if (!ret) { + /* Verify the candidate key against the digest */ + ret = verify_master_key(digest, md_type, cand_key, + keyslot.key_size, master_key, + &key_size); + memset(cand_key, '\0', sizeof(cand_key)); + if (!ret) { + *key_sizep = key_size; + return 0; /* Success! */ + } + /* Verification failed, continue trying */ + } + + memset(cand_key, '\0', sizeof(cand_key)); + + return -EAGAIN; /* Continue trying other keyslots */ +} + +int unlock_luks2(struct udevice *blk, struct disk_partition *pinfo, + const char *pass, u8 *master_key, uint *key_sizep) +{ + ofnode keyslots_node, keyslot_node; + struct luks2_digest digest; + mbedtls_md_type_t md_type; + struct abuf fdt_buf; + int ret; + + /* Read and parse LUKS2 header and metadata */ + ret = read_luks2_info(blk, pinfo, &fdt_buf, &digest, &md_type, + &keyslots_node); + if (ret) + return ret; + + /* Try each keyslot until one succeeds */ + ret = -EACCES; + ofnode_for_each_subnode(keyslot_node, keyslots_node) { + ret = try_unlock_keyslot(blk, pinfo, keyslot_node, &digest, + md_type, pass, master_key, key_sizep); + if (!ret) /* Successfully unlocked! */ + break; + + /* -EAGAIN means skip, other errors also continue trying */ + } + abuf_uninit(&fdt_buf); + if (ret) { + if (ret == -EAGAIN) /* no usable slots */ + log_debug("LUKS2: no supported keyslots found\n"); + else /* no slots worked */ + log_debug("LUKS2: wrong passphrase\n"); + ret = -EACCES; + } + + return ret; +} diff --git a/drivers/block/luks_internal.h b/drivers/block/luks_internal.h index 32714787550..14d3839fe6a 100644 --- a/drivers/block/luks_internal.h +++ b/drivers/block/luks_internal.h @@ -27,4 +27,17 @@ int af_merge(const u8 *src, u8 *dst, size_t key_size, uint stripes, const char *hash_spec); +/** + * unlock_luks2() - Unlock a LUKS2 partition with a passphrase + * + * @blk: Block device + * @pinfo: Partition information + * @pass: Passphrase to unlock the partition + * @master_key: Buffer to receive the decrypted master key + * @key_sizep: Returns the key size + * Return: 0 on success, -ve on error + */ +int unlock_luks2(struct udevice *blk, struct disk_partition *pinfo, + const char *pass, u8 *master_key, uint *key_sizep); + #endif /* __LUKS_INTERNAL_H__ */ From patchwork Tue Nov 11 12:41:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 685 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=1762864969; bh=Te60GQ7oIXDagEllyuwM4V0UCKgyPfZ8VXRq5xi5dtI=; 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=uIlNp98AiTqTJmW2pRK8gGJl4ica2oBpZz4ZWNxK9IxKssjvdgyThVS8hiUJ6GvIC LDO+CfuaNBZ3CQMTBWGd3XrXDgdHkOsdRZk4Qm3APaSNmKRkJPu05GpSQxM3+eZLIo gZj8lGRz8mHhgneanNmheXg3QSxMBgGaAbZ1E1muVoQB5RCDDS7NPlIgz55S82k+D5 My1zOvbw+RbrI0DfYB/qodW+n27/G4INL6ZFj1BRZiUlVmR8kzy3ZHYV1RCwV4yizs EE1KOVFa/tlw0qub+ThGGTEntfN3XkJ1z60jHZsBHUwdW9WmP/QVCq6VRXVeG1JP6D qW1xmz9OtPzcg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 513B368484 for ; Tue, 11 Nov 2025 05:42:49 -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 95Bo3CS5fR2r for ; Tue, 11 Nov 2025 05:42:49 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864967; bh=Te60GQ7oIXDagEllyuwM4V0UCKgyPfZ8VXRq5xi5dtI=; 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=Xb0Lpkvl+gbddgzH53d40uc8x6GYd0gQsun26F6IsdN2UJR7ZeGRWdudf8Hf3Yv20 kBLONzRJNhB5kbw8lUYJDkBTz/ygXCV68mvApg5UH6K+VimrJsfyM3RveWtKI2/khm eBA7JoXQUxMQppQ5HTvezLckpb65noGiyKMYQCveoFPpyxJFGCTDeCO3JnTwTl4m1I lL4xt9UpJvTb/56wlJ/zCwfwthRKjrmbHiCuVPzPubqyeMcEOrTqa6mlX8Gm5KyMYR 8nECrHabXh3vTkauchagDt633MmU7rTq3c8DutxrvaaEsyiaDN8bo0vwk0AMv7RKjW f9GhHT5MVksaQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7D10768539 for ; Tue, 11 Nov 2025 05:42:47 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864964; bh=TjB+/yhDytnNiT1UZkpFhh/lG2TKqCjVMwDwcvs1v3Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CkBJFbt8+pQs/pzUqScEcl/p8hgjDqEpRildkvN0bKHCT3Xlq16akep3uVLECsZNx Rn2hJbPuz0nvC2iEQjww0AT9lqgB/cNOTMSIlU6kDcqbNfisl6Tq3V4kh1MxrxxQVv vEISfNU8w/Vyyx7vKBM/o1P8ZIdCphEIe68vyDojgLXDNe/dTojgFEK5wpiRq62/+Q VM4lvsFvAdzmsKwp1taH+N7VjAD8SkEgZfiAvmrCe2RvSgtCf+/769wykkzuTXNFW+ VAO16C/YOP9kxbAgkAvWVexDyyDmQNNqwgYwzksf7Jn2de5p6RFxOEviXVfrqpRIfa GUCyOQXmhWA1Q== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 324CC68484; Tue, 11 Nov 2025 05:42:44 -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 10026) with ESMTP id Y2A8-vwf8jYH; Tue, 11 Nov 2025 05:42:44 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1762864964; bh=XhvIbkSHzxnRjlZqC/kBQ78NVojsCzrO8EzZHFzSTUs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ikXvEiOkEqHs30U7AT2omW0YBodTdXKtROGK67qCQVmSNcYWmm0BAHJIqtEVPtEMZ 5dwZaK/VxjZrgNu0AFjgyPvEIb+Ue0OM35OOBkk2UY1XGHMSwW+QVZ4dnF1pwXO1KL TPETztQYG9e/FUp/w1NQMQEfihze6XVRPBeqIBHCbTMPtc1xRUBBW/dWbxNotNRQRd 1gpl9Qh2SDHr0x6lX5ykgy5OBYDHcZbts0TkhHaG9GZohRQkVJu+onkth334Tni8rw izeSQJVj4FncsQ2YRu0qE/LJMK32sHBO2P4BCq0k9aMasHI9b82wOieK3vZmuuwE9G T1OupjvGqbsOA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id AA5C768472; Tue, 11 Nov 2025 05:42:43 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 11 Nov 2025 05:41:20 -0700 Message-ID: <20251111124131.1198930-15-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251111124131.1198930-1-sjg@u-boot.org> References: <20251111124131.1198930-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: GZ7USSQUU47DOE2CCDP3P45U3AVADC5E X-Message-ID-Hash: GZ7USSQUU47DOE2CCDP3P45U3AVADC5E 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: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 14/15] luks: Enable LUKSv2 support in the luks command 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 Allow unlocking a v2 LUKS partition. Signed-off-by: Simon Glass --- cmd/luks.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/luks.c b/cmd/luks.c index 19f909be96b..c1e8035e685 100644 --- a/cmd/luks.c +++ b/cmd/luks.c @@ -85,10 +85,7 @@ static int do_luks_unlock(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - if (version != LUKS_VERSION_1) { - printf("Only LUKS1 is currently supported\n"); - return CMD_RET_FAILURE; - } + printf("Unlocking LUKS%d partition...\n", version); /* Unlock the partition to get the master key */ ret = luks_unlock(dev_desc->bdev, &info, passphrase, master_key,