From patchwork Sun Mar 13 01:05:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 12779001 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C0BEC4167D for ; Sun, 13 Mar 2022 01:06:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232055AbiCMBHq (ORCPT ); Sat, 12 Mar 2022 20:07:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36852 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233318AbiCMBHp (ORCPT ); Sat, 12 Mar 2022 20:07:45 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A9D3148937; Sat, 12 Mar 2022 17:06:38 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id F0A06B80A28; Sun, 13 Mar 2022 01:06:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 861B7C340EC; Sun, 13 Mar 2022 01:06:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1647133595; bh=to6IW2z9U18TCna1FETwt+H7w+MF+NBX+9yA6HLX51w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XZuCvijrPx7w/6sbzTX4IMtT47ee+ckrR8TWvzKmJ5bKyS/nTTI4/gL0FOPYyCUnF +CAfMCuweUgMO36OHTNdG4CLQdAbo+uw0b8c8eEOnwnZ3wAag7dxh+0CPtCx5a0OFO kB7qL/F6g12Z9I2BtAc8yCKFcT4TeLr5/BMFq04/z2FirwQvw3tw8bND3L8PGzwFJz SyvP4fzdlW5WO19y7hBfvCyW8jSlZwrpZFquyoJ8d/omQm34Qufhy2VeV533NGNkl0 bus1F50F3kJGC8Kz0n/lSxgdDx2JYHnHjF9bISXhgmEYa9jMGsyesyLAYBFPTKj5li oDID8pktuz2pA== From: Eric Biggers To: fstests@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org Subject: [PATCH v2 1/5] fscrypt-crypt-util: use an explicit --direct-key option Date: Sat, 12 Mar 2022 17:05:55 -0800 Message-Id: <20220313010559.545995-2-ebiggers@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220313010559.545995-1-ebiggers@kernel.org> References: <20220313010559.545995-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org From: Eric Biggers Make fscrypt-crypt-util use an option --direct-key to specify the use of the DIRECT_KEY method for key derivation and IV generation. Previously, this method was implicitly detected via --mode-num being given without either --iv-ino-lblk-64 or --iv-ino-lblk-32, or --kdf=none being given in combination with --file-nonce. The benefit of this change is that it makes the various options to fscrypt-crypt-util behave more consistently. --direct-key, --iv-ino-lblk-64, and --iv-ino-lblk-32 now all work similarly (they select a key derivation and IV generation method); likewise, --mode-num, --file-nonce, --inode-number, and --fs-uuid now all work similarly (they provide information that key derivation and IV generation may need). Signed-off-by: Eric Biggers --- common/encrypt | 10 ++++---- src/fscrypt-crypt-util.c | 52 ++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/common/encrypt b/common/encrypt index f90c4ef0..2cf02ca0 100644 --- a/common/encrypt +++ b/common/encrypt @@ -842,27 +842,25 @@ _verify_ciphertext_for_encryption_policy() set_encpolicy_args+=" -c $contents_mode_num" set_encpolicy_args+=" -n $filenames_mode_num" + crypt_util_contents_args+=" --mode-num=$contents_mode_num" + crypt_util_filename_args+=" --mode-num=$filenames_mode_num" if (( policy_version > 1 )); then set_encpolicy_args+=" -v 2" crypt_util_args+=" --kdf=HKDF-SHA512" if (( policy_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then - crypt_util_args+=" --mode-num=$contents_mode_num" + crypt_util_args+=" --direct-key" elif (( policy_flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 )); then crypt_util_args+=" --iv-ino-lblk-64" - crypt_util_contents_args+=" --mode-num=$contents_mode_num" - crypt_util_filename_args+=" --mode-num=$filenames_mode_num" elif (( policy_flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )); then crypt_util_args+=" --iv-ino-lblk-32" - crypt_util_contents_args+=" --mode-num=$contents_mode_num" - crypt_util_filename_args+=" --mode-num=$filenames_mode_num" fi else if (( policy_flags & ~FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then _fail "unsupported flags for v1 policy: $policy_flags" fi if (( policy_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then - crypt_util_args+=" --kdf=none" + crypt_util_args+=" --direct-key --kdf=none" else crypt_util_args+=" --kdf=AES-128-ECB" fi diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c index 03cc3c4a..e5992275 100644 --- a/src/fscrypt-crypt-util.c +++ b/src/fscrypt-crypt-util.c @@ -64,6 +64,8 @@ static void usage(FILE *fp) " --block-size=BLOCK_SIZE Encrypt each BLOCK_SIZE bytes independently.\n" " Default: 4096 bytes\n" " --decrypt Decrypt instead of encrypt\n" +" --direct-key Use the format where the IVs include the file\n" +" nonce and the same key is shared across files.\n" " --file-nonce=NONCE File's nonce as a 32-character hex string\n" " --fs-uuid=UUID The filesystem UUID as a 32-character hex string.\n" " Required for --iv-ino-lblk-32 and\n" @@ -76,11 +78,10 @@ static void usage(FILE *fp) " 32-bit variant.\n" " --iv-ino-lblk-64 Use the format where the IVs include the inode\n" " number and the same key is shared across files.\n" -" Requires --kdf=HKDF-SHA512, --fs-uuid,\n" -" --inode-number, and --mode-num.\n" " --kdf=KDF Key derivation function to use: AES-128-ECB,\n" " HKDF-SHA512, or none. Default: none\n" -" --mode-num=NUM Derive per-mode key using mode number NUM\n" +" --mode-num=NUM The encryption mode number. This may be required\n" +" for key derivation, depending on other options.\n" " --padding=PADDING If last block is partial, zero-pad it to next\n" " PADDING-byte boundary. Default: BLOCK_SIZE\n" , fp); @@ -1790,6 +1791,7 @@ struct key_and_iv_params { u8 mode_num; u8 file_nonce[FILE_NONCE_SIZE]; bool file_nonce_specified; + bool direct_key; bool iv_ino_lblk_64; bool iv_ino_lblk_32; u64 block_number; @@ -1835,7 +1837,7 @@ static void get_key_and_iv(const struct key_and_iv_params *params, u8 *real_key, size_t real_key_size, union fscrypt_iv *iv) { - bool file_nonce_in_iv = false; + int iv_methods = 0; struct aes_key aes_key; u8 info[8 + 1 + 1 + UUID_SIZE] = "fscrypt"; size_t infolen = 8; @@ -1848,11 +1850,22 @@ static void get_key_and_iv(const struct key_and_iv_params *params, /* Overridden later for iv_ino_lblk_{64,32} */ iv->block_number = cpu_to_le64(params->block_number); - if (params->iv_ino_lblk_64 || params->iv_ino_lblk_32) { + iv_methods += params->direct_key; + iv_methods += params->iv_ino_lblk_64; + iv_methods += params->iv_ino_lblk_32; + if (iv_methods > 1) + die("Conflicting IV methods specified"); + if (iv_methods > 0 && params->kdf == KDF_AES_128_ECB) + die("--kdf=AES-128-ECB is incompatible with IV method options"); + + if (params->direct_key) { + if (!params->file_nonce_specified) + die("--direct-key requires --file-nonce"); + if (params->kdf != KDF_NONE && params->mode_num == 0) + die("--direct-key with KDF requires --mode-num"); + } else if (params->iv_ino_lblk_64 || params->iv_ino_lblk_32) { const char *opt = params->iv_ino_lblk_64 ? "--iv-ino-lblk-64" : "--iv-ino-lblk-32"; - if (params->iv_ino_lblk_64 && params->iv_ino_lblk_32) - die("--iv-ino-lblk-64 and --iv-ino-lblk-32 are mutually exclusive"); if (params->kdf != KDF_HKDF_SHA512) die("%s requires --kdf=HKDF-SHA512", opt); if (!params->fs_uuid_specified) @@ -1869,16 +1882,11 @@ static void get_key_and_iv(const struct key_and_iv_params *params, switch (params->kdf) { case KDF_NONE: - if (params->mode_num != 0) - die("--mode-num isn't supported with --kdf=none"); memcpy(real_key, params->master_key, real_key_size); - file_nonce_in_iv = true; break; case KDF_AES_128_ECB: if (!params->file_nonce_specified) - die("--file-nonce is required with --kdf=AES-128-ECB"); - if (params->mode_num != 0) - die("--mode-num isn't supported with --kdf=AES-128-ECB"); + die("--kdf=AES-128-ECB requires --file-nonce"); STATIC_ASSERT(FILE_NONCE_SIZE == AES_128_KEY_SIZE); ASSERT(real_key_size % AES_BLOCK_SIZE == 0); aes_setkey(&aes_key, params->file_nonce, AES_128_KEY_SIZE); @@ -1887,7 +1895,10 @@ static void get_key_and_iv(const struct key_and_iv_params *params, &real_key[i]); break; case KDF_HKDF_SHA512: - if (params->iv_ino_lblk_64) { + if (params->direct_key) { + info[infolen++] = HKDF_CONTEXT_DIRECT_KEY; + info[infolen++] = params->mode_num; + } else if (params->iv_ino_lblk_64) { info[infolen++] = HKDF_CONTEXT_IV_INO_LBLK_64_KEY; info[infolen++] = params->mode_num; memcpy(&info[infolen], params->fs_uuid, UUID_SIZE); @@ -1903,17 +1914,13 @@ static void get_key_and_iv(const struct key_and_iv_params *params, cpu_to_le32(hash_inode_number(params) + params->block_number); iv->inode_number = 0; - } else if (params->mode_num != 0) { - info[infolen++] = HKDF_CONTEXT_DIRECT_KEY; - info[infolen++] = params->mode_num; - file_nonce_in_iv = true; } else if (params->file_nonce_specified) { info[infolen++] = HKDF_CONTEXT_PER_FILE_ENC_KEY; memcpy(&info[infolen], params->file_nonce, FILE_NONCE_SIZE); infolen += FILE_NONCE_SIZE; } else { - die("With --kdf=HKDF-SHA512, at least one of --file-nonce and --mode-num must be specified"); + die("--kdf=HKDF-SHA512 requires --file-nonce or --iv-ino-lblk-{64,32}"); } hkdf_sha512(params->master_key, params->master_key_size, NULL, 0, info, infolen, real_key, real_key_size); @@ -1922,7 +1929,7 @@ static void get_key_and_iv(const struct key_and_iv_params *params, ASSERT(0); } - if (file_nonce_in_iv && params->file_nonce_specified) + if (params->direct_key) memcpy(iv->nonce, params->file_nonce, FILE_NONCE_SIZE); } @@ -1930,6 +1937,7 @@ enum { OPT_BLOCK_NUMBER, OPT_BLOCK_SIZE, OPT_DECRYPT, + OPT_DIRECT_KEY, OPT_FILE_NONCE, OPT_FS_UUID, OPT_HELP, @@ -1945,6 +1953,7 @@ static const struct option longopts[] = { { "block-number", required_argument, NULL, OPT_BLOCK_NUMBER }, { "block-size", required_argument, NULL, OPT_BLOCK_SIZE }, { "decrypt", no_argument, NULL, OPT_DECRYPT }, + { "direct-key", no_argument, NULL, OPT_DIRECT_KEY }, { "file-nonce", required_argument, NULL, OPT_FILE_NONCE }, { "fs-uuid", required_argument, NULL, OPT_FS_UUID }, { "help", no_argument, NULL, OPT_HELP }, @@ -1999,6 +2008,9 @@ int main(int argc, char *argv[]) case OPT_DECRYPT: decrypting = true; break; + case OPT_DIRECT_KEY: + params.direct_key = true; + break; case OPT_FILE_NONCE: if (hex2bin(optarg, params.file_nonce, FILE_NONCE_SIZE) != FILE_NONCE_SIZE) From patchwork Sun Mar 13 01:05:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 12779002 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2EB94C433F5 for ; Sun, 13 Mar 2022 01:06:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233320AbiCMBHr (ORCPT ); Sat, 12 Mar 2022 20:07:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233321AbiCMBHp (ORCPT ); Sat, 12 Mar 2022 20:07:45 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A90D614994A; Sat, 12 Mar 2022 17:06:38 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 35C5EB80A0A; Sun, 13 Mar 2022 01:06:37 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BD003C340F4; Sun, 13 Mar 2022 01:06:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1647133595; bh=nPJW1Y1N6I6YGJJusDwMhGoanPnRuOvDgTSB7YPzg+M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vJ4ZAeyGgkGE34ssh+hXJQ3h1aZmvqJ1RrSrGx/lDMSXCbeRfYc1K8ZZTyq4QL2I+ qhA9HqbnwJHX4lA9o9HM6JY8cEw9AQIab6tV28AjJM2/8GtrDN9Wawva4ElBjpfoSq /un8OuU7QwtAbuuuigPV48u6VNRtje25U5t4ow87t9v+U6wxBts4rlTwdqhQnYfS38 Hjts3CmuWAm11WWxiANx9A8Fn4hHni9Q3C9gW0SzS8/dHhJ5QzYGRlhDkxjR/cLFSV m+moJDrfpYx5gak+PuRb8ILxCHJ9Q8DY8kx7+ujM6VcEefi9mXlGvuKZaj1FoxXYdS C5u8P7IeQEDdg== From: Eric Biggers To: fstests@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org Subject: [PATCH v2 2/5] fscrypt-crypt-util: refactor get_key_and_iv() Date: Sat, 12 Mar 2022 17:05:56 -0800 Message-Id: <20220313010559.545995-3-ebiggers@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220313010559.545995-1-ebiggers@kernel.org> References: <20220313010559.545995-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org From: Eric Biggers Split get_key_and_iv() into two distinct parts: (1) deriving the key and (2) generating the IV. Also, check for the presence of needed options just before they are used rather than doing it all up-front. These changes should make this code much easier to understand. Signed-off-by: Eric Biggers --- src/fscrypt-crypt-util.c | 124 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c index e5992275..124eb23f 100644 --- a/src/fscrypt-crypt-util.c +++ b/src/fscrypt-crypt-util.c @@ -1818,6 +1818,9 @@ static u32 hash_inode_number(const struct key_and_iv_params *params) } hash_key; info[8] = HKDF_CONTEXT_INODE_HASH_KEY; + + if (params->kdf != KDF_HKDF_SHA512) + die("--iv-ino-lblk-32 requires --kdf=HKDF-SHA512"); hkdf_sha512(params->master_key, params->master_key_size, NULL, 0, info, sizeof(info), hash_key.bytes, sizeof(hash_key)); @@ -1828,16 +1831,9 @@ static u32 hash_inode_number(const struct key_and_iv_params *params) return (u32)siphash_1u64(hash_key.words, params->inode_number); } -/* - * Get the key and starting IV with which the encryption will actually be done. - * If a KDF was specified, a subkey is derived from the master key and the mode - * number or file nonce. Otherwise, the master key is used directly. - */ -static void get_key_and_iv(const struct key_and_iv_params *params, - u8 *real_key, size_t real_key_size, - union fscrypt_iv *iv) +static void derive_real_key(const struct key_and_iv_params *params, + u8 *real_key, size_t real_key_size) { - int iv_methods = 0; struct aes_key aes_key; u8 info[8 + 1 + 1 + UUID_SIZE] = "fscrypt"; size_t infolen = 8; @@ -1845,41 +1841,6 @@ static void get_key_and_iv(const struct key_and_iv_params *params, ASSERT(real_key_size <= params->master_key_size); - memset(iv, 0, sizeof(*iv)); - - /* Overridden later for iv_ino_lblk_{64,32} */ - iv->block_number = cpu_to_le64(params->block_number); - - iv_methods += params->direct_key; - iv_methods += params->iv_ino_lblk_64; - iv_methods += params->iv_ino_lblk_32; - if (iv_methods > 1) - die("Conflicting IV methods specified"); - if (iv_methods > 0 && params->kdf == KDF_AES_128_ECB) - die("--kdf=AES-128-ECB is incompatible with IV method options"); - - if (params->direct_key) { - if (!params->file_nonce_specified) - die("--direct-key requires --file-nonce"); - if (params->kdf != KDF_NONE && params->mode_num == 0) - die("--direct-key with KDF requires --mode-num"); - } else if (params->iv_ino_lblk_64 || params->iv_ino_lblk_32) { - const char *opt = params->iv_ino_lblk_64 ? "--iv-ino-lblk-64" : - "--iv-ino-lblk-32"; - if (params->kdf != KDF_HKDF_SHA512) - die("%s requires --kdf=HKDF-SHA512", opt); - if (!params->fs_uuid_specified) - die("%s requires --fs-uuid", opt); - if (params->inode_number == 0) - die("%s requires --inode-number", opt); - if (params->mode_num == 0) - die("%s requires --mode-num", opt); - if (params->block_number > UINT32_MAX) - die("%s can't use --block-number > UINT32_MAX", opt); - if (params->inode_number > UINT32_MAX) - die("%s can't use --inode-number > UINT32_MAX", opt); - } - switch (params->kdf) { case KDF_NONE: memcpy(real_key, params->master_key, real_key_size); @@ -1896,31 +1857,35 @@ static void get_key_and_iv(const struct key_and_iv_params *params, break; case KDF_HKDF_SHA512: if (params->direct_key) { + if (params->mode_num == 0) + die("--direct-key with KDF requires --mode-num"); info[infolen++] = HKDF_CONTEXT_DIRECT_KEY; info[infolen++] = params->mode_num; } else if (params->iv_ino_lblk_64) { + if (params->mode_num == 0) + die("--iv-ino-lblk-64 with KDF requires --mode-num"); + if (!params->fs_uuid_specified) + die("--iv-ino-lblk-64 with KDF requires --fs-uuid"); info[infolen++] = HKDF_CONTEXT_IV_INO_LBLK_64_KEY; info[infolen++] = params->mode_num; memcpy(&info[infolen], params->fs_uuid, UUID_SIZE); infolen += UUID_SIZE; - iv->block_number32 = cpu_to_le32(params->block_number); - iv->inode_number = cpu_to_le32(params->inode_number); } else if (params->iv_ino_lblk_32) { + if (params->mode_num == 0) + die("--iv-ino-lblk-32 with KDF requires --mode-num"); + if (!params->fs_uuid_specified) + die("--iv-ino-lblk-32 with KDF requires --fs-uuid"); info[infolen++] = HKDF_CONTEXT_IV_INO_LBLK_32_KEY; info[infolen++] = params->mode_num; memcpy(&info[infolen], params->fs_uuid, UUID_SIZE); infolen += UUID_SIZE; - iv->block_number32 = - cpu_to_le32(hash_inode_number(params) + - params->block_number); - iv->inode_number = 0; - } else if (params->file_nonce_specified) { + } else { + if (!params->file_nonce_specified) + die("--kdf=HKDF-SHA512 requires --file-nonce or --iv-ino-lblk-{64,32}"); info[infolen++] = HKDF_CONTEXT_PER_FILE_ENC_KEY; memcpy(&info[infolen], params->file_nonce, FILE_NONCE_SIZE); infolen += FILE_NONCE_SIZE; - } else { - die("--kdf=HKDF-SHA512 requires --file-nonce or --iv-ino-lblk-{64,32}"); } hkdf_sha512(params->master_key, params->master_key_size, NULL, 0, info, infolen, real_key, real_key_size); @@ -1928,9 +1893,60 @@ static void get_key_and_iv(const struct key_and_iv_params *params, default: ASSERT(0); } +} - if (params->direct_key) +static void generate_iv(const struct key_and_iv_params *params, + union fscrypt_iv *iv) +{ + memset(iv, 0, sizeof(*iv)); + if (params->direct_key) { + if (!params->file_nonce_specified) + die("--direct-key requires --file-nonce"); + iv->block_number = cpu_to_le64(params->block_number); memcpy(iv->nonce, params->file_nonce, FILE_NONCE_SIZE); + } else if (params->iv_ino_lblk_64) { + if (params->block_number > UINT32_MAX) + die("iv-ino-lblk-64 can't use --block-number > UINT32_MAX"); + if (params->inode_number == 0) + die("iv-ino-lblk-64 requires --inode-number"); + if (params->inode_number > UINT32_MAX) + die("iv-ino-lblk-64 can't use --inode-number > UINT32_MAX"); + iv->block_number32 = cpu_to_le32(params->block_number); + iv->inode_number = cpu_to_le32(params->inode_number); + } else if (params->iv_ino_lblk_32) { + if (params->block_number > UINT32_MAX) + die("iv-ino-lblk-32 can't use --block-number > UINT32_MAX"); + if (params->inode_number == 0) + die("iv-ino-lblk-32 requires --inode-number"); + iv->block_number32 = cpu_to_le32(hash_inode_number(params) + + params->block_number); + } else { + iv->block_number = cpu_to_le64(params->block_number); + } +} + +/* + * Get the key and starting IV with which the encryption will actually be done. + * If a KDF was specified, then a subkey is derived from the master key. + * Otherwise, the master key is used directly. + */ +static void get_key_and_iv(const struct key_and_iv_params *params, + u8 *real_key, size_t real_key_size, + union fscrypt_iv *iv) +{ + int iv_methods = 0; + + iv_methods += params->direct_key; + iv_methods += params->iv_ino_lblk_64; + iv_methods += params->iv_ino_lblk_32; + if (iv_methods > 1) + die("Conflicting IV methods specified"); + if (iv_methods > 0 && params->kdf == KDF_AES_128_ECB) + die("--kdf=AES-128-ECB is incompatible with IV method options"); + + derive_real_key(params, real_key, real_key_size); + + generate_iv(params, iv); } enum { From patchwork Sun Mar 13 01:05:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 12778997 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0D78C433F5 for ; Sun, 13 Mar 2022 01:06:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233316AbiCMBHo (ORCPT ); Sat, 12 Mar 2022 20:07:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36766 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231147AbiCMBHn (ORCPT ); Sat, 12 Mar 2022 20:07:43 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AF51145E38; Sat, 12 Mar 2022 17:06:37 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 9F46C60DC6; Sun, 13 Mar 2022 01:06:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id F3B1EC340F3; Sun, 13 Mar 2022 01:06:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1647133596; bh=xSWwMaATSOlo0tZ18wM2im1YC+0I7XtkCleyPTUOXE4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KIbbAyZlVUwPQlgZ4+NSZ/FEnOTksBOI1IV1qg2wxSAhHNaVp9mj6GZXgsvEsWyAf Ajbu+dLoAOCn9e/oe01r8n+XXKlaZbiaiDU/U1hEsko8WWbg7D2LqsDR8CbspxN8vX GHbCks97u3Mls0XG5oVRPJBYlGPzx7MGXieQr2HVS4R0Ki1jyPavi72zdSPCNjtgay QqyPulnAaIkVcKByCReAEj+zZgiKTVWsI+pQdLLtHfr8ryT6RsAlSHq5lxP+hm4Y7s G4q8hBSrZyl0eGiYqqfmduUEsYPKpN3u8AvIx/QjCkQxQzvUPyuhhfypZYd6UmcxOX MSTMzhpV+8Fog== From: Eric Biggers To: fstests@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org Subject: [PATCH v2 3/5] fscrypt-crypt-util: add support for dumping key identifier Date: Sat, 12 Mar 2022 17:05:57 -0800 Message-Id: <20220313010559.545995-4-ebiggers@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220313010559.545995-1-ebiggers@kernel.org> References: <20220313010559.545995-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org From: Eric Biggers Add an option to fscrypt-crypt-util to make it compute the key identifier for the given key. This will allow testing the correctness of the filesystem's key identifier computation. Signed-off-by: Eric Biggers --- src/fscrypt-crypt-util.c | 51 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c index 124eb23f..ffb9534d 100644 --- a/src/fscrypt-crypt-util.c +++ b/src/fscrypt-crypt-util.c @@ -46,7 +46,7 @@ static void usage(FILE *fp) { fputs( -"Usage: " PROGRAM_NAME " [OPTION]... CIPHER MASTER_KEY\n" +"Usage: " PROGRAM_NAME " [OPTION]... [CIPHER | --dump-key-identifier] MASTER_KEY\n" "\n" "Utility for verifying fscrypt-encrypted data. This program encrypts\n" "(or decrypts) the data on stdin using the given CIPHER with the given\n" @@ -66,6 +66,8 @@ static void usage(FILE *fp) " --decrypt Decrypt instead of encrypt\n" " --direct-key Use the format where the IVs include the file\n" " nonce and the same key is shared across files.\n" +" --dump-key-identifier Instead of encrypting/decrypting data, just\n" +" compute and dump the key identifier.\n" " --file-nonce=NONCE File's nonce as a 32-character hex string\n" " --fs-uuid=UUID The filesystem UUID as a 32-character hex string.\n" " Required for --iv-ino-lblk-32 and\n" @@ -1949,11 +1951,38 @@ static void get_key_and_iv(const struct key_and_iv_params *params, generate_iv(params, iv); } +static void do_dump_key_identifier(const struct key_and_iv_params *params) +{ + u8 info[9] = "fscrypt"; + u8 key_identifier[16]; + int i; + + info[8] = HKDF_CONTEXT_KEY_IDENTIFIER; + + if (params->kdf != KDF_HKDF_SHA512) + die("--dump-key-identifier requires --kdf=HKDF-SHA512"); + hkdf_sha512(params->master_key, params->master_key_size, + NULL, 0, info, sizeof(info), + key_identifier, sizeof(key_identifier)); + + for (i = 0; i < sizeof(key_identifier); i++) + printf("%02x", key_identifier[i]); +} + +static void parse_master_key(const char *arg, struct key_and_iv_params *params) +{ + params->master_key_size = hex2bin(arg, params->master_key, + MAX_KEY_SIZE); + if (params->master_key_size < 0) + die("Invalid master_key: %s", arg); +} + enum { OPT_BLOCK_NUMBER, OPT_BLOCK_SIZE, OPT_DECRYPT, OPT_DIRECT_KEY, + OPT_DUMP_KEY_IDENTIFIER, OPT_FILE_NONCE, OPT_FS_UUID, OPT_HELP, @@ -1970,6 +1999,7 @@ static const struct option longopts[] = { { "block-size", required_argument, NULL, OPT_BLOCK_SIZE }, { "decrypt", no_argument, NULL, OPT_DECRYPT }, { "direct-key", no_argument, NULL, OPT_DIRECT_KEY }, + { "dump-key-identifier", no_argument, NULL, OPT_DUMP_KEY_IDENTIFIER }, { "file-nonce", required_argument, NULL, OPT_FILE_NONCE }, { "fs-uuid", required_argument, NULL, OPT_FS_UUID }, { "help", no_argument, NULL, OPT_HELP }, @@ -1986,6 +2016,7 @@ int main(int argc, char *argv[]) { size_t block_size = 4096; bool decrypting = false; + bool dump_key_identifier = false; struct key_and_iv_params params; size_t padding = 0; const struct fscrypt_cipher *cipher; @@ -2027,6 +2058,9 @@ int main(int argc, char *argv[]) case OPT_DIRECT_KEY: params.direct_key = true; break; + case OPT_DUMP_KEY_IDENTIFIER: + dump_key_identifier = true; + break; case OPT_FILE_NONCE: if (hex2bin(optarg, params.file_nonce, FILE_NONCE_SIZE) != FILE_NONCE_SIZE) @@ -2074,6 +2108,15 @@ int main(int argc, char *argv[]) argc -= optind; argv += optind; + if (dump_key_identifier) { + if (argc != 1) { + usage(stderr); + return 2; + } + parse_master_key(argv[0], ¶ms); + do_dump_key_identifier(¶ms); + return 0; + } if (argc != 2) { usage(stderr); return 2; @@ -2087,10 +2130,8 @@ int main(int argc, char *argv[]) die("Block size of %zu bytes is too small for cipher %s", block_size, cipher->name); - params.master_key_size = hex2bin(argv[1], params.master_key, - MAX_KEY_SIZE); - if (params.master_key_size < 0) - die("Invalid master_key: %s", argv[1]); + parse_master_key(argv[1], ¶ms); + if (params.master_key_size < cipher->keysize) die("Master key is too short for cipher %s", cipher->name); From patchwork Sun Mar 13 01:05:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 12778998 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E42FC43217 for ; Sun, 13 Mar 2022 01:06:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232296AbiCMBHq (ORCPT ); Sat, 12 Mar 2022 20:07:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232055AbiCMBHo (ORCPT ); Sat, 12 Mar 2022 20:07:44 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 50B231470DF; Sat, 12 Mar 2022 17:06:37 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id DCD8D60DD8; Sun, 13 Mar 2022 01:06:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 35773C340F5; Sun, 13 Mar 2022 01:06:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1647133596; bh=k4S5di8zkPHlytVqNzUKf65R4jUD1HKT508FSPuOsA8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DDbbwEPJT1hHytorHuv4AbNo+VIoPSYjfv0phRFw6m4LoSFQeMf9jhRnhvegRj8rH NbuRKHLfxZcwORev1Qych11LAYbPTUtoEMvAWaHpE/RiyidcP5BoPhGiix46x0VqKV iSy4ePqLgjfXmoRiSnCx8BqHMNF1aiyvVrbl+C43vqbjXIiA5Ls4luO/MCGbVkid3U waKyuesodWSUlBDpM3I8fKN3HYsXX9DgpZN8ZnNmjdK2x4tBQ/WFjuT8l4b0aaLcpc b6ok3wZqWkVxucCA6dzsqavyRPpkhJyOHz4hjGYrKPE8ISD3EJZZDjx/7lkt4fqOZ9 JRekqU5vskt0Q== From: Eric Biggers To: fstests@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org Subject: [PATCH v2 4/5] common/encrypt: log full ciphertext verification params Date: Sat, 12 Mar 2022 17:05:58 -0800 Message-Id: <20220313010559.545995-5-ebiggers@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220313010559.545995-1-ebiggers@kernel.org> References: <20220313010559.545995-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org From: Eric Biggers To help with debugging, log some additional information to $seqres.full. Signed-off-by: Eric Biggers --- common/encrypt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common/encrypt b/common/encrypt index 2cf02ca0..cf402570 100644 --- a/common/encrypt +++ b/common/encrypt @@ -908,6 +908,17 @@ _verify_ciphertext_for_encryption_policy() echo -e "\tfilenames_encryption_mode: $filenames_encryption_mode" [ $# -ne 0 ] && echo -e "\toptions: $*" + cat >> $seqres.full < X-Patchwork-Id: 12779000 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B77B8C4167B for ; Sun, 13 Mar 2022 01:06:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233325AbiCMBHr (ORCPT ); Sat, 12 Mar 2022 20:07:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233320AbiCMBHp (ORCPT ); Sat, 12 Mar 2022 20:07:45 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 31343149979; Sat, 12 Mar 2022 17:06:39 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id D6D69B80AF4; Sun, 13 Mar 2022 01:06:37 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6C1CCC340F7; Sun, 13 Mar 2022 01:06:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1647133596; bh=0hiKtnvItwbeAVZHNDETPFE8syYxYRcQaVRMGhIxECM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jEZ6kHkBZGcXpASLKqYGG4lBh1Kyq2fL2gC7O/yot1W+WFYiVLkA2UKplN99Iv1qR SXN43vx6u1cfXtjwcSy9JyZOwzYHcSfUDmPsxLacKoykzKR6bTW+1jpz0voeXcW8rK gQIzZP0aiFMeLdexW/asc1bD3sWH3ZyLa8aSvMTHPNlpKuds7AUmi2Ppb/9nHUAyWN VZ1URr8IN91KlgrPOja3q0E7NaqLXo4BEsa79uNDcMIGpZd5oIMkRuOBcEEfHeeQgV gS7DMucvW06tvMT3q3CoIAQr6/AY4o+89Me6V8fU7NM1+owWlwvJcDkSTvmgTOqVF+ 978C+M9TsT2bw== From: Eric Biggers To: fstests@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org Subject: [PATCH v2 5/5] common/encrypt: verify the key identifiers Date: Sat, 12 Mar 2022 17:05:59 -0800 Message-Id: <20220313010559.545995-6-ebiggers@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220313010559.545995-1-ebiggers@kernel.org> References: <20220313010559.545995-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org From: Eric Biggers As part of all the ciphertext verification tests, verify that the filesystem correctly computed the key identifier from the key the test generated. This uses fscrypt-crypt-util to compute the key identifier. Previously this was only being tested indirectly, via the tests that happen to use the hardcoded $TEST_RAW_KEY and $TEST_KEY_IDENTIFIER. The new check provides better coverage. Signed-off-by: Eric Biggers --- common/encrypt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/encrypt b/common/encrypt index cf402570..78a574bd 100644 --- a/common/encrypt +++ b/common/encrypt @@ -812,6 +812,7 @@ _verify_ciphertext_for_encryption_policy() local crypt_util_args="" local crypt_util_contents_args="" local crypt_util_filename_args="" + local expected_identifier shift 2 for opt; do @@ -902,6 +903,18 @@ _verify_ciphertext_for_encryption_policy() fi local raw_key_hex=$(echo "$raw_key" | tr -d '\\x') + if (( policy_version > 1 )); then + echo "Verifying key identifier" >> $seqres.full + expected_identifier=$($here/src/fscrypt-crypt-util \ + --dump-key-identifier "$raw_key_hex" \ + $crypt_util_args) + if [ "$expected_identifier" != "$keyspec" ]; then + echo "KEY IDENTIFIER MISMATCH!" + echo " Expected: $expected_identifier" + echo " Actual: $keyspec" + fi + fi + echo echo -e "Verifying ciphertext with parameters:" echo -e "\tcontents_encryption_mode: $contents_encryption_mode"