[PATCH] fscrypt: add support for ChaCha20 contents encryption

Ard Biesheuvel ard.biesheuvel at linaro.org
Fri Dec 8 01:11:57 PST 2017


On 8 December 2017 at 09:11, Ard Biesheuvel <ard.biesheuvel at linaro.org> wrote:
> Hi Eric,
>
> On 8 December 2017 at 01:38, Eric Biggers <ebiggers3 at gmail.com> wrote:
>> From: Eric Biggers <ebiggers at google.com>
>>
>> fscrypt currently only supports AES encryption.  However, many low-end
>> mobile devices still use older CPUs such as ARMv7, which do not support
>> the AES instructions (the ARMv8 Cryptography Extensions).  This results
>> in very poor AES performance, even if the NEON bit-sliced implementation
>> is used.  Roughly 20-40 MB/s is a typical number, in comparison to
>> 300-800 MB/s on CPUs that support the AES instructions.  Switching from
>> AES-256 to AES-128 only helps by about 30%.
>>
>> The result is that vendors don't enable encryption on these devices,
>> leaving users unprotected.
>>
>> A performance difference of similar magnitude can also be observed on
>> x86, between CPUs with and without the AES-NI instruction set.
>>
>> This patch provides an alternative to AES by updating fscrypt to support
>> the ChaCha20 stream cipher (RFC7539) for contents encryption.  ChaCha20
>> was designed to have a large security margin, to be efficient on
>> general-purpose CPUs without dedicated instructions, and to be
>> vectorizable.  It is already supported by the Linux crypto API,
>> including a vectorized implementation for ARM using NEON instructions,
>> and vectorized implementations for x86 using SSSE3 or AVX2 instructions.
>>
>> On 32-bit ARM processors with NEON support, ChaCha20 is about 3.2 times
>> faster than AES-128-XTS (chacha20-neon vs. xts-aes-neonbs).  Without
>> NEON support, ChaCha20 is about 1.5 times as fast (chacha20-generic vs.
>> xts(aes-asm)).  The improvement over AES-256-XTS is even greater.
>>
>> Note that stream ciphers are not an ideal choice for disk encryption,
>> since each data block has to be encrypted with the same IV each time it
>> is overwritten.  Consequently, an adversary who observes the ciphertext
>> both before and after a write can trivially recover the keystream if
>> they can guess one of the plaintexts.  Moreover, an adversary who can
>> write to the ciphertext can flip arbitrary bits in the plaintext, merely
>> by flipping the corresponding bits in the ciphertext.  A block cipher
>> operating in the XTS or CBC-ESSIV mode provides some protection against
>> these types of attacks -- albeit not full protection, which would at
>> minimum require the use an authenticated encryption mode with nonces.
>>
>> Unfortunately, we are unaware of any block cipher which performs as well
>> as ChaCha20, has a similar or greater security margin, and has been
>> subject to as much public security analysis.  We do not consider Speck
>> to be a viable alternative at this time.
>>
>> Still, a stream cipher is sufficient to protect data confidentiality in
>> the event of a single point-in-time permanent offline compromise of the
>> disk, which currently is the primary threat model for fscrypt.  Thus,
>> when the alternative is quite literally *no encryption*, we might as
>> well use a stream cipher.
>>
>> We offer ChaCha20 rather than the reduced-round variants ChaCha8 or
>> ChaCha12 because ChaCha20 has a much higher security margin, and we are
>> primarily targeting CPUs where ChaCha20 is fast enough, in particular
>> CPUs that have vector instructions such as NEON or SSSE3.  Also, the
>> crypto API currently only supports ChaCha20.  Still, if ChaCha8 and/or
>> ChaCha12 support were to be added to the crypto API, it would be
>> straightforward to support them in fscrypt too.
>>
>> Currently, stream ciphers cannot be used for filenames encryption with
>> fscrypt because all filenames in a directory have to be encrypted with
>> the same IV.  Therefore, we offer ChaCha20 for contents encryption only.
>> Filenames encryption still must use AES-256-CTS-CBC.  This is acceptable
>> because filenames encryption is not as performance-critical as contents
>> encryption.
>>
>> Reviewed-by: Michael Halcrow <mhalcrow at google.com>
>> Signed-off-by: Eric Biggers <ebiggers at google.com>
>> ---
>>  Documentation/filesystems/fscrypt.rst | 43 +++++++++++++++++++---
>>  fs/crypto/Kconfig                     |  1 +
>>  fs/crypto/crypto.c                    | 69 ++++++++++++++++++++++++++++-------
>>  fs/crypto/keyinfo.c                   |  2 +
>>  include/linux/fscrypt.h               |  6 ++-
>>  include/uapi/linux/fs.h               |  1 +
>>  6 files changed, 102 insertions(+), 20 deletions(-)
>>
>> diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
>> index 776ddc655f79..927d3c88816b 100644
>> --- a/Documentation/filesystems/fscrypt.rst
>> +++ b/Documentation/filesystems/fscrypt.rst
>> @@ -184,6 +184,9 @@ replaced with HKDF or another more standard KDF in the future.
>>  Encryption modes and usage
>>  ==========================
>>
>> +Available modes
>> +---------------
>> +
>>  fscrypt allows one encryption mode to be specified for file contents
>>  and one encryption mode to be specified for filenames.  Different
>>  directory trees are permitted to use different encryption modes.
>> @@ -191,24 +194,52 @@ Currently, the following pairs of encryption modes are supported:
>>
>>  - AES-256-XTS for contents and AES-256-CTS-CBC for filenames
>>  - AES-128-CBC for contents and AES-128-CTS-CBC for filenames
>> +- ChaCha20 for contents and AES-256-CTS-CBC for filenames
>>
>>  It is strongly recommended to use AES-256-XTS for contents encryption.
>>  AES-128-CBC was added only for low-powered embedded devices with
>>  crypto accelerators such as CAAM or CESA that do not support XTS.
>>
>> +Similarly, ChaCha20 was only added for low-end devices that have
>> +neither a CPU with AES instructions, nor a hardware crypto
>> +accelerator.  Note that since ChaCha20 is a stream cipher, it is
>> +easily broken if an attacker can view encrypted data both before and
>> +after it is overwritten.  Thus, even moreso than the other modes,
>> +ChaCha20 can protect data confidentiality *only* in the event of a
>> +single point-in-time, permanent offline compromise of the storage.
>> +Also, ChaCha20 is supported only for contents encryption, not
>> +filenames encryption, because all filenames in a directory have to be
>> +encrypted with the same IV, which would be especially inappropriate
>> +for a stream cipher.
>> +
>>  New encryption modes can be added relatively easily, without changes
>>  to individual filesystems.  However, authenticated encryption (AE)
>>  modes are not currently supported because of the difficulty of dealing
>>  with ciphertext expansion.
>>
>> +Contents encryption
>> +-------------------
>> +
>>  For file contents, each filesystem block is encrypted independently.
>>  Currently, only the case where the filesystem block size is equal to
>> -the system's page size (usually 4096 bytes) is supported.  With the
>> -XTS mode of operation (recommended), the logical block number within
>> -the file is used as the IV.  With the CBC mode of operation (not
>> -recommended), ESSIV is used; specifically, the IV for CBC is the
>> -logical block number encrypted with AES-256, where the AES-256 key is
>> -the SHA-256 hash of the inode's data encryption key.
>> +the system's page size (usually 4096 bytes) is supported.
>> +
>> +With the XTS mode of operation, the logical block number within the
>> +file is used as the IV.
>> +
>> +With the CBC mode of operation, ESSIV is used.  Specifically, the IV
>> +is the file logical block number encrypted with AES-256, where the
>> +AES-256 key is the SHA-256 hash of the inode's data encryption key.
>> +
>> +With ChaCha20, the file logical block number is also used as the IV,
>> +but it is formatted differently to ensure that it is copied into the
>> +"nonce" portion of the ChaCha20 initial state (words 14-15) rather
>> +than the "block counter" portion (words 12-13).  This detail is
>> +critical, since otherwise different portions of the file would be
>> +encrypted with the same keystream.
>> +
>> +Filenames encryption
>> +--------------------
>>
>>  For filenames, the full filename is encrypted at once.  Because of the
>>  requirements to retain support for efficient directory lookups and
>> diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
>> index 02b7d91c9231..44f052e9d842 100644
>> --- a/fs/crypto/Kconfig
>> +++ b/fs/crypto/Kconfig
>> @@ -3,6 +3,7 @@ config FS_ENCRYPTION
>>         select CRYPTO
>>         select CRYPTO_AES
>>         select CRYPTO_CBC
>> +       select CRYPTO_CHACHA20
>>         select CRYPTO_ECB
>>         select CRYPTO_XTS
>>         select CRYPTO_CTS
>> diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
>> index 732a786cce9d..d5c95a18db59 100644
>> --- a/fs/crypto/crypto.c
>> +++ b/fs/crypto/crypto.c
>> @@ -126,15 +126,66 @@ struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
>>  }
>>  EXPORT_SYMBOL(fscrypt_get_ctx);
>>
>> +struct fscrypt_iv {
>> +       __le64 first_half;
>> +       __le64 second_half;
>> +};
>> +
>> +/*
>> + * Generate the IV for encrypting/decrypting the block at the given logical
>> + * block number within a file.
>> + */
>> +static void fscrypt_generate_iv(struct fscrypt_iv *iv, u64 lblk_num,
>> +                               const struct fscrypt_info *ci)
>> +{
>> +       BUILD_BUG_ON(sizeof(*iv) != FS_IV_SIZE);
>> +
>> +       if (ci->ci_data_mode == FS_ENCRYPTION_MODE_CHACHA20) {
>> +               /*
>> +                * ChaCha20 interprets its IV as a block counter followed by a
>> +                * nonce.  We *MUST NOT* use the file logical block number as
>> +                * the Chacha block counter because the ChaCha block counter
>> +                * counts 64-byte ChaCha blocks, which are much smaller than
>> +                * file blocks.  If we did, then portions of the keystream would
>> +                * be repeated, which would be catastrophic.
>> +                *
>
> OK, so you are saying that LBA n + 1 will share its keystream with LBA
> n but shift by 64 blocks, right? Yeah, that's terrible.
>

shift-ed by 64 *bytes*



More information about the linux-mtd mailing list