aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2022-03-12 17:05:56 -0800
committerEryu Guan <guaneryu@gmail.com>2022-04-10 20:40:44 +0800
commit02222a33a0e59aac403b92a3e0dfb7953566b446 (patch)
tree219575412887add82e4eba9fd2ee89bec311f7b4
parentcd81e731261d0d062ad8ed8216deb51b110e4fd7 (diff)
downloadxfstests-dev-02222a33a0e59aac403b92a3e0dfb7953566b446.tar.gz
fscrypt-crypt-util: refactor get_key_and_iv()
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 <ebiggers@google.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
-rw-r--r--src/fscrypt-crypt-util.c124
1 files changed, 70 insertions, 54 deletions
diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c
index e599227544..124eb23f4f 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 {