OSDN Git Service

BACKPORT, FROMLIST: fscrypt: add Speck128/256 support
authorEric Biggers <ebiggers@google.com>
Tue, 8 May 2018 00:22:08 +0000 (17:22 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 25 May 2018 15:41:18 +0000 (15:41 +0000)
fscrypt currently only supports AES encryption.  However, many low-end
mobile devices have older CPUs that don't have AES instructions, e.g.
the ARMv8 Cryptography Extensions.  Currently, user data on such devices
is not encrypted at rest because AES is too slow, even when the NEON
bit-sliced implementation of AES is used.  Unfortunately, it is
infeasible to encrypt these devices at all when AES is the only option.

Therefore, this patch updates fscrypt to support the Speck block cipher,
which was recently added to the crypto API.  The C implementation of
Speck is not especially fast, but Speck can be implemented very
efficiently with general-purpose vector instructions, e.g. ARM NEON.
For example, on an ARMv7 processor, we measured the NEON-accelerated
Speck128/256-XTS at 69 MB/s for both encryption and decryption, while
AES-256-XTS with the NEON bit-sliced implementation was only 22 MB/s
encryption and 19 MB/s decryption.

There are multiple variants of Speck.  This patch only adds support for
Speck128/256, which is the variant with a 128-bit block size and 256-bit
key size -- the same as AES-256.  This is believed to be the most secure
variant of Speck, and it's only about 6% slower than Speck128/128.
Speck64/128 would be at least 20% faster because it has 20% rounds, and
it can be even faster on CPUs that can't efficiently do the 64-bit
operations needed for Speck128.  However, Speck64's 64-bit block size is
not preferred security-wise.  ARM NEON also supports the needed 64-bit
operations even on 32-bit CPUs, resulting in Speck128 being fast enough
for our targeted use cases so far.

The chosen modes of operation are XTS for contents and CTS-CBC for
filenames.  These are the same modes of operation that fscrypt defaults
to for AES.  Note that as with the other fscrypt modes, Speck will not
be used unless userspace chooses to use it.  Nor are any of the existing
modes (which are all AES-based) being removed, of course.

We intentionally don't make CONFIG_FS_ENCRYPTION select
CONFIG_CRYPTO_SPECK, so people will have to enable Speck support
themselves if they need it.  This is because we shouldn't bloat the
FS_ENCRYPTION dependencies with every new cipher, especially ones that
aren't recommended for most users.  Moreover, CRYPTO_SPECK is just the
generic implementation, which won't be fast enough for many users; in
practice, they'll need to enable CRYPTO_SPECK_NEON to get acceptable
performance.

More details about our choice of Speck can be found in our patches that
added Speck to the crypto API, and the follow-on discussion threads.
We're planning a publication that explains the choice in more detail.
But briefly, we can't use ChaCha20 as we previously proposed, since it
would be insecure to use a stream cipher in this context, with potential
IV reuse during writes on f2fs and/or on wear-leveling flash storage.

We also evaluated many other lightweight and/or ARX-based block ciphers
such as Chaskey-LTS, RC5, LEA, CHAM, Threefish, RC6, NOEKEON, SPARX, and
XTEA.  However, all had disadvantages vs. Speck, such as insufficient
performance with NEON, much less published cryptanalysis, or an
insufficient security level.  Various design choices in Speck make it
perform better with NEON than competing ciphers while still having a
security margin similar to AES, and in the case of Speck128 also the
same available security levels.  Unfortunately, Speck does have some
political baggage attached -- it's an NSA designed cipher, and was
rejected from an ISO standard (though for context, as far as I know none
of the above-mentioned alternatives are ISO standards either).
Nevertheless, we believe it is a good solution to the problem from a
technical perspective.

Certain algorithms constructed from ChaCha or the ChaCha permutation,
such as MEM (Masked Even-Mansour) or HPolyC, may also meet our
performance requirements.  However, these are new constructions that
need more time to receive the cryptographic review and acceptance needed
to be confident in their security.  HPolyC hasn't been published yet,
and we are concerned that MEM makes stronger assumptions about the
underlying permutation than the ChaCha stream cipher does.  In contrast,
the XTS mode of operation is relatively well accepted, and Speck has
over 70 cryptanalysis papers.  Of course, these ChaCha-based algorithms
can still be added later if they become ready.

The best known attack on Speck128/256 is a differential cryptanalysis
attack on 25 of 34 rounds with 2^253 time complexity and 2^125 chosen
plaintexts, i.e. only marginally faster than brute force.  There is no
known attack on the full 34 rounds.

Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
(cherry-picked from commit 12d28f79558f2e987c5f3817f89e1ccc0f11a7b5
 https://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt.git master)
(dropped Documentation/filesystems/fscrypt.rst change)
(fixed merge conflict in fs/crypto/keyinfo.c)
(also ported change to fs/ext4/, which isn't using fs/crypto/ in this
 kernel version)
Change-Id: I62c632044dfd06a2c5b74c2fb058f9c3b8af0add
Signed-off-by: Eric Biggers <ebiggers@google.com>
fs/crypto/fscrypt_private.h
fs/crypto/keyinfo.c
fs/ext4/crypto.c
fs/ext4/crypto_fname.c
fs/ext4/crypto_key.c
fs/ext4/crypto_policy.c
fs/ext4/ext4.h
fs/ext4/ext4_crypto.h
include/uapi/linux/fs.h

index 426aa1b..fe6f652 100644 (file)
@@ -101,6 +101,10 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
            filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
                return true;
 
+       if (contents_mode == FS_ENCRYPTION_MODE_SPECK128_256_XTS &&
+           filenames_mode == FS_ENCRYPTION_MODE_SPECK128_256_CTS)
+               return true;
+
        return false;
 }
 
index 7c00331..472f691 100644 (file)
@@ -134,6 +134,8 @@ static const struct {
                                             FS_AES_128_CBC_KEY_SIZE },
        [FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))",
                                             FS_AES_128_CTS_KEY_SIZE },
