Commit 6b2a51ff authored by Nathan Huckleberry's avatar Nathan Huckleberry Committed by Herbert Xu

fscrypt: Add HCTR2 support for filename encryption

HCTR2 is a tweakable, length-preserving encryption mode that is intended
for use on CPUs with dedicated crypto instructions.  HCTR2 has the
property that a bitflip in the plaintext changes the entire ciphertext.
This property fixes a known weakness with filename encryption: when two
filenames in the same directory share a prefix of >= 16 bytes, with
AES-CTS-CBC their encrypted filenames share a common substring, leaking
information.  HCTR2 does not have this problem.

More information on HCTR2 can be found here: "Length-preserving
encryption with HCTR2": https://eprint.iacr.org/2021/1441.pdfSigned-off-by: default avatarNathan Huckleberry <nhuck@google.com>
Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
Acked-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 9d2c0b48
...@@ -337,6 +337,7 @@ Currently, the following pairs of encryption modes are supported: ...@@ -337,6 +337,7 @@ Currently, the following pairs of encryption modes are supported:
- AES-256-XTS for contents and AES-256-CTS-CBC for filenames - AES-256-XTS for contents and AES-256-CTS-CBC for filenames
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames - AES-128-CBC for contents and AES-128-CTS-CBC for filenames
- Adiantum for both contents and filenames - Adiantum for both contents and filenames
- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only)
If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair. If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
...@@ -357,6 +358,17 @@ To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast ...@@ -357,6 +358,17 @@ To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast
implementations of ChaCha and NHPoly1305 should be enabled, e.g. implementations of ChaCha and NHPoly1305 should be enabled, e.g.
CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM. CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM.
AES-256-HCTR2 is another true wide-block encryption mode that is intended for
use on CPUs with dedicated crypto instructions. AES-256-HCTR2 has the property
that a bitflip in the plaintext changes the entire ciphertext. This property
makes it desirable for filename encryption since initialization vectors are
reused within a directory. For more details on AES-256-HCTR2, see the paper
"Length-preserving encryption with HCTR2"
(https://eprint.iacr.org/2021/1441.pdf). To use AES-256-HCTR2,
CONFIG_CRYPTO_HCTR2 must be enabled. Also, fast implementations of XCTR and
POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and
CRYPTO_AES_ARM64_CE_BLK for ARM64.
New encryption modes can be added relatively easily, without changes New encryption modes can be added relatively easily, without changes
to individual filesystems. However, authenticated encryption (AE) to individual filesystems. However, authenticated encryption (AE)
modes are not currently supported because of the difficulty of dealing modes are not currently supported because of the difficulty of dealing
...@@ -404,11 +416,11 @@ alternatively has the file's nonce (for `DIRECT_KEY policies`_) or ...@@ -404,11 +416,11 @@ alternatively has the file's nonce (for `DIRECT_KEY policies`_) or
inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs. inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs.
Thus, IV reuse is limited to within a single directory. Thus, IV reuse is limited to within a single directory.
With CTS-CBC, the IV reuse means that when the plaintext filenames With CTS-CBC, the IV reuse means that when the plaintext filenames share a
share a common prefix at least as long as the cipher block size (16 common prefix at least as long as the cipher block size (16 bytes for AES), the
bytes for AES), the corresponding encrypted filenames will also share corresponding encrypted filenames will also share a common prefix. This is
a common prefix. This is undesirable. Adiantum does not have this undesirable. Adiantum and HCTR2 do not have this weakness, as they are
weakness, as it is a wide-block encryption mode. wide-block encryption modes.
All supported filenames encryption modes accept any plaintext length All supported filenames encryption modes accept any plaintext length
>= 16 bytes; cipher block alignment is not required. However, >= 16 bytes; cipher block alignment is not required. However,
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define FSCRYPT_CONTEXT_V2 2 #define FSCRYPT_CONTEXT_V2 2
/* Keep this in sync with include/uapi/linux/fscrypt.h */ /* Keep this in sync with include/uapi/linux/fscrypt.h */
#define FSCRYPT_MODE_MAX FSCRYPT_MODE_ADIANTUM #define FSCRYPT_MODE_MAX FSCRYPT_MODE_AES_256_HCTR2
struct fscrypt_context_v1 { struct fscrypt_context_v1 {
u8 version; /* FSCRYPT_CONTEXT_V1 */ u8 version; /* FSCRYPT_CONTEXT_V1 */
......
...@@ -53,6 +53,13 @@ struct fscrypt_mode fscrypt_modes[] = { ...@@ -53,6 +53,13 @@ struct fscrypt_mode fscrypt_modes[] = {
.ivsize = 32, .ivsize = 32,
.blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM, .blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM,
}, },
[FSCRYPT_MODE_AES_256_HCTR2] = {
.friendly_name = "AES-256-HCTR2",
.cipher_str = "hctr2(aes)",
.keysize = 32,
.security_strength = 32,
.ivsize = 32,
},
}; };
static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex); static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex);
......
...@@ -61,7 +61,7 @@ fscrypt_get_dummy_policy(struct super_block *sb) ...@@ -61,7 +61,7 @@ fscrypt_get_dummy_policy(struct super_block *sb)
return sb->s_cop->get_dummy_policy(sb); return sb->s_cop->get_dummy_policy(sb);
} }
static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode)
{ {
if (contents_mode == FSCRYPT_MODE_AES_256_XTS && if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
filenames_mode == FSCRYPT_MODE_AES_256_CTS) filenames_mode == FSCRYPT_MODE_AES_256_CTS)
...@@ -78,6 +78,14 @@ static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) ...@@ -78,6 +78,14 @@ static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
return false; return false;
} }
static bool fscrypt_valid_enc_modes_v2(u32 contents_mode, u32 filenames_mode)
{
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
filenames_mode == FSCRYPT_MODE_AES_256_HCTR2)
return true;
return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode);
}
static bool supported_direct_key_modes(const struct inode *inode, static bool supported_direct_key_modes(const struct inode *inode,
u32 contents_mode, u32 filenames_mode) u32 contents_mode, u32 filenames_mode)
{ {
...@@ -151,7 +159,7 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy, ...@@ -151,7 +159,7 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,
static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
const struct inode *inode) const struct inode *inode)
{ {
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, if (!fscrypt_valid_enc_modes_v1(policy->contents_encryption_mode,
policy->filenames_encryption_mode)) { policy->filenames_encryption_mode)) {
fscrypt_warn(inode, fscrypt_warn(inode,
"Unsupported encryption modes (contents %d, filenames %d)", "Unsupported encryption modes (contents %d, filenames %d)",
...@@ -187,7 +195,7 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, ...@@ -187,7 +195,7 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
{ {
int count = 0; int count = 0;
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, if (!fscrypt_valid_enc_modes_v2(policy->contents_encryption_mode,
policy->filenames_encryption_mode)) { policy->filenames_encryption_mode)) {
fscrypt_warn(inode, fscrypt_warn(inode,
"Unsupported encryption modes (contents %d, filenames %d)", "Unsupported encryption modes (contents %d, filenames %d)",
......
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
#define FSCRYPT_MODE_AES_128_CBC 5 #define FSCRYPT_MODE_AES_128_CBC 5
#define FSCRYPT_MODE_AES_128_CTS 6 #define FSCRYPT_MODE_AES_128_CTS 6
#define FSCRYPT_MODE_ADIANTUM 9 #define FSCRYPT_MODE_ADIANTUM 9
/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */ #define FSCRYPT_MODE_AES_256_HCTR2 10
/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
/* /*
* Legacy policy version; ad-hoc KDF and no key verification. * Legacy policy version; ad-hoc KDF and no key verification.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment