fscrypt-crypt-util: refactor get_key_and_iv()
[xfstests-dev.git] / src / fscrypt-crypt-util.c
index e59922754405f4ecbc310ffddd23dc7544123765..124eb23f4f1c457eacbba599940c0ac7505b5ac4 100644 (file)
@@ -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 {