+       [FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)",      64 },
+       [FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 },
 };
 
 static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
index f240cef..f6096ee 100644 (file)
@@ -457,9 +457,17 @@ errout:
        return err;
 }
 
-bool ext4_valid_contents_enc_mode(uint32_t mode)
+bool ext4_valid_enc_modes(uint32_t contents_mode, uint32_t filenames_mode)
 {
-       return (mode == EXT4_ENCRYPTION_MODE_AES_256_XTS);
+       if (contents_mode == EXT4_ENCRYPTION_MODE_AES_256_XTS) {
+               return (filenames_mode == EXT4_ENCRYPTION_MODE_AES_256_CTS ||
+                       filenames_mode == EXT4_ENCRYPTION_MODE_AES_256_HEH);
+       }
+
+       if (contents_mode == EXT4_ENCRYPTION_MODE_SPECK128_256_XTS)
+               return filenames_mode == EXT4_ENCRYPTION_MODE_SPECK128_256_CTS;
+
+       return false;
 }
 
 /**
index 026716b..5e5afb6 100644 (file)
@@ -42,12 +42,6 @@ static void ext4_dir_crypt_complete(struct crypto_async_request *req, int res)
        complete(&ecr->completion);
 }
 
-bool ext4_valid_filenames_enc_mode(uint32_t mode)
-{
-       return (mode == EXT4_ENCRYPTION_MODE_AES_256_CTS ||
-               mode == EXT4_ENCRYPTION_MODE_AES_256_HEH);
-}
-
 static unsigned max_name_len(struct inode *inode)
 {
        return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
index 14ae778..6822522 100644 (file)
@@ -258,6 +258,12 @@ int ext4_get_encryption_info(struct inode *inode)
        case EXT4_ENCRYPTION_MODE_AES_256_HEH:
                cipher_str = "heh(aes)";
                break;
+       case EXT4_ENCRYPTION_MODE_SPECK128_256_XTS:
+               cipher_str = "xts(speck128)";
+               break;
+       case EXT4_ENCRYPTION_MODE_SPECK128_256_CTS:
+               cipher_str = "cts(cbc(speck128))";
+               break;
        default:
                printk_once(KERN_WARNING
                            "ext4: unsupported key mode %d (ino %u)\n",
index e4f4fc4..818fa45 100644 (file)
@@ -60,16 +60,12 @@ static int ext4_create_encryption_context_from_policy(
        ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
        memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
               EXT4_KEY_DESCRIPTOR_SIZE);
-       if (!ext4_valid_contents_enc_mode(policy->contents_encryption_mode)) {
+       if (!ext4_valid_enc_modes(policy->contents_encryption_mode,
+                                 policy->filenames_encryption_mode)) {
                printk(KERN_WARNING
-                      "%s: Invalid contents encryption mode %d\n", __func__,
-                       policy->contents_encryption_mode);
-               return -EINVAL;
-       }
-       if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
-               printk(KERN_WARNING
-                      "%s: Invalid filenames encryption mode %d\n", __func__,
-                       policy->filenames_encryption_mode);
+                      "%s: Invalid encryption modes (contents %d, filenames %d)\n",
+                      __func__, policy->contents_encryption_mode,
+                      policy->filenames_encryption_mode);
                return -EINVAL;
        }
        if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
index 6edacb8..40992b6 100644 (file)
@@ -589,6 +589,8 @@ enum {
 #define EXT4_ENCRYPTION_MODE_AES_256_GCM       2
 #define EXT4_ENCRYPTION_MODE_AES_256_CBC       3
 #define EXT4_ENCRYPTION_MODE_AES_256_CTS       4
+#define EXT4_ENCRYPTION_MODE_SPECK128_256_XTS  7
+#define EXT4_ENCRYPTION_MODE_SPECK128_256_CTS  8
 #define EXT4_ENCRYPTION_MODE_AES_256_HEH       126
 
 #include "ext4_crypto.h"
@@ -2259,7 +2261,7 @@ int ext4_get_policy(struct inode *inode,
 
 /* crypto.c */
 extern struct kmem_cache *ext4_crypt_info_cachep;
