fscrypt: add support for IV_INO_LBLK_32 policies
Subsystems (5)
Eric Biggers
maintainerPATCH 1/1 fscrypt: add support for IV_INO_LBLK_32 policies
From: Eric Biggers <[email protected]>
The eMMC inline crypto standard will only specify 32 DUN bits (a.k.a. IV bits), unlike UFS's 64. IV_INO_LBLK_64 is therefore not applicable, but an encryption format which uses one key per policy and permits the moving of encrypted file contents (as f2fs's garbage collector requires) is still desirable.
To support such hardware, add a new encryption format IV_INO_LBLK_32 that makes the best use of the 32 bits: the IV is set to 'SipHash-2-4(inode_number) + file_logical_block_number mod 2^32', where the SipHash key is derived from the fscrypt master key. We hash only the inode number and not also the block number, because we need to maintain contiguity of DUNs to merge bios.
Unlike with IV_INO_LBLK_64, with this format IV reuse is possible; this is unavoidable given the size of the DUN. This means this format should only be used where the requirements of the first paragraph apply. However, the hash spreads out the IVs in the whole usable range, and the use of a keyed hash makes it difficult for an attacker to determine which files use which IVs.
Besides the above differences, this flag works like IV_INO_LBLK_64 in that on ext4 it is only allowed if the stable_inodes feature has been enabled to prevent inode numbers and the filesystem UUID from changing.
--- Documentation/filesystems/fscrypt.rst | 33 +++++++++-- fs/crypto/crypto.c | 6 +- fs/crypto/fscrypt_private.h | 20 +++++-- fs/crypto/keyring.c | 5 +- fs/crypto/keysetup.c | 85 +++++++++++++++++++++------ fs/crypto/policy.c | 51 +++++++++++----- include/uapi/linux/fscrypt.h | 3 +- 7 files changed, 157 insertions(+), 46 deletions(-)
Documentation/filesystems/fscrypt.rst +29 -4
@@ -292,8 +292,22 @@ files' data differently, inode numbers are included in the IVs. Consequently, shrinking the filesystem may not be allowed. This format is optimized for use with inline encryption hardware -compliant with the UFS or eMMC standards, which support only 64 IV -bits per I/O request and may have only a small number of keyslots. +compliant with the UFS standard, which supports only 64 IV bits per +I/O request and may have only a small number of keyslots. + +IV_INO_LBLK_32 policies +----------------------- + +IV_INO_LBLK_32 policies work like IV_INO_LBLK_64, except that for +IV_INO_LBLK_32, the inode number is hashed with SipHash-2-4 (where the +SipHash key is derived from the master key) and added to the file +logical block number mod 2^32 to produce a 32-bit IV. + +This format is optimized for use with inline encryption hardware +compliant with the eMMC v5.2 standard, which supports only 32 IV bits +per I/O request and may have only a small number of keyslots. This +format results in some level of IV reuse, so it should only be used +when necessary due to hardware limitations. Key identifiers ---------------
@@ -369,6 +383,10 @@ a little endian number, except that: to 32 bits and is placed in bits 0-31 of the IV. The inode number (which is also limited to 32 bits) is placed in bits 32-63. +- With `IV_INO_LBLK_32 policies`_, the logical block number is limited + to 32 bits and is placed in bits 0-31 of the IV. The inode number + is then hashed and added mod 2^32. + Note that because file logical block numbers are included in the IVs, filesystems must enforce that blocks are never shifted around within encrypted files, e.g. via "collapse range" or "insert range".
@@ -465,8 +483,15 @@ This structure must be initialized as follows: (0x3). - FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_. - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64 - policies`_. This is mutually exclusive with DIRECT_KEY and is not - supported on v1 policies. + policies`_. + - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: See `IV_INO_LBLK_32 + policies`_. + + v1 encryption policies only support the PAD_* and DIRECT_KEY flags. + The other flags are only supported by v2 encryption policies. + + The DIRECT_KEY, IV_INO_LBLK_64, and IV_INO_LBLK_32 flags are + mutually exclusive. - For v2 encryption policies, ``__reserved`` must be zeroed.
fs/crypto/crypto.c +5 -1
@@ -76,8 +76,12 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,memset (iv,0 , ci->ci_mode->ivsize);if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ) { -WARN_ON_ONCE ((u32 )lblk_num != lblk_num); +WARN_ON_ONCE (lblk_num >U32_MAX ); +WARN_ON_ONCE (ci->ci_inode->i_ino >U32_MAX ); lblk_num |= (u64 )ci->ci_inode->i_ino <<32 ; + }else if (flags &FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ) { +WARN_ON_ONCE (lblk_num >U32_MAX ); + lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); }else if (flags &FSCRYPT_POLICY_FLAG_DIRECT_KEY ) {memcpy (iv->nonce, ci->ci_nonce,FS_KEY_DERIVATION_NONCE_SIZE ); }
fs/crypto/fscrypt_private.h +14 -6
@@ -222,6 +222,9 @@ struct fscrypt_info {/* This inode's nonce, copied from the fscrypt_context */ u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE ]; + +/* Hashed inode number. Only set for IV_INO_LBLK_32 */ +u32 ci_hashed_ino; }; typedef enum {
@@ -293,6 +296,8 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,#define HKDF_CONTEXT_DIRECT_KEY 3#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4#define HKDF_CONTEXT_DIRHASH_KEY 5 +#define HKDF_CONTEXT_IV_INO_LBLK_32_KEY 6 +#define HKDF_CONTEXT_INODE_HASH_KEY 7 extern int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen,
@@ -389,14 +394,17 @@ struct fscrypt_master_key {struct list_head mk_decrypted_inodes;spinlock_t mk_decrypted_inodes_lock; -/* Crypto API transforms for DIRECT_KEY policies, allocated on-demand */ -struct crypto_skcipher *mk_direct_tfms[__FSCRYPT_MODE_MAX +1 ]; -/* -* Crypto API transforms for filesystem-layer implementation of -* IV_INO_LBLK_64 policies, allocated on-demand. +* Per-mode encryption keys for the various types of encryption policies +* that use them. Allocated and derived on-demand. */ -struct crypto_skcipher *mk_iv_ino_lblk_64_tfms[__FSCRYPT_MODE_MAX +1 ]; +struct crypto_skcipher *mk_direct_keys[__FSCRYPT_MODE_MAX +1 ]; +struct crypto_skcipher *mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX +1 ]; +struct crypto_skcipher *mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX +1 ]; + +/* Hash key for inode numbers. Initialized only when needed. */ +siphash_key_t mk_ino_hash_key; +bool mk_ino_hash_key_initialized; } __randomize_layout;
fs/crypto/keyring.c +3 -2
@@ -44,8 +44,9 @@ static void free_master_key(struct fscrypt_master_key *mk)wipe_master_key_secret (&mk->mk_secret);for (i =0 ; i <= __FSCRYPT_MODE_MAX; i++) { -crypto_free_skcipher (mk->mk_direct_tfms[i]); -crypto_free_skcipher (mk->mk_iv_ino_lblk_64_tfms[i]); +crypto_free_skcipher (mk->mk_direct_keys[i]); +crypto_free_skcipher (mk->mk_iv_ino_lblk_64_keys[i]); +crypto_free_skcipher (mk->mk_iv_ino_lblk_32_keys[i]); }key_put (mk->mk_users);
fs/crypto/keysetup.c +67 -18
135 lines not on this page · raw message
fs/crypto/policy.c +37 -14
96 lines not on this page · raw message
include/uapi/linux/fscrypt.h +2 -1
@@ -19,7 +19,8 @@#define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03#define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 -#define FSCRYPT_POLICY_FLAGS_VALID 0x0F +#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 0x10 +#define FSCRYPT_POLICY_FLAGS_VALID 0x1F/* Encryption algorithms */ #define FSCRYPT_MODE_AES_256_XTS 1
Signature · 1 line
2.26.2
Quoted 22 lines · Eric Biggers
From: Eric Biggers <[email protected]>
The eMMC inline crypto standard will only specify 32 DUN bits (a.k.a. IV bits), unlike UFS's 64.
IV_INO_LBLK_64is therefore not applicable, but an encryption format which uses one key per policy and permits the moving of encrypted file contents (as f2fs's garbage collector requires) is still desirable.To support such hardware, add a new encryption format
IV_INO_LBLK_32that makes the best use of the 32 bits: the IV is set to 'SipHash-2-4(inode_number) +file_logical_block_numbermod 2^32', where the SipHash key is derived from the fscrypt master key. We hash only the inode number and not also the block number, because we need to maintain contiguity of DUNs to merge bios.Unlike with
IV_INO_LBLK_64, with this format IV reuse is possible; this is unavoidable given the size of the DUN. This means this format should only be used where the requirements of the first paragraph apply. However, the hash spreads out the IVs in the whole usable range, and the use of a keyed hash makes it difficult for an attacker to determine which files use which IVs.
Quoted 5 lines
Besides the above differences, this flag works like
IV_INO_LBLK_64in that on ext4 it is only allowed if thestable_inodesfeature has been enabled to prevent inode numbers and the filesystem UUID from changing.Signed-off-by Eric Biggers <[email protected]>
I kind of wish we had Kunit tests with test vectors, but that's for another commit I think.
- Ted
_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Eric Biggers
maintainerQuoted 27 lines · Theodore Y. Ts'o
Quoted 26 lines · Eric Biggers
From: Eric Biggers <[email protected]>
The eMMC inline crypto standard will only specify 32 DUN bits (a.k.a. IV bits), unlike UFS's 64.
IV_INO_LBLK_64is therefore not applicable, but an encryption format which uses one key per policy and permits the moving of encrypted file contents (as f2fs's garbage collector requires) is still desirable.To support such hardware, add a new encryption format
IV_INO_LBLK_32that makes the best use of the 32 bits: the IV is set to 'SipHash-2-4(inode_number) +file_logical_block_numbermod 2^32', where the SipHash key is derived from the fscrypt master key. We hash only the inode number and not also the block number, because we need to maintain contiguity of DUNs to merge bios.Unlike with
IV_INO_LBLK_64, with this format IV reuse is possible; this is unavoidable given the size of the DUN. This means this format should only be used where the requirements of the first paragraph apply. However, the hash spreads out the IVs in the whole usable range, and the use of a keyed hash makes it difficult for an attacker to determine which files use which IVs.Besides the above differences, this flag works like
IV_INO_LBLK_64in that on ext4 it is only allowed if thestable_inodesfeature has been enabled to prevent inode numbers and the filesystem UUID from changing.
Quoted 7 lines
Quoted 1 line
Signed-off-by Eric Biggers <[email protected]>Reviewed-by Theodore Ts'o <[email protected]>I kind of wish we had Kunit tests with test vectors, but that's for another commit I think.
We do have ciphertext verification tests in xfstests for all the existing fscrypt options. Actually, I had hacked one together for IV_INO_LBLK_32 before sending this patch
(https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/xfstests-dev.git/commit/?id=55153ceee2948269c0359bd97fc0d58a26139c87).
I'll be sending it for review after I've looked over it again.
Similarly, since earlier this year, we now also have ciphertext verification tests in Android's VTS (Vendor Test Suite)
(https://android.googlesource.com/platform/test/vts-testcase/kernel/+/refs/heads/master/encryption/).
I'll be adding one for this new flag.
These ciphertext verification tests test the round-trip from the key added by userspace to the data on-disk -- even if the data is encrypted by inline crypto hardware rather than the kernel itself. So they're better than Kunit tests.
The thing I'm struggling with a bit is actually that when inline crypto is used, IV_INO_LBLK_32 introduces a case where the DUN can wrap from 0xffffffff to 0, and that case is new/special in that blocks can't be merged over that boundary even if they are both logically and physically contiguous. So, we could also use a test that tests doing I/O around this boundary where the DUN wraps around.
- Eric
Quoted 9 lines · Eric Biggers
From: Eric Biggers <[email protected]>
The eMMC inline crypto standard will only specify 32 DUN bits (a.k.a. IV bits), unlike UFS's 64.
IV_INO_LBLK_64is therefore not applicable, but an encryption format which uses one key per policy and permits the moving of encrypted file contents (as f2fs's garbage collector requires) is still desirable.
Quoted 6 lines
To support such hardware, add a new encryption format
IV_INO_LBLK_32that makes the best use of the 32 bits: the IV is set to 'SipHash-2-4(inode_number) +file_logical_block_numbermod 2^32', where the SipHash key is derived from the fscrypt master key. We hash only the inode number and not also the block number, because we need to maintain contiguity of DUNs to merge bios.
This is the best that can be done cryptographically on such hardware.
_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Quoted 27 lines · Eric Biggers
From: Eric Biggers <[email protected]>
The eMMC inline crypto standard will only specify 32 DUN bits (a.k.a. IV bits), unlike UFS's 64.
IV_INO_LBLK_64is therefore not applicable, but an encryption format which uses one key per policy and permits the moving of encrypted file contents (as f2fs's garbage collector requires) is still desirable.To support such hardware, add a new encryption format
IV_INO_LBLK_32that makes the best use of the 32 bits: the IV is set to 'SipHash-2-4(inode_number) +file_logical_block_numbermod 2^32', where the SipHash key is derived from the fscrypt master key. We hash only the inode number and not also the block number, because we need to maintain contiguity of DUNs to merge bios.Unlike with
IV_INO_LBLK_64, with this format IV reuse is possible; this is unavoidable given the size of the DUN. This means this format should only be used where the requirements of the first paragraph apply. However, the hash spreads out the IVs in the whole usable range, and the use of a keyed hash makes it difficult for an attacker to determine which files use which IVs.Besides the above differences, this flag works like
IV_INO_LBLK_64in that on ext4 it is only allowed if thestable_inodesfeature has been enabled to prevent inode numbers and the filesystem UUID from changing.Signed-off-by Eric Biggers <[email protected]>
Quoted 9 lines
--- Documentation/filesystems/fscrypt.rst | 33 +++++++++-- fs/crypto/crypto.c | 6 +- fs/crypto/fscrypt_private.h | 20 +++++-- fs/crypto/keyring.c | 5 +- fs/crypto/keysetup.c | 85 +++++++++++++++++++++------ fs/crypto/policy.c | 51 +++++++++++----- include/uapi/linux/fscrypt.h | 3 +- 7 files changed, 157 insertions(+), 46 deletions(-)
Applied to fscrypt.git#master for 5.8.
- Eric