fscrypt: fix derivation of SipHash keys on big endian CPUs
Subsystems (2)
Eric Biggers
maintainerPATCH v2 1/1 fscrypt: fix derivation of SipHash keys on big endian CPUs
From: Eric Biggers <[email protected]>
Typically, the cryptographic APIs that fscrypt uses take keys as byte arrays, which avoids endianness issues. However, siphash_key_t is an exception. It is defined as 'u64 key[2];', i.e. the 128-bit key is expected to be given directly as two 64-bit words in CPU endianness.
fscrypt_derive_dirhash_key() and fscrypt_setup_iv_ino_lblk_32_key() forgot to take this into account. Therefore, the SipHash keys used to index encrypted+casefolded directories differ on big endian vs. little endian platforms, as do the SipHash keys used to hash inode numbers for IV_INO_LBLK_32-encrypted directories. This makes such directories non-portable between these platforms.
Fix this by always using the little endian order. This is a breaking change for big endian platforms, but this should be fine in practice since these features (encrypt+casefold support, and the IV_INO_LBLK_32 flag) aren't known to actually be used on any big endian platforms yet.
---
v2: Fixed fscrypt_setup_iv_ino_lblk_32_key() too, not just
fscrypt_derive_dirhash_key().
fs/crypto/keysetup.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-)
fs/crypto/keysetup.c +32 -8
@@ -210,15 +210,40 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,return err; } +/* +* Derive a SipHash key from the given fscrypt master key and the given +* application-specific information string. +* +* Note that the KDF produces a byte array, but the SipHash APIs expect the key +* as a pair of 64-bit words. Therefore, on big endian CPUs we have to do an +* endianness swap in order to get the same results as on little endian CPUs. +*/ +static int fscrypt_derive_siphash_key (const struct fscrypt_master_key *mk, +u8 context,const u8 *info, +unsigned int infolen,siphash_key_t *key) +{ +int err; + + err =fscrypt_hkdf_expand (&mk->mk_secret.hkdf, context, info, infolen, + (u8 *)key,sizeof (*key)); +if (err) +return err; + +BUILD_BUG_ON (sizeof (*key) !=16 ); +BUILD_BUG_ON (ARRAY_SIZE (key->key) !=2 ); +le64_to_cpus (&key->key[0 ]); +le64_to_cpus (&key->key[1 ]); +return 0 ; +} +int fscrypt_derive_dirhash_key (struct fscrypt_info *ci,const struct fscrypt_master_key *mk) {int err; - err =fscrypt_hkdf_expand (&mk->mk_secret.hkdf,HKDF_CONTEXT_DIRHASH_KEY , - ci->ci_nonce,FSCRYPT_FILE_NONCE_SIZE , - (u8 *)&ci->ci_dirhash_key, -sizeof (ci->ci_dirhash_key)); + err =fscrypt_derive_siphash_key (mk,HKDF_CONTEXT_DIRHASH_KEY , + ci->ci_nonce,FSCRYPT_FILE_NONCE_SIZE , + &ci->ci_dirhash_key);if (err)return err; ci->ci_dirhash_key_initialized = true;
@@ -253,10 +278,9 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,if (mk->mk_ino_hash_key_initialized) goto unlock; - err =fscrypt_hkdf_expand (&mk->mk_secret.hkdf, -HKDF_CONTEXT_INODE_HASH_KEY ,NULL ,0 , - (u8 *)&mk->mk_ino_hash_key, -sizeof (mk->mk_ino_hash_key)); + err =fscrypt_derive_siphash_key (mk, +HKDF_CONTEXT_INODE_HASH_KEY , +NULL ,0 , &mk->mk_ino_hash_key);if (err) goto unlock;/* pairs with smp_load_acquire() above */
base-commit: 77f30bfcfcf484da7208affd6a9e63406420bf91
Signature · 1 line
2.31.1
Quoted 23 lines · Eric Biggers
From: Eric Biggers <[email protected]>
Typically, the cryptographic APIs that fscrypt uses take keys as byte arrays, which avoids endianness issues. However,
siphash_key_tis an exception. It is defined as 'u64 key[2];', i.e. the 128-bit key is expected to be given directly as two 64-bit words in CPU endianness.
fscrypt_derive_dirhash_key()andfscrypt_setup_iv_ino_lblk_32_key()forgot to take this into account. Therefore, the SipHash keys used to index encrypted+casefolded directories differ on big endian vs. little endian platforms, as do the SipHash keys used to hash inode numbers for IV_INO_LBLK_32-encrypted directories. This makes such directories non-portable between these platforms.Fix this by always using the little endian order. This is a breaking change for big endian platforms, but this should be fine in practice since these features (encrypt+casefold support, and the
IV_INO_LBLK_32flag) aren't known to actually be used on any big endian platforms yet.Fixes aa408f835d02 ("fscrypt: derive dirhash key for casefolded directories")Fixes e3b1078bedd3 ("fscrypt: add support for IV_INO_LBLK_32 policies")Cc <[email protected]> # v5.6+Signed-off-by Eric Biggers <[email protected]>
Quoted 8 lines
---
v2: Fixed
fscrypt_setup_iv_ino_lblk_32_key()too, not just
fscrypt_derive_dirhash_key().fs/crypto/keysetup.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-)
Applied to fscrypt.git#master for 5.14.
- Eric