-bool ext4_valid_contents_enc_mode(uint32_t mode);
+bool ext4_valid_enc_modes(uint32_t contents_mode, uint32_t filenames_mode);
 uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size);
 extern struct workqueue_struct *ext4_read_workqueue;
 struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
@@ -2290,7 +2292,6 @@ static inline int ext4_sb_has_crypto(struct super_block *sb)
 #endif
 
 /* crypto_fname.c */
-bool ext4_valid_filenames_enc_mode(uint32_t mode);
 u32 ext4_fname_crypto_round_up(u32 size, u32 blksize);
 unsigned ext4_fname_encrypted_size(struct inode *inode, u32 ilen);
 int ext4_fname_crypto_alloc_buffer(struct inode *inode,
index e52637d..f7ba3be 100644 (file)
@@ -124,6 +124,10 @@ static inline int ext4_encryption_key_size(int mode)
                return EXT4_AES_256_CTS_KEY_SIZE;
        case EXT4_ENCRYPTION_MODE_AES_256_HEH:
                return EXT4_AES_256_HEH_KEY_SIZE;
+       case EXT4_ENCRYPTION_MODE_SPECK128_256_XTS:
+               return 64;
+       case EXT4_ENCRYPTION_MODE_SPECK128_256_CTS:
+               return 32;
        default:
                BUG();
        }
index 60d2749..d122ea5 100644 (file)
@@ -193,6 +193,8 @@ struct inodes_stat_t {
 #define FS_ENCRYPTION_MODE_AES_256_CTS         4
 #define FS_ENCRYPTION_MODE_AES_128_CBC         5
 #define FS_ENCRYPTION_MODE_AES_128_CTS         6
+#define FS_ENCRYPTION_MODE_SPECK128_256_XTS    7
+#define FS_ENCRYPTION_MODE_SPECK128_256_CTS    8
 
 
 struct fscrypt_policy {