On Wed, Oct 07, 2020 at 10:05:00PM +0000, Satya Tangirala wrote: > > I notice this is missing the step I suggested to include the metadata encryption > > key in the HKDF application-specific info string when deriving subkeys from the > > fscrypt master keys. > > > > The same effect could also be achieved by adding an additional level to the key > > hierarchy: each HKDF key would be derived from a fscrypt master key and the > > metadata encryption key. > > > > We need one of those, to guarantee that the file contents encryption is at least > > as strong as the "metadata encryption". > > > Yes - I didn't get around to that in the first version, but I'll add > that too in the next version. I was going to go with the first approach > before I saw your comment - is there one method you'd recommend going > with over the other? I'm not entirely sure, but I'm now leaning towards the second approach because it would avoid adding additional work (another SHA-512 block) to all later key derivations. Also it would avoid having to add a super_block argument to fscrypt_hkdf_expand(). But please ask Paul Crowley for his suggestion too. Here's a quick untested patch to consider: diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index dca254590a70..67f8ba3098d3 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -319,6 +319,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, #define HKDF_CONTEXT_DIRHASH_KEY 5 /* info=file_nonce */ #define HKDF_CONTEXT_IV_INO_LBLK_32_KEY 6 /* info=mode_num||fs_uuid */ #define HKDF_CONTEXT_INODE_HASH_KEY 7 /* info=<empty> */ +#define HKDF_CONTEXT_MIX_METADATA_KEY 8 /* info=metadata_key */ int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, @@ -600,6 +601,20 @@ int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci); +/* metadata_crypt.c */ + +#ifdef CONFIG_FS_ENCRYPTION_METADATA +int fscrypt_mix_in_metadata_key(struct super_block *sb, + struct fscrypt_master_key_secret *secret); +#else +static inline int +fscrypt_mix_in_metadata_key(struct super_block *sb, + struct fscrypt_master_key_secret *secret) +{ + return 0; +} +#endif + /* policy.c */ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, diff --git a/fs/crypto/hkdf.c b/fs/crypto/hkdf.c index 0cba7928446d..61d1f0aa802e 100644 --- a/fs/crypto/hkdf.c +++ b/fs/crypto/hkdf.c @@ -174,4 +174,5 @@ int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf) { crypto_free_shash(hkdf->hmac_tfm); + hkdf->hmac_tfm = NULL; } diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index e74f239c4428..43453a7f77b1 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -494,6 +494,10 @@ static int add_master_key(struct super_block *sb, */ memzero_explicit(secret->raw, secret->size); + err = fscrypt_mix_in_metadata_key(sb, secret); + if (err) + return err; + /* Calculate the key identifier */ err = fscrypt_hkdf_expand(&secret->hkdf, HKDF_CONTEXT_KEY_IDENTIFIER, NULL, 0, diff --git a/fs/crypto/metadata_crypt.c b/fs/crypto/metadata_crypt.c index 5e16df130509..233e68c35504 100644 --- a/fs/crypto/metadata_crypt.c +++ b/fs/crypto/metadata_crypt.c @@ -13,6 +13,32 @@ #include "fscrypt_private.h" +/* TODO: add comment */ +int fscrypt_mix_in_metadata_key(struct super_block *sb, + struct fscrypt_master_key_secret *secret) +{ + u8 real_key[FSCRYPT_MAX_KEY_SIZE]; + int err; + + if (WARN_ON(secret->size > sizeof(real_key))) + return -EINVAL; + + if (!sb->s_metadata_key) + return 0; + + err = fscrypt_hkdf_expand(&secret->hkdf, HKDF_CONTEXT_MIX_METADATA_KEY, + sb->s_metadata_key->raw, + sb->s_metadata_key->size, + real_key, secret->size); + if (err) + return err; + + fscrypt_destroy_hkdf(&secret->hkdf); + err = fscrypt_init_hkdf(&secret->hkdf, real_key, secret->size); + memzero_explicit(real_key, secret->size); + return err; +} + /* TODO: mostly copied from keysetup_v1.c - maybe refactor this function */ static int fscrypt_metadata_get_key_from_id(const char *prefix, char *descriptor_hex,