crypto: Speck support
v2 cover crypto: Speck support
Hello,
This series adds Speck support to the crypto API, including the Speck128 and Speck64 variants. Speck is a lightweight block cipher that can be much faster than AES on processors that don't have AES instructions.
We are planning to offer Speck-XTS (probably Speck128/256-XTS) as an option for dm-crypt and fscrypt on Android, for low-end mobile devices with older CPUs such as ARMv7 which don't have the Cryptography Extensions. Currently, such devices are unencrypted because AES is not fast enough, even when the NEON bit-sliced implementation of AES is used. Other AES alternatives such as Twofish, Threefish, Camellia, CAST6, and Serpent aren't fast enough either; it seems that only a modern ARX cipher can provide sufficient performance on these devices.
This is a replacement for our original proposal
(https://patchwork.kernel.org/patch/10101451/) which was to offer ChaCha20 for these devices. However, the use of a stream cipher for disk/file encryption with no space to store nonces would have been much more insecure than we thought initially, given that it would be used on top of flash storage as well as potentially on top of F2FS, neither of which is guaranteed to overwrite data in-place.
Speck has been somewhat controversial due to its origin. Nevertheless, it has a straightforward design (it's an ARX cipher), and it appears to be the leading software-optimized lightweight block cipher currently, with the most cryptanalysis. It's also easy to implement without side channels, unlike AES. Moreover, we only intend Speck to be used when the status quo is no encryption, due to AES not being fast enough.
We've also considered a novel length-preserving encryption mode based on ChaCha20 and Poly1305. While theoretically attractive, such a mode would be a brand new crypto construction and would be more complicated and difficult to implement efficiently in comparison to Speck-XTS.
Thus, patch 1 adds a generic implementation of Speck, and the following patches add a 32-bit ARM NEON implementation of Speck-XTS. The NEON-accelerated implementation is much faster than the generic implementation and therefore is the implementation that would primarily be used in practice on the devices we are targeting.
There is no AArch64 implementation added, since such CPUs are likely to have the Cryptography Extensions, allowing the use of AES.
Changed since v1:
- Use the word order recommended by the Speck authors. All test vectors were updated.
Eric Biggers (5):
crypto: add support for the Speck block cipher
crypto: speck - export common helpers
crypto: arm/speck - add NEON-accelerated implementation of Speck-XTS
crypto: speck - add test vectors for Speck128-XTS
crypto: speck - add test vectors for Speck64-XTS
arch/arm/crypto/Kconfig | 6 + arch/arm/crypto/Makefile | 2 + arch/arm/crypto/speck-neon-core.S | 432 +++++++++++ arch/arm/crypto/speck-neon-glue.c | 290 ++++++++ crypto/Kconfig | 14 + crypto/Makefile | 1 + crypto/speck.c | 307 ++++++++ crypto/testmgr.c | 36 + crypto/testmgr.h | 1486 +++++++++++++++++++++++++++++++++++++ include/crypto/speck.h | 62 ++ 10 files changed, 2636 insertions(+) create mode 100644 arch/arm/crypto/speck-neon-core.S create mode 100644 arch/arm/crypto/speck-neon-glue.c create mode 100644 crypto/speck.c create mode 100644 include/crypto/speck.h
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
PATCH v2 1/5 crypto: add support for the Speck block cipher
Add a generic implementation of Speck, including the Speck128 and Speck64 variants. Speck is a lightweight block cipher that can be much faster than AES on processors that don't have AES instructions.
We are planning to offer Speck-XTS (probably Speck128/256-XTS) as an option for dm-crypt and fscrypt on Android, for low-end mobile devices with older CPUs such as ARMv7 which don't have the Cryptography Extensions. Currently, such devices are unencrypted because AES is not fast enough, even when the NEON bit-sliced implementation of AES is used. Other AES alternatives such as Twofish, Threefish, Camellia, CAST6, and Serpent aren't fast enough either; it seems that only a modern ARX cipher can provide sufficient performance on these devices.
This is a replacement for our original proposal
(https://patchwork.kernel.org/patch/10101451/) which was to offer ChaCha20 for these devices. However, the use of a stream cipher for disk/file encryption with no space to store nonces would have been much more insecure than we thought initially, given that it would be used on top of flash storage as well as potentially on top of F2FS, neither of which is guaranteed to overwrite data in-place.
Speck has been somewhat controversial due to its origin. Nevertheless, it has a straightforward design (it's an ARX cipher), and it appears to be the leading software-optimized lightweight block cipher currently, with the most cryptanalysis. It's also easy to implement without side channels, unlike AES. Moreover, we only intend Speck to be used when the status quo is no encryption, due to AES not being fast enough.
We've also considered a novel length-preserving encryption mode based on ChaCha20 and Poly1305. While theoretically attractive, such a mode would be a brand new crypto construction and would be more complicated and difficult to implement efficiently in comparison to Speck-XTS.
There is confusion about the byte and word orders of Speck, since the original paper doesn't specify them. But we have implemented it using the orders the authors recommended in a correspondence with them. The test vectors are taken from the original paper but were mapped to byte arrays using the recommended byte and word orders.
--- crypto/Kconfig | 14 +++ crypto/Makefile | 1 + crypto/speck.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/testmgr.c | 18 ++++ crypto/testmgr.h | 128 ++++++++++++++++++++++++ 5 files changed, 460 insertions(+) create mode 100644 crypto/speck.c
crypto/Kconfig +14 -0
@@ -1508,6 +1508,20 @@ config CRYPTO_SERPENT_AVX2_X86_64 See also: <http://www.cl.cam.ac.uk/~rja14/serpent.html> +config CRYPTO_SPECK + tristate "Speck cipher algorithm" + select CRYPTO_ALGAPI + help + Speck is a lightweight block cipher that is tuned for optimal + performance in software (rather than hardware). + + Speck may not be as secure as AES, and should only be used on systems + where AES is not fast enough. + + See also: <https://eprint.iacr.org/2013/404.pdf> + + If unsure, say N. + config CRYPTO_TEA tristate "TEA, XTEA and XETA cipher algorithms" select CRYPTO_ALGAPI
crypto/Makefile +1 -0
@@ -110,6 +110,7 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o obj-$(CONFIG_CRYPTO_SEED) += seed.o +obj-$(CONFIG_CRYPTO_SPECK) += speck.o obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
crypto/speck.c new file +299 -0
299 lines not on this page · raw message
crypto/testmgr.c +18 -0
@@ -3000,6 +3000,24 @@ static const struct alg_test_desc alg_test_descs[] = { .dec = __VECS(serpent_dec_tv_template) } } + }, { + .alg = "ecb(speck128)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = __VECS(speck128_enc_tv_template), + .dec = __VECS(speck128_dec_tv_template) + } + } + }, { + .alg = "ecb(speck64)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = __VECS(speck64_enc_tv_template), + .dec = __VECS(speck64_dec_tv_template) + } + } }, { .alg = "ecb(tea)", .test = alg_test_skcipher,
crypto/testmgr.h +128 -0
134 lines not on this page · raw message
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
PATCH v2 2/5 crypto: speck - export common helpers
In reply to Eric BiggersExport the Speck constants and transform context and the ->setkey(), ->encrypt(), and ->decrypt() functions so that they can be reused by the ARM NEON implementation of Speck-XTS. The generic key expansion code will be reused because it is not performance-critical and is not vectorizable, while the generic encryption and decryption functions are needed as fallbacks and for the XTS tweak encryption.
--- crypto/speck.c | 90 +++++++++++++++++++++++++++----------------------- include/crypto/speck.h | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 41 deletions(-) create mode 100644 include/crypto/speck.h
crypto/speck.c +49 -41
@@ -24,6 +24,7 @@*/ #include <asm/unaligned.h> +#include <crypto/speck.h> #include <linux/bitops.h> #include <linux/crypto.h> #include <linux/init.h>
@@ -31,22 +32,6 @@/* Speck128 */ -#define SPECK128_BLOCK_SIZE 16 - -#define SPECK128_128_KEY_SIZE 16 -#define SPECK128_128_NROUNDS 32 - -#define SPECK128_192_KEY_SIZE 24 -#define SPECK128_192_NROUNDS 33 - -#define SPECK128_256_KEY_SIZE 32 -#define SPECK128_256_NROUNDS 34 - -struct speck128_tfm_ctx { -u64 round_keys[SPECK128_256_NROUNDS ]; -int nrounds; -}; - static __always_inline void speck128_round(u64 *x, u64 *y, u64 k) { *x =ror64 (*x,8 );
@@ -65,9 +50,9 @@ static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k) *x =rol64 (*x,8 ); } -static void speck128_encrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +void crypto_speck128_encrypt (const struct speck128_tfm_ctx *ctx, +u8 *out,const u8 *in) { -const struct speck128_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u64 y =get_unaligned_le64 (in);u64 x =get_unaligned_le64 (in +8 );int i;
@@ -78,10 +63,16 @@ static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)put_unaligned_le64 (y, out);put_unaligned_le64 (x, out +8 ); } +EXPORT_SYMBOL_GPL (crypto_speck128_encrypt); -static void speck128_decrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +static void speck128_encrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +crypto_speck128_encrypt (crypto_tfm_ctx (tfm), out, in); +} + +void crypto_speck128_decrypt (const struct speck128_tfm_ctx *ctx, +u8 *out,const u8 *in) { -const struct speck128_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u64 y =get_unaligned_le64 (in);u64 x =get_unaligned_le64 (in +8 );int i;
@@ -92,11 +83,16 @@ static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)put_unaligned_le64 (y, out);put_unaligned_le64 (x, out +8 ); } +EXPORT_SYMBOL_GPL (crypto_speck128_decrypt); -static int speck128_setkey (struct crypto_tfm *tfm,const u8 *key, +static void speck128_decrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +crypto_speck128_decrypt (crypto_tfm_ctx (tfm), out, in); +} + +int crypto_speck128_setkey (struct speck128_tfm_ctx *ctx,const u8 *key,unsigned int keylen) { -struct speck128_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u64 l[3 ];u64 k;int i;
@@ -138,21 +134,15 @@ static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key,return 0 ; } +EXPORT_SYMBOL_GPL (crypto_speck128_setkey); -/* Speck64 */ - -#define SPECK64_BLOCK_SIZE 8 - -#define SPECK64_96_KEY_SIZE 12 -#define SPECK64_96_NROUNDS 26 - -#define SPECK64_128_KEY_SIZE 16 -#define SPECK64_128_NROUNDS 27 +static int speck128_setkey (struct crypto_tfm *tfm,const u8 *key, +unsigned int keylen) +{ +return crypto_speck128_setkey (crypto_tfm_ctx (tfm), key, keylen); +} -struct speck64_tfm_ctx { -u32 round_keys[SPECK64_128_NROUNDS ]; -int nrounds; -}; +/* Speck64 */ static __always_inline void speck64_round(u32 *x, u32 *y, u32 k) {
@@ -172,9 +162,9 @@ static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k) *x =rol32 (*x,8 ); } -static void speck64_encrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +void crypto_speck64_encrypt (const struct speck64_tfm_ctx *ctx, +u8 *out,const u8 *in) { -const struct speck64_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u32 y =get_unaligned_le32 (in);u32 x =get_unaligned_le32 (in +4 );int i;
@@ -185,10 +175,16 @@ static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)put_unaligned_le32 (y, out);put_unaligned_le32 (x, out +4 ); } +EXPORT_SYMBOL_GPL (crypto_speck64_encrypt); -static void speck64_decrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +static void speck64_encrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +crypto_speck64_encrypt (crypto_tfm_ctx (tfm), out, in); +} + +void crypto_speck64_decrypt (const struct speck64_tfm_ctx *ctx, +u8 *out,const u8 *in) { -const struct speck64_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u32 y =get_unaligned_le32 (in);u32 x =get_unaligned_le32 (in +4 );int i;
@@ -199,11 +195,16 @@ static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)put_unaligned_le32 (y, out);put_unaligned_le32 (x, out +4 ); } +EXPORT_SYMBOL_GPL (crypto_speck64_decrypt); -static int speck64_setkey (struct crypto_tfm *tfm,const u8 *key, +static void speck64_decrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +crypto_speck64_decrypt (crypto_tfm_ctx (tfm), out, in); +} + +int crypto_speck64_setkey (struct speck64_tfm_ctx *ctx,const u8 *key,unsigned int keylen) { -struct speck64_tfm_ctx *ctx =crypto_tfm_ctx (tfm);u32 l[3 ];u32 k;int i;
@@ -236,6 +237,13 @@ static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key,return 0 ; } +EXPORT_SYMBOL_GPL (crypto_speck64_setkey); + +static int speck64_setkey (struct crypto_tfm *tfm,const u8 *key, +unsigned int keylen) +{ +return crypto_speck64_setkey (crypto_tfm_ctx (tfm), key, keylen); +}/* Algorithm definitions */
include/crypto/speck.h new file +62 -0
62 lines not on this page · raw message
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
PATCH v2 3/5 crypto: arm/speck - add NEON-accelerated implementation of Speck-XTS
In reply to Eric BiggersAdd an ARM NEON-accelerated implementation of Speck-XTS. It operates on 128-byte chunks at a time, i.e. 8 blocks for Speck128 or 16 blocks for Speck64. Each 128-byte chunk goes through XTS preprocessing, then is encrypted/decrypted (doing one cipher round for all the blocks, then the next round, etc.), then goes through XTS postprocessing.
The performance depends on the processor but can be about 3 times faster than the generic code. For example, on an ARMv7 processor we observe the following performance with Speck128/256-XTS:
xts-speck128-neon: Encryption 107.9 MB/s, Decryption 108.1 MB/s
xts(speck128-generic): Encryption 32.1 MB/s, Decryption 36.6 MB/sIn comparison to AES-256-XTS without the Cryptography Extensions:
xts-aes-neonbs: Encryption 41.2 MB/s, Decryption 36.7 MB/s
xts(aes-asm): Encryption 31.7 MB/s, Decryption 30.8 MB/s
xts(aes-generic): Encryption 21.2 MB/s, Decryption 20.9 MB/sSpeck64/128-XTS is even faster:
xts-speck64-neon: Encryption 138.6 MB/s, Decryption 139.1 MB/s
Note that as with the generic code, only the Speck128 and Speck64 variants are supported. Also, for now only the XTS mode of operation is supported, to target the disk and file encryption use cases. The NEON code also only handles the portion of the data that is evenly divisible into 128-byte chunks, with any remainder handled by a C fallback. Of course, other modes of operation could be added later if needed, and/or the NEON code could be updated to handle other buffer sizes.
The XTS specification is only defined for AES which has a 128-bit block size, so for the GF(2^64) math needed for Speck64-XTS we use the reducing polynomial 'x^64 + x^4 + x^3 + x + 1' given by the original XEX paper. Of course, when possible users should use Speck128-XTS, but even that may be too slow on some processors; Speck64-XTS can be faster.
--- arch/arm/crypto/Kconfig | 6 + arch/arm/crypto/Makefile | 2 + arch/arm/crypto/speck-neon-core.S | 432 ++++++++++++++++++++++++++++++++++++++ arch/arm/crypto/speck-neon-glue.c | 290 +++++++++++++++++++++++++ 4 files changed, 730 insertions(+) create mode 100644 arch/arm/crypto/speck-neon-core.S create mode 100644 arch/arm/crypto/speck-neon-glue.c
arch/arm/crypto/Kconfig +6 -0
@@ -121,4 +121,10 @@ config CRYPTO_CHACHA20_NEON select CRYPTO_BLKCIPHER select CRYPTO_CHACHA20 +config CRYPTO_SPECK_NEON + tristate "NEON accelerated Speck cipher algorithms" + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_SPECK + endif
arch/arm/crypto/Makefile +2 -0
@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o +obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
@@ -53,6 +54,7 @@ ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o +speck-neon-y := speck-neon-core.o speck-neon-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@)
arch/arm/crypto/speck-neon-core.S new file +432 -0
432 lines not on this page · raw message
arch/arm/crypto/speck-neon-glue.c new file +290 -0
290 lines not on this page · raw message
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
PATCH v2 3/5 crypto: arm/speck - add NEON-accelerated implementation of Speck-XTS
Hi Eric,
Quoted 31 lines · Eric Biggers
Add an ARM NEON-accelerated implementation of Speck-XTS. It operates on 128-byte chunks at a time, i.e. 8 blocks for Speck128 or 16 blocks for Speck64. Each 128-byte chunk goes through XTS preprocessing, then is encrypted/decrypted (doing one cipher round for all the blocks, then the next round, etc.), then goes through XTS postprocessing.
The performance depends on the processor but can be about 3 times faster than the generic code. For example, on an ARMv7 processor we observe the following performance with Speck128/256-XTS:
xts-speck128-neon: Encryption 107.9 MB/s, Decryption 108.1 MB/s xts(speck128-generic): Encryption 32.1 MB/s, Decryption 36.6 MB/sIn comparison to AES-256-XTS without the Cryptography Extensions:
xts-aes-neonbs: Encryption 41.2 MB/s, Decryption 36.7 MB/s xts(aes-asm): Encryption 31.7 MB/s, Decryption 30.8 MB/s xts(aes-generic): Encryption 21.2 MB/s, Decryption 20.9 MB/sSpeck64/128-XTS is even faster:
xts-speck64-neon: Encryption 138.6 MB/s, Decryption 139.1 MB/sNote that as with the generic code, only the Speck128 and Speck64 variants are supported. Also, for now only the XTS mode of operation is supported, to target the disk and file encryption use cases. The NEON code also only handles the portion of the data that is evenly divisible into 128-byte chunks, with any remainder handled by a C fallback. Of course, other modes of operation could be added later if needed, and/or the NEON code could be updated to handle other buffer sizes.
Quoted 6 lines
The XTS specification is only defined for AES which has a 128-bit block size, so for the GF(2^64) math needed for Speck64-XTS we use the reducing polynomial 'x^64 + x^4 + x^3 + x + 1' given by the original XEX paper. Of course, when possible users should use Speck128-XTS, but even that may be too slow on some processors; Speck64-XTS can be faster.
I think this is excellent work. Speck seems an appropriate solution to this problem, and I'm glad we are not ending up with a stream cipher for block encryption.
Also, I think an arm64 port would be nice. I may take a stab at this if nobody else beats me to it.
I did run into an issue with this code though: On big-endian, I get
[ 0.272381] alg: skcipher: Test 1 failed (invalid result) on encryption for xts-speck64-neon [ 0.276151] 00000000: 84 af 54 07 19 d4 7c a6 9c 8a ac f6 c2 14 04 d8 [ 0.278541] 00000010: 7f 18 6c 43 56 ed 0b b3 92 21 a2 d9 17 59 e4 3b
so there may be a byte order corner case you missed in the rewrite (or the issue existed before, as I did not test your v1)
Signature · 1 line
Ard.
Quoted 782 lines
Signed-off-by Eric Biggers <[email protected]>--- arch/arm/crypto/Kconfig | 6 + arch/arm/crypto/Makefile | 2 + arch/arm/crypto/speck-neon-core.S | 432 ++++++++++++++++++++++++++++++++++++++ arch/arm/crypto/speck-neon-glue.c | 290 +++++++++++++++++++++++++ 4 files changed, 730 insertions(+) create mode 100644 arch/arm/crypto/speck-neon-core.S create mode 100644 arch/arm/crypto/speck-neon-glue.carch/arm/crypto/Kconfig +6
-0@@ -121,4 +121,10 @@ config CRYPTO_CHACHA20_NEON select CRYPTO_BLKCIPHER select CRYPTO_CHACHA20 +config CRYPTO_SPECK_NEON + tristate "NEON accelerated Speck cipher algorithms" + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_SPECK + endifarch/arm/crypto/Makefile +2
-0@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o +obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o@@ -53,6 +54,7 @@ ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o +speck-neon-y := speck-neon-core.o speck-neon-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@)arch/arm/crypto/speck-neon-core.S new file +432
-0@@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * + * Copyright (c) 2018 Google, Inc + * + * Author: Eric Biggers <[email protected]> + */ + +#include <linux/linkage.h> + + .text + .fpu neon + + // arguments + ROUND_KEYS .req r0 // const {u64,u32} *round_keys + NROUNDS .req r1 // int nrounds + DST .req r2 // void *dst + SRC .req r3 // const void *src + NBYTES .req r4 // unsigned int nbytes + TWEAK .req r5 // void *tweak + + // registers which hold the data being encrypted/decrypted + X0 .req q0 + X0_L .req d0 + X0_H .req d1 + Y0 .req q1 + Y0_H .req d3 + X1 .req q2 + X1_L .req d4 + X1_H .req d5 + Y1 .req q3 + Y1_H .req d7 + X2 .req q4 + X2_L .req d8 + X2_H .req d9 + Y2 .req q5 + Y2_H .req d11 + X3 .req q6 + X3_L .req d12 + X3_H .req d13 + Y3 .req q7 + Y3_H .req d15 + + // the round key, duplicated in all lanes + ROUND_KEY .req q8 + ROUND_KEY_L .req d16 + ROUND_KEY_H .req d17 + + // index vector for vtbl-based 8-bit rotates + ROTATE_TABLE .req d18 + + // multiplication table for updating XTS tweaks + GF128MUL_TABLE .req d19 + GF64MUL_TABLE .req d19 + + // current XTS tweak value(s) + TWEAKV .req q10 + TWEAKV_L .req d20 + TWEAKV_H .req d21 + + TMP0 .req q12 + TMP0_L .req d24 + TMP0_H .req d25 + TMP1 .req q13 + TMP2 .req q14 + TMP3 .req q15 + + .align 4 +.Lror64_8_table: + .byte 1, 2, 3, 4, 5, 6, 7, 0 +.Lror32_8_table: + .byte 1, 2, 3, 0, 5, 6, 7, 4 +.Lrol64_8_table: + .byte 7, 0, 1, 2, 3, 4, 5, 6 +.Lrol32_8_table: + .byte 3, 0, 1, 2, 7, 4, 5, 6 +.Lgf128mul_table: + .byte 0, 0x87 + .fill 14 +.Lgf64mul_table: + .byte 0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b + .fill 12 + +/* + * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time + * + * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for + * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes + * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. + * + * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because + * the vtbl approach is faster on some processors and the same speed on others. + */ +.macro _speck_round_128bytes n + + // x = ror(x, 8) + vtbl.8 X0_L, {X0_L}, ROTATE_TABLE + vtbl.8 X0_H, {X0_H}, ROTATE_TABLE + vtbl.8 X1_L, {X1_L}, ROTATE_TABLE + vtbl.8 X1_H, {X1_H}, ROTATE_TABLE + vtbl.8 X2_L, {X2_L}, ROTATE_TABLE + vtbl.8 X2_H, {X2_H}, ROTATE_TABLE + vtbl.8 X3_L, {X3_L}, ROTATE_TABLE + vtbl.8 X3_H, {X3_H}, ROTATE_TABLE + + // x += y + vadd.u\n X0, Y0 + vadd.u\n X1, Y1 + vadd.u\n X2, Y2 + vadd.u\n X3, Y3 + + // x ^= k + veor X0, ROUND_KEY + veor X1, ROUND_KEY + veor X2, ROUND_KEY + veor X3, ROUND_KEY + + // y = rol(y, 3) + vshl.u\n TMP0, Y0, #3 + vshl.u\n TMP1, Y1, #3 + vshl.u\n TMP2, Y2, #3 + vshl.u\n TMP3, Y3, #3 + vsri.u\n TMP0, Y0, #(\n - 3) + vsri.u\n TMP1, Y1, #(\n - 3) + vsri.u\n TMP2, Y2, #(\n - 3) + vsri.u\n TMP3, Y3, #(\n - 3) + + // y ^= x + veor Y0, TMP0, X0 + veor Y1, TMP1, X1 + veor Y2, TMP2, X2 + veor Y3, TMP3, X3 +.endm + +/* + * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time + * + * This is the inverse of _speck_round_128bytes(). + */ +.macro _speck_unround_128bytes n + + // y ^= x + veor TMP0, Y0, X0 + veor TMP1, Y1, X1 + veor TMP2, Y2, X2 + veor TMP3, Y3, X3 + + // y = ror(y, 3) + vshr.u\n Y0, TMP0, #3 + vshr.u\n Y1, TMP1, #3 + vshr.u\n Y2, TMP2, #3 + vshr.u\n Y3, TMP3, #3 + vsli.u\n Y0, TMP0, #(\n - 3) + vsli.u\n Y1, TMP1, #(\n - 3) + vsli.u\n Y2, TMP2, #(\n - 3) + vsli.u\n Y3, TMP3, #(\n - 3) + + // x ^= k + veor X0, ROUND_KEY + veor X1, ROUND_KEY + veor X2, ROUND_KEY + veor X3, ROUND_KEY + + // x -= y + vsub.u\n X0, Y0 + vsub.u\n X1, Y1 + vsub.u\n X2, Y2 + vsub.u\n X3, Y3 + + // x = rol(x, 8); + vtbl.8 X0_L, {X0_L}, ROTATE_TABLE + vtbl.8 X0_H, {X0_H}, ROTATE_TABLE + vtbl.8 X1_L, {X1_L}, ROTATE_TABLE + vtbl.8 X1_H, {X1_H}, ROTATE_TABLE + vtbl.8 X2_L, {X2_L}, ROTATE_TABLE + vtbl.8 X2_H, {X2_H}, ROTATE_TABLE + vtbl.8 X3_L, {X3_L}, ROTATE_TABLE + vtbl.8 X3_H, {X3_H}, ROTATE_TABLE +.endm + +.macro _xts128_precrypt_one dst_reg, tweak_buf, tmp + + // Load the next source block + vld1.8 {\dst_reg}, [SRC]! + + // Save the current tweak in the tweak buffer + vst1.8 {TWEAKV}, [\tweak_buf:128]! + + // XOR the next source block with the current tweak + veor \dst_reg, TWEAKV + + /* + * Calculate the next tweak by multiplying the current one by x, + * modulo p(x) = x^128 + x^7 + x^2 + x + 1. + */ + vshr.u64 \tmp, TWEAKV, #63 + vshl.u64 TWEAKV, #1 + veor TWEAKV_H, \tmp\()_L + vtbl.8 \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H + veor TWEAKV_L, \tmp\()_H +.endm + +.macro _xts64_precrypt_two dst_reg, tweak_buf, tmp + + // Load the next two source blocks + vld1.8 {\dst_reg}, [SRC]! + + // Save the current two tweaks in the tweak buffer + vst1.8 {TWEAKV}, [\tweak_buf:128]! + + // XOR the next two source blocks with the current two tweaks + veor \dst_reg, TWEAKV + + /* + * Calculate the next two tweaks by multiplying the current ones by x^2, + * modulo p(x) = x^64 + x^4 + x^3 + x + 1. + */ + vshr.u64 \tmp, TWEAKV, #62 + vshl.u64 TWEAKV, #2 + vtbl.8 \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L + vtbl.8 \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H + veor TWEAKV, \tmp +.endm + +/* + * _speck_xts_crypt() - Speck-XTS encryption/decryption + * + * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer + * using Speck-XTS, specifically the variant with a block size of '2n' and round + * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and + * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a + * nonzero multiple of 128. + */ +.macro _speck_xts_crypt n, decrypting + push {r4-r7} + mov r7, sp + + /* + * The first four parameters were passed in registers r0-r3. Load the + * additional parameters, which were passed on the stack. + */ + ldr NBYTES, [sp, #16] + ldr TWEAK, [sp, #20] + + /* + * If decrypting, modify the ROUND_KEYS parameter to point to the last + * round key rather than the first, since for decryption the round keys + * are used in reverse order. + */ +.if \decrypting +.if \n == 64 + add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3 + sub ROUND_KEYS, #8 +.else + add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2 + sub ROUND_KEYS, #4 +.endif +.endif + + // Load the index vector for vtbl-based 8-bit rotates +.if \decrypting + ldr r12, =.Lrol\n\()_8_table +.else + ldr r12, =.Lror\n\()_8_table +.endif + vld1.8 {ROTATE_TABLE}, [r12:64] + + // One-time XTS preparation + + /* + * Allocate stack space to store 128 bytes worth of tweaks. For + * performance, this space is aligned to a 16-byte boundary so that we + * can use the load/store instructions that declare 16-byte alignment. + */ + sub sp, #128 + bic sp, #0xf + +.if \n == 64 + // Load first tweak + vld1.8 {TWEAKV}, [TWEAK] + + // Load GF(2^128) multiplication table + ldr r12, =.Lgf128mul_table + vld1.8 {GF128MUL_TABLE}, [r12:64] +.else + // Load first tweak + vld1.8 {TWEAKV_L}, [TWEAK] + + // Load GF(2^64) multiplication table + ldr r12, =.Lgf64mul_table + vld1.8 {GF64MUL_TABLE}, [r12:64] + + // Calculate second tweak, packing it together with the first + vshr.u64 TMP0_L, TWEAKV_L, #63 + vtbl.u8 TMP0_L, {GF64MUL_TABLE}, TMP0_L + vshl.u64 TWEAKV_H, TWEAKV_L, #1 + veor TWEAKV_H, TMP0_L +.endif + +.Lnext_128bytes_\@: + + /* + * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak + * values, and save the tweaks on the stack for later. Then + * de-interleave the 'x' and 'y' elements of each block, i.e. make it so + * that the X[0-3] registers contain only the second halves of blocks, + * and the Y[0-3] registers contain only the first halves of blocks. + * (Speck uses the order (y, x) rather than the more intuitive (x, y).) + */ + mov r12, sp +.if \n == 64 + _xts128_precrypt_one X0, r12, TMP0 + _xts128_precrypt_one Y0, r12, TMP0 + _xts128_precrypt_one X1, r12, TMP0 + _xts128_precrypt_one Y1, r12, TMP0 + _xts128_precrypt_one X2, r12, TMP0 + _xts128_precrypt_one Y2, r12, TMP0 + _xts128_precrypt_one X3, r12, TMP0 + _xts128_precrypt_one Y3, r12, TMP0 + vswp X0_L, Y0_H + vswp X1_L, Y1_H + vswp X2_L, Y2_H + vswp X3_L, Y3_H +.else + _xts64_precrypt_two X0, r12, TMP0 + _xts64_precrypt_two Y0, r12, TMP0 + _xts64_precrypt_two X1, r12, TMP0 + _xts64_precrypt_two Y1, r12, TMP0 + _xts64_precrypt_two X2, r12, TMP0 + _xts64_precrypt_two Y2, r12, TMP0 + _xts64_precrypt_two X3, r12, TMP0 + _xts64_precrypt_two Y3, r12, TMP0 + vuzp.32 Y0, X0 + vuzp.32 Y1, X1 + vuzp.32 Y2, X2 + vuzp.32 Y3, X3 +.endif + + // Do the cipher rounds + + mov r12, ROUND_KEYS + mov r6, NROUNDS + +.Lnext_round_\@: +.if \decrypting +.if \n == 64 + vld1.64 ROUND_KEY_L, [r12] + sub r12, #8 + vmov ROUND_KEY_H, ROUND_KEY_L +.else + vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12] + sub r12, #4 +.endif + _speck_unround_128bytes \n +.else +.if \n == 64 + vld1.64 ROUND_KEY_L, [r12]! + vmov ROUND_KEY_H, ROUND_KEY_L +.else + vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]! +.endif + _speck_round_128bytes \n +.endif + subs r6, r6, #1 + bne .Lnext_round_\@ + + // Re-interleave the 'x' and 'y' elements of each block +.if \n == 64 + vswp X0_L, Y0_H + vswp X1_L, Y1_H + vswp X2_L, Y2_H + vswp X3_L, Y3_H +.else + vzip.32 Y0, X0 + vzip.32 Y1, X1 + vzip.32 Y2, X2 + vzip.32 Y3, X3 +.endif + + // XOR the encrypted/decrypted blocks with the tweaks we saved earlier + mov r12, sp + vld1.8 {TMP0, TMP1}, [r12:128]! + vld1.8 {TMP2, TMP3}, [r12:128]! + veor X0, TMP0 + veor Y0, TMP1 + veor X1, TMP2 + veor Y1, TMP3 + vld1.8 {TMP0, TMP1}, [r12:128]! + vld1.8 {TMP2, TMP3}, [r12:128]! + veor X2, TMP0 + veor Y2, TMP1 + veor X3, TMP2 + veor Y3, TMP3 + + // Store the ciphertext in the destination buffer + vst1.8 {X0, Y0}, [DST]! + vst1.8 {X1, Y1}, [DST]! + vst1.8 {X2, Y2}, [DST]! + vst1.8 {X3, Y3}, [DST]! + + // Continue if there are more 128-byte chunks remaining, else return + subs NBYTES, #128 + bne .Lnext_128bytes_\@ + + // Store the next tweak +.if \n == 64 + vst1.8 {TWEAKV}, [TWEAK] +.else + vst1.8 {TWEAKV_L}, [TWEAK] +.endif + + mov sp, r7 + pop {r4-r7} + bx lr +.endm + +ENTRY(speck128_xts_encrypt_neon) + _speck_xts_crypt n=64, decrypting=0 +ENDPROC(speck128_xts_encrypt_neon) + +ENTRY(speck128_xts_decrypt_neon) + _speck_xts_crypt n=64, decrypting=1 +ENDPROC(speck128_xts_decrypt_neon) + +ENTRY(speck64_xts_encrypt_neon) + _speck_xts_crypt n=32, decrypting=0 +ENDPROC(speck64_xts_encrypt_neon) + +ENTRY(speck64_xts_decrypt_neon) + _speck_xts_crypt n=32, decrypting=1 +ENDPROC(speck64_xts_decrypt_neon)arch/arm/crypto/speck-neon-glue.c new file +290
-1@@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* NEON-accelerated implementation of Speck128-XTS and Speck64-XTS +* +* Copyright (c) 2018 Google, Inc +* +* Note: the NIST recommendation for XTS only specifies a 128-bit block size, +* but a 64-bit version (needed for Speck64) is fairly straightforward; the math +* is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial +* x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004: +* "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes +* OCB and PMAC"), represented as 0x1B. +*/ + +#include <asm/hwcap.h> +#include <asm/neon.h> +#include <asm/simd.h> +#include <crypto/algapi.h> +#include <crypto/gf128mul.h> +#include <crypto/internal/skcipher.h> +#include <crypto/speck.h> +#include <crypto/xts.h> +#include <linux/kernel.h> +#include <linux/module.h> + +/* The assembly functions only handle multiples of 128 bytes */ +#define SPECK_NEON_CHUNK_SIZE 128 + +/* Speck128 */ + +struct speck128_xts_tfm_ctx { +struct speck128_tfm_ctx main_key; +struct speck128_tfm_ctx tweak_key; +}; + +asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, +void *dst,const void *src, +unsigned int nbytes,void *tweak); + +asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, +void *dst,const void *src, +unsigned int nbytes,void *tweak); + +typedef void (*speck128_crypt_one_t )(const struct speck128_tfm_ctx *, +u8 *,const u8 *); +typedef void (*speck128_xts_crypt_many_t )(const u64 *,int ,void *, +const void *,unsigned int ,void *); + + +static __always_inline int +__speck128_xts_crypt (struct skcipher_request *req, +speck128_crypt_one_t crypt_one, +speck128_xts_crypt_many_t crypt_many) +{ +struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req); +const struct speck128_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm); +struct skcipher_walk walk; +le128 tweak; +int err; + + err =skcipher_walk_virt (&walk, req, true); + +crypto_speck128_encrypt (&ctx->tweak_key, (u8 *)&tweak, walk.iv); + +while (walk.nbytes >0 ) { +unsigned int nbytes = walk.nbytes; +u8 *dst = walk.dst.virt.addr; +const u8 *src = walk.src.virt.addr; + +if (nbytes >=SPECK_NEON_CHUNK_SIZE &&may_use_simd ()) { +unsigned int count; + + count =round_down (nbytes,SPECK_NEON_CHUNK_SIZE ); +kernel_neon_begin (); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); +kernel_neon_end (); + dst += count; + src += count; + nbytes -= count; + } + +/* Handle any remainder with generic code */ +while (nbytes >=sizeof (le128)) { +le128_xor ((le128 *)dst, (const le128 *)src, &tweak); + (*crypt_one)(&ctx->main_key, dst, dst); +le128_xor ((le128 *)dst, (const le128 *)dst, &tweak); +gf128mul_x_ble (&tweak, &tweak); + + dst +=sizeof (le128); + src +=sizeof (le128); + nbytes -=sizeof (le128); + } + err =skcipher_walk_done (&walk, nbytes); + } + +return err; +} + +static int speck128_xts_encrypt (struct skcipher_request *req) +{ +return __speck128_xts_crypt (req, crypto_speck128_encrypt, + speck128_xts_encrypt_neon); + +} + +static int speck128_xts_decrypt (struct skcipher_request *req) +{ +return __speck128_xts_crypt (req, crypto_speck128_decrypt, + speck128_xts_decrypt_neon); +} + +static int speck128_xts_setkey (struct crypto_skcipher *tfm,const u8 *key, +unsigned int keylen) +{ +struct speck128_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm); +int err; + + err =xts_verify_key (tfm, key, keylen); +if (err) +return err; + + keylen /=2 ; + + err =crypto_speck128_setkey (&ctx->main_key, key, keylen); +if (err) +return err; + +return crypto_speck128_setkey (&ctx->tweak_key, key + keylen, keylen); +} + +/* Speck64 */ + +struct speck64_xts_tfm_ctx { +struct speck64_tfm_ctx main_key; +struct speck64_tfm_ctx tweak_key; +}; + +asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, +void *dst,const void *src, +unsigned int nbytes,void *tweak); + +asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, +void *dst,const void *src, +unsigned int nbytes,void *tweak); + +typedef void (*speck64_crypt_one_t )(const struct speck64_tfm_ctx *, +u8 *,const u8 *); +typedef void (*speck64_xts_crypt_many_t )(const u32 *,int ,void *, +const void *,unsigned int ,void *); + +static __always_inline int +__speck64_xts_crypt (struct skcipher_request *req,speck64_crypt_one_t crypt_one, +speck64_xts_crypt_many_t crypt_many) +{ +struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req); +const struct speck64_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm); +struct skcipher_walk walk; +u64 tweak; +int err; + + err =skcipher_walk_virt (&walk, req, true); + +crypto_speck64_encrypt (&ctx->tweak_key, (u8 *)&tweak, walk.iv); + +while (walk.nbytes >0 ) { +unsigned int nbytes = walk.nbytes; +u8 *dst = walk.dst.virt.addr; +const u8 *src = walk.src.virt.addr; + +if (nbytes >=SPECK_NEON_CHUNK_SIZE &&may_use_simd ()) { +unsigned int count; + + count =round_down (nbytes,SPECK_NEON_CHUNK_SIZE ); +kernel_neon_begin (); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); +kernel_neon_end (); + dst += count; + src += count; + nbytes -= count; + } + +/* Handle any remainder with generic code */ +while (nbytes >=sizeof (u64)) { + *(u64 *)dst = *(u64 *)src ^ tweak; + (*crypt_one)(&ctx->main_key, dst, dst); + *(u64 *)dst ^= tweak; + tweak = (tweak <<1 ) ^ + ((tweak & (1ULL <<63 )) ?0x1B :0 ); + + dst +=sizeof (u64); + src +=sizeof (u64); + nbytes -=sizeof (u64); + } + err =skcipher_walk_done (&walk, nbytes); + } + +return err; +} + +static int speck64_xts_encrypt (struct skcipher_request *req) +{ +return __speck64_xts_crypt (req, crypto_speck64_encrypt, + speck64_xts_encrypt_neon); +} + +static int speck64_xts_decrypt (struct skcipher_request *req) +{ +return __speck64_xts_crypt (req, crypto_speck64_decrypt, + speck64_xts_decrypt_neon); +} + +static int speck64_xts_setkey (struct crypto_skcipher *tfm,const u8 *key, +unsigned int keylen) +{ +struct speck64_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm); +int err; + + err =xts_verify_key (tfm, key, keylen); +if (err) +return err; + + keylen /=2 ; + + err =crypto_speck64_setkey (&ctx->main_key, key, keylen); +if (err) +return err; + +return crypto_speck64_setkey (&ctx->tweak_key, key + keylen, keylen); +} + +static struct skcipher_alg speck_algs[] = { + { + .base.cra_name ="xts(speck128)" , + .base.cra_driver_name ="xts-speck128-neon" , + .base.cra_priority =300 , + .base.cra_blocksize =SPECK128_BLOCK_SIZE , + .base.cra_ctxsize =sizeof (struct speck128_xts_tfm_ctx ), + .base.cra_alignmask =7 , + .base.cra_module =THIS_MODULE , + .min_keysize =2 *SPECK128_128_KEY_SIZE , + .max_keysize =2 *SPECK128_256_KEY_SIZE , + .ivsize =SPECK128_BLOCK_SIZE , + .walksize =SPECK_NEON_CHUNK_SIZE , + .setkey = speck128_xts_setkey, + .encrypt = speck128_xts_encrypt, + .decrypt = speck128_xts_decrypt, + }, { + .base.cra_name ="xts(speck64)" , + .base.cra_driver_name ="xts-speck64-neon" , + .base.cra_priority =300 , + .base.cra_blocksize =SPECK64_BLOCK_SIZE , + .base.cra_ctxsize =sizeof (struct speck64_xts_tfm_ctx ), + .base.cra_alignmask =7 , + .base.cra_module =THIS_MODULE , + .min_keysize =2 *SPECK64_96_KEY_SIZE , + .max_keysize =2 *SPECK64_128_KEY_SIZE , + .ivsize =SPECK64_BLOCK_SIZE , + .walksize =SPECK_NEON_CHUNK_SIZE , + .setkey = speck64_xts_setkey, + .encrypt = speck64_xts_encrypt, + .decrypt = speck64_xts_decrypt, + } +}; + +static int __init speck_neon_module_init (void ) +{ +if (!(elf_hwcap &HWCAP_NEON )) +return -ENODEV ; +return crypto_register_skciphers (speck_algs,ARRAY_SIZE (speck_algs)); +} + +static void __exit speck_neon_module_exit(void) +{ +crypto_unregister_skciphers (speck_algs,ARRAY_SIZE (speck_algs)); +} + +module_init (speck_neon_module_init); +module_exit (speck_neon_module_exit); + +MODULE_DESCRIPTION ("Speck block cipher (NEON-accelerated)" ); +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Eric Biggers <[email protected]>" ); +MODULE_ALIAS_CRYPTO ("xts(speck128)" ); +MODULE_ALIAS_CRYPTO ("xts-speck128-neon" ); +MODULE_ALIAS_CRYPTO ("xts(speck64)" ); +MODULE_ALIAS_CRYPTO ("xts-speck64-neon" ); --2.16.0.rc1.238.g530d649a79-goog
PATCH v2 3/5 crypto: arm/speck - add NEON-accelerated implementation of Speck-XTS
Hi Ard,
Quoted 41 lines · Ard Biesheuvel
Hi Eric,
Quoted 31 lines · Eric Biggers
Add an ARM NEON-accelerated implementation of Speck-XTS. It operates on 128-byte chunks at a time, i.e. 8 blocks for Speck128 or 16 blocks for Speck64. Each 128-byte chunk goes through XTS preprocessing, then is encrypted/decrypted (doing one cipher round for all the blocks, then the next round, etc.), then goes through XTS postprocessing.
The performance depends on the processor but can be about 3 times faster than the generic code. For example, on an ARMv7 processor we observe the following performance with Speck128/256-XTS:
xts-speck128-neon: Encryption 107.9 MB/s, Decryption 108.1 MB/s xts(speck128-generic): Encryption 32.1 MB/s, Decryption 36.6 MB/sIn comparison to AES-256-XTS without the Cryptography Extensions:
xts-aes-neonbs: Encryption 41.2 MB/s, Decryption 36.7 MB/s xts(aes-asm): Encryption 31.7 MB/s, Decryption 30.8 MB/s xts(aes-generic): Encryption 21.2 MB/s, Decryption 20.9 MB/sSpeck64/128-XTS is even faster:
xts-speck64-neon: Encryption 138.6 MB/s, Decryption 139.1 MB/sNote that as with the generic code, only the Speck128 and Speck64 variants are supported. Also, for now only the XTS mode of operation is supported, to target the disk and file encryption use cases. The NEON code also only handles the portion of the data that is evenly divisible into 128-byte chunks, with any remainder handled by a C fallback. Of course, other modes of operation could be added later if needed, and/or the NEON code could be updated to handle other buffer sizes.
Quoted 6 lines
The XTS specification is only defined for AES which has a 128-bit block size, so for the GF(2^64) math needed for Speck64-XTS we use the reducing polynomial 'x^64 + x^4 + x^3 + x + 1' given by the original XEX paper. Of course, when possible users should use Speck128-XTS, but even that may be too slow on some processors; Speck64-XTS can be faster.
Quoted 6 lines
I think this is excellent work. Speck seems an appropriate solution to this problem, and I'm glad we are not ending up with a stream cipher for block encryption.
Also, I think an arm64 port would be nice. I may take a stab at this if nobody else beats me to it.
We don't really want to encourage people to use Speck over AES with the Cryptography Extensions, so that's why I didn't include an arm64 port. That being said, I suppose we can't stop people from adding an arm64 port if they really do prefer Speck, or maybe for use on arm64 CPUs that don't have the Cryptography Extensions (though I thought that almost all do).
Quoted 11 lines
I did run into an issue with this code though: On big-endian, I get
[ 0.272381] alg: skcipher: Test 1 failed (invalid result) on encryption for xts-speck64-neon [ 0.276151] 00000000: 84 af 54 07 19 d4 7c a6 9c 8a ac f6 c2 14 04 d8 [ 0.278541] 00000010: 7f 18 6c 43 56 ed 0b b3 92 21 a2 d9 17 59 e4 3bso there may be a byte order corner case you missed in the rewrite (or the issue existed before, as I did not test your v1)
To be honest I haven't tested either version on a big endian ARM CPU yet. I don't really know how to do that currently; maybe it's possible with QEMU.
But assuming I haven't missed anything, in the assembly code everything is treated as byte arrays with the exception of the round keys which are 32-bit or 64-bit numbers in CPU endianness. The byte arrays are loaded and stored with vld1.8 and vst1.8 while the round keys are loaded with vld1.32 or vld1.64, so the assembly code *should* work correctly on a big endian CPU.
However, looking over it now, I think there is a bug in the glue code for Speck64-XTS when it handles buffers not evenly divisible into 128 bytes. Namely, the tweak is treated as CPU endian when it should be little endian. Could you try the following patch?
arch/arm/crypto/speck-neon-glue.c +10 -10
@@ -157,7 +157,7 @@ __speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one,struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req);const struct speck64_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm);struct skcipher_walk walk; -u64 tweak; +__le64 tweak;int err; err =skcipher_walk_virt (&walk, req, true);
@@ -184,16 +184,16 @@ __speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one, }/* Handle any remainder with generic code */ -while (nbytes >=sizeof (u64)) { - *(u64 *)dst = *(u64 *)src ^ tweak; +while (nbytes >=sizeof (__le64)) { + *(__le64 *)dst = *(__le64 *)src ^ tweak; (*crypt_one)(&ctx->main_key, dst, dst); - *(u64 *)dst ^= tweak; - tweak = (tweak <<1 ) ^ - ((tweak & (1ULL <<63 )) ?0x1B :0 ); - - dst +=sizeof (u64); - src +=sizeof (u64); - nbytes -=sizeof (u64); + *(__le64 *)dst ^= tweak; + tweak =cpu_to_le64 ((le64_to_cpu (tweak) <<1 ) ^ + ((tweak &cpu_to_le64 (1ULL <<63 )) ? +0x1B :0 )); + dst +=sizeof (__le64); + src +=sizeof (__le64); + nbytes -=sizeof (__le64); } err =skcipher_walk_done (&walk, nbytes); }
PATCH v2 3/5 crypto: arm/speck - add NEON-accelerated implementation of Speck-XTS
Quoted 48 lines · Eric Biggers
Hi Ard,
Quoted 45 lines · Ard Biesheuvel
Hi Eric,
Quoted 31 lines · Eric Biggers
Add an ARM NEON-accelerated implementation of Speck-XTS. It operates on 128-byte chunks at a time, i.e. 8 blocks for Speck128 or 16 blocks for Speck64. Each 128-byte chunk goes through XTS preprocessing, then is encrypted/decrypted (doing one cipher round for all the blocks, then the next round, etc.), then goes through XTS postprocessing.
The performance depends on the processor but can be about 3 times faster than the generic code. For example, on an ARMv7 processor we observe the following performance with Speck128/256-XTS:
xts-speck128-neon: Encryption 107.9 MB/s, Decryption 108.1 MB/s xts(speck128-generic): Encryption 32.1 MB/s, Decryption 36.6 MB/sIn comparison to AES-256-XTS without the Cryptography Extensions:
xts-aes-neonbs: Encryption 41.2 MB/s, Decryption 36.7 MB/s xts(aes-asm): Encryption 31.7 MB/s, Decryption 30.8 MB/s xts(aes-generic): Encryption 21.2 MB/s, Decryption 20.9 MB/sSpeck64/128-XTS is even faster:
xts-speck64-neon: Encryption 138.6 MB/s, Decryption 139.1 MB/sNote that as with the generic code, only the Speck128 and Speck64 variants are supported. Also, for now only the XTS mode of operation is supported, to target the disk and file encryption use cases. The NEON code also only handles the portion of the data that is evenly divisible into 128-byte chunks, with any remainder handled by a C fallback. Of course, other modes of operation could be added later if needed, and/or the NEON code could be updated to handle other buffer sizes.
Quoted 6 lines
The XTS specification is only defined for AES which has a 128-bit block size, so for the GF(2^64) math needed for Speck64-XTS we use the reducing polynomial 'x^64 + x^4 + x^3 + x + 1' given by the original XEX paper. Of course, when possible users should use Speck128-XTS, but even that may be too slow on some processors; Speck64-XTS can be faster.
I think this is excellent work. Speck seems an appropriate solution to this problem, and I'm glad we are not ending up with a stream cipher for block encryption.
Quoted 9 lines
Quoted 2 lines
Also, I think an arm64 port would be nice. I may take a stab at this if nobody else beats me to it.
We don't really want to encourage people to use Speck over AES with the Cryptography Extensions, so that's why I didn't include an arm64 port. That being said, I suppose we can't stop people from adding an arm64 port if they really do prefer Speck, or maybe for use on arm64 CPUs that don't have the Cryptography Extensions (though I thought that almost all do).
Many do, but not all of them. A notable exception is the Raspberry Pi 3.
Quoted 8 lines
Quoted 8 lines
I did run into an issue with this code though: On big-endian, I get
[ 0.272381] alg: skcipher: Test 1 failed (invalid result) on encryption for xts-speck64-neon [ 0.276151] 00000000: 84 af 54 07 19 d4 7c a6 9c 8a ac f6 c2 14 04 d8 [ 0.278541] 00000010: 7f 18 6c 43 56 ed 0b b3 92 21 a2 d9 17 59 e4 3b
Quoted 7 lines
Quoted 3 lines
so there may be a byte order corner case you missed in the rewrite (or the issue existed before, as I did not test your v1)
To be honest I haven't tested either version on a big endian ARM CPU yet. I don't really know how to do that currently; maybe it's possible with QEMU.
I tested this on a big-endian 32-bit VM running under KVM on a 64-bit host.
Quoted 6 lines
But assuming I haven't missed anything, in the assembly code everything is treated as byte arrays with the exception of the round keys which are 32-bit or 64-bit numbers in CPU endianness. The byte arrays are loaded and stored with vld1.8 and vst1.8 while the round keys are loaded with vld1.32 or vld1.64, so the assembly code *should* work correctly on a big endian CPU.
Indeed.
Quoted 34 lines
However, looking over it now, I think there is a bug in the glue code for Speck64-XTS when it handles buffers not evenly divisible into 128 bytes. Namely, the tweak is treated as CPU endian when it should be little endian. Could you try the following patch?
arch/arm/crypto/speck-neon-glue.c +3
-10@@ -157,7 +157,7 @@ __speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one,struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req);const struct speck64_xts_tfm_ctx *ctx =crypto_skcipher_ctx (tfm);struct skcipher_walk walk; -u64 tweak; +__le64 tweak;int err; err =skcipher_walk_virt (&walk, req, true);@@ -184,16 +184,16 @@ __speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one, }/* Handle any remainder with generic code */ -while (nbytes >=sizeof (u64)) { - *(u64 *)dst = *(u64 *)src ^ tweak; +while (nbytes >=sizeof (__le64)) { + *(__le64 *)dst = *(__le64 *)src ^ tweak; (*crypt_one)(&ctx->main_key, dst, dst); - *(u64 *)dst ^= tweak; - tweak = (tweak <<1 ) ^ - ((tweak & (1ULL <<63 )) ?0x1B :0 ); - - dst +=sizeof (u64); - src +=sizeof (u64); - nbytes -=sizeof (u64);
arch/arm/crypto/speck-neon-glue.c __speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one, · line 199
Quoted 10 lines
arch/arm/crypto/speck-neon-glue.c +7
-0+ *(__le64 *)dst ^= tweak; + tweak =cpu_to_le64 ((le64_to_cpu (tweak) <<1 ) ^ + ((tweak &cpu_to_le64 (1ULL <<63 )) ? +0x1B :0 )); + dst +=sizeof (__le64); + src +=sizeof (__le64); + nbytes -=sizeof (__le64); } err =skcipher_walk_done (&walk, nbytes); }
This fixes it.
PATCH v2 4/5 crypto: speck - add test vectors for Speck128-XTS
In reply to Eric BiggersAdd test vectors for Speck128-XTS, generated in userspace using C code. The inputs were borrowed from the AES-XTS test vectors.
Both xts(speck128-generic) and xts-speck128-neon pass these tests.
--- crypto/testmgr.c | 9 + crypto/testmgr.h | 687 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 696 insertions(+)
crypto/testmgr.c +9 -0
@@ -3575,6 +3575,15 @@ static const struct alg_test_desc alg_test_descs[] = { .dec = __VECS(serpent_xts_dec_tv_template) } } + }, { + .alg = "xts(speck128)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = __VECS(speck128_xts_enc_tv_template), + .dec = __VECS(speck128_xts_dec_tv_template) + } + } }, { .alg = "xts(twofish)", .test = alg_test_skcipher,
crypto/testmgr.h +687 -0
693 lines not on this page · raw message
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
PATCH v2 5/5 crypto: speck - add test vectors for Speck64-XTS
In reply to Eric BiggersAdd test vectors for Speck64-XTS, generated in userspace using C code. The inputs were borrowed from the AES-XTS test vectors, with key lengths adjusted.
xts-speck64-neon passes these tests. However, they aren't currently applicable for the generic XTS template, as that only supports a 128-bit block size.
--- crypto/testmgr.c | 9 + crypto/testmgr.h | 671 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 680 insertions(+)
crypto/testmgr.c +9 -0
@@ -3584,6 +3584,15 @@ static const struct alg_test_desc alg_test_descs[] = { .dec = __VECS(speck128_xts_dec_tv_template) } } + }, { + .alg = "xts(speck64)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = __VECS(speck64_xts_enc_tv_template), + .dec = __VECS(speck64_xts_dec_tv_template) + } + } }, { .alg = "xts(twofish)", .test = alg_test_skcipher,
crypto/testmgr.h +671 -0
677 lines not on this page · raw message
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
v2 cover crypto: Speck support
In reply to Eric BiggersCan we please not Speck?
It was just rejected by the ISO/IEC.
v2 cover crypto: Speck support
Hi Jason,
Quoted 5 lines · Jason A. Donenfeld
Can we please not Speck?
It was just rejected by the ISO/IEC.
So, what do you propose replacing it with?
As I explained in the patch, the purpose of adding Speck is to allow low-end Android devices -- ones that have CPUs without the ARMv8 Cryptography Extensions -- to start using dm-crypt or fscrypt. Currently such devices are unencrypted. So, Speck is replacing *no encryption*, not another encryption algorithm. By removing Speck, you are removing encryption. It's great that people are enthusiastic about debating choices of crypto algorithms. But it's unfortunate that "no crypto" tends to pass by without comment from the same people.
We really wanted to use ChaCha20 instead. But it would have been used in a context where IVs are reused (f2fs encryption on flash storage), which catastrophically breaks stream ciphers, but is less bad for a block cipher operating in XTS mode. Thus, we had to use either a block cipher, or a wide-block encryption mode (pseudorandom permutation over the whole input). Of course, we would have liked to store nonces instead, but that is not currently feasible with either dm-crypt or fscrypt. It can be done with dm-crypt on top of dm-integrity, but that performs very poorly and would be especially inappropriate for low end mobile devices.
Paul Crowley actually designed a very neat wide-block encryption mode based on ChaCha20 and Poly1305, which we considered too. But it would have been harder to implement, and we'd have had to be pushing it with zero or very little outside crypto review, vs. the many cryptanalysis papers on Speck. (In that respect the controversy about Speck has actually become an advantage, as it has received much more cryptanalysis than other lightweight block ciphers.)
The reason we chose Speck had nothing to do with the proposed ISO standard or any sociopolitical factors, but rather because it was the only algorithm we could find that met the performance and security requirements. Note that Linux doesn't bow down to any particular standards organization, and it offers algorithms that were specified in various places, even some with no more than a publication by the author. In fact, support for SM4 was just added too, which is a Chinese government standard. Are you going to send a patch to remove that too, or is it just NSA designed algorithms that are not okay?
It is unfortunate that we had to choose an algorithm that has some emotional/political baggage attached, and of course we did expect some pushback. But I hope you can understand that all *technical* indicators are that Speck is secure enough, and not really backdoor-able other than a new cryptoanalytical technique that would likely apply to other ARX ciphers as well (in fact, you'd probably have a different opinion of it if the authors had simply worked somewhere else and published the exact same algorithm); and also, the trend towards stream ciphers such as ChaCha20 has mostly ignored the disk encryption use case, where a block cipher is still needed.
Thanks,
Eric
v2 cover crypto: Speck support
Hi Eric,
Quoted 1 line · Eric Biggers
So, what do you propose replacing it with?
Something more cryptographically justifiable.
Quoted 3 lines
outside crypto review, vs. the many cryptanalysis papers on Speck. (In that respect the controversy about Speck has actually become an advantage, as it has received much more cryptanalysis than other lightweight block ciphers.)
That's the thing that worries me, actually. Many of the design decisions behind Speck haven't been justified.
Quoted 10 lines
The reason we chose Speck had nothing to do with the proposed ISO standard or any sociopolitical factors, but rather because it was the only algorithm we could find that met the performance and security requirements.
Note that Linux
doesn't bow down to any particular standards organization, and it offers algorithms that were specified in various places, even some with no more than a publication by the author. In fact, support for SM4 was just added too, which is a Chinese government standard. Are you going to send a patch to remove that too, or is it just NSA designed algorithms that are not okay?
No need to be belittling; I have much less tinfoil strapped around my head than perhaps you think. I'm not blindly opposed to government-designed algorithms. Take SHA2, for example -- built by the NSA.
But I do care quite a bit about using ciphers that have acceptance of the academic community and a large body of literature documenting its design decisions and analyzing it. Some of the best symmetric cryptographers in academia have expressed reservations about it, and it was just rejected from a major standard's body. Linux, of course, is free to disagree -- or "bow down" as you oddly put it -- but I'd make sure you've got a pretty large bucket of justifications for that disagreement.
Quoted 3 lines
(in fact, you'd
probably have a different opinion of it if the authors had simply worked somewhere else and published the exact same algorithm);
Again, no need to patronize. I don't actually have a bias like that.
Quoted 2 lines
But I hope you can understand that all *technical* indicators are that Speck is secure enough
That's the thing I'm worried about.
Jason
v2 cover crypto: Speck support
Quoted 4 lines · Jason A. Donenfeld
Quoted 1 line · Eric Biggers
So, what do you propose replacing it with?
Something more cryptographically justifiable.
I'm keen to hear recommendations here, if there are options we should be considering I'd like to know about them.
Quoted 2 lines
That's the thing that worries me, actually. Many of the design decisions behind Speck haven't been justified.
It seems to me justified about as well as one would hope for a new cipher -
"Notes on the design and analysis of Simon and Speck" seems to me to give
more detail on the reasoning than went into eg Salsa20, which I think also hit a perfectly acceptable bar and was a good choice for adding to the Linux kernel. Of course it's building on the fairly detailed understanding we now have of how to build a secure ARX cipher. Given what a prize cryptanalysis of an NSA-designed block cipher would be for anyone in the field, the sheer simplicity and straightforwardness of the design, taken with the very large gap between the full cipher and the best cryptanalysis, and drawing on my own experience attacking Salsa20, I feel pretty good about fielding this design. But if you have a specific alternative in mind
- a 128-bit block cipher (so we can use it in XTS mode) which is fast and side-channel-free on ARM processors with NEON but without ARM CE - I'm very keen to hear about it.
Could you say a little more about what it is that separates Speck from SM4 for you?
Thanks!
v2 cover crypto: Speck support
In reply to Jason A. DonenfeldHi Jason,
Quoted 7 lines · Jason A. Donenfeld
Hi Eric,
Quoted 1 line · Eric Biggers
So, what do you propose replacing it with?
Something more cryptographically justifiable.
It's easy to say that, but do you have an actual suggestion? As I mentioned, for disk encryption without AES instructions the main alternatives we've considered are ChaCha20 with reused nonces, an unpublished wide-block mode based on ChaCha20 and Poly1305 (with no external cryptanalysis yet, and probably actually using ChaCha8 or ChaCha12 to meet performance requirements), or the status quo of no encryption at all.
It *might* be possible to add per-block metadata support to f2fs, in which it could be used with ChaCha20 in fscrypt. But if feasible at all it would be quite difficult (requiring some significant filesystem surgery, and disabling conflicting filesystem features that allow data to be updated in-place) and would not cover dm-crypt, nor ext4.
Note also that many other lightweight block ciphers are designed for hardware and perform poorly in software, e.g. PRESENT is even slower than AES. Thus there really weren't many options.
Any concrete suggestions are greatly appreciated!
Quoted 7 lines
Quoted 3 lines
outside crypto review, vs. the many cryptanalysis papers on Speck. (In that respect the controversy about Speck has actually become an advantage, as it has received much more cryptanalysis than other lightweight block ciphers.)
That's the thing that worries me, actually. Many of the design decisions behind Speck haven't been justified.
Originally that was true, but later there were significant clarifications released, e.g. the paper "Notes on the design and analysis of Simon and Speck"
(https://eprint.iacr.org/2017/560.pdf). In fact, from what I can see, many competing lightweight block ciphers don't have as much design justification available as Speck. Daniel Bernstein's papers are excellent, but unfortunately he has only designed a stream cipher, not a block cipher or another algorithm that is applicable for disk encryption.
Quoted 16 lines
Quoted 10 lines
The reason we chose Speck had nothing to do with the proposed ISO standard or any sociopolitical factors, but rather because it was the only algorithm we could find that met the performance and security requirements.
Note that Linux
doesn't bow down to any particular standards organization, and it offers algorithms that were specified in various places, even some with no more than a publication by the author. In fact, support for SM4 was just added too, which is a Chinese government standard. Are you going to send a patch to remove that too, or is it just NSA designed algorithms that are not okay?No need to be belittling; I have much less tinfoil strapped around my head than perhaps you think. I'm not blindly opposed to government-designed algorithms. Take SHA2, for example -- built by the NSA.
Quoted 9 lines
But I do care quite a bit about using ciphers that have acceptance of the academic community and a large body of literature documenting its design decisions and analyzing it. Some of the best symmetric cryptographers in academia have expressed reservations about it, and it was just rejected from a major standard's body. Linux, of course, is free to disagree -- or "bow down" as you oddly put it -- but I'd make sure you've got a pretty large bucket of justifications for that disagreement.
There have actually been many papers analyzing Speck. As with other ciphers, reduced-round variants have been successfully attacked, while the full variants have held up. This is expected. It's true that some other ciphers such as ChaCha20 have a higher security margin, which has resulted in some criticism of Speck. But the correct security margin is always debatable, and in a performance-oriented cipher it's desirable to not have an excessive number of rounds. In fact it was even looking like ChaCha20 was not going to be fast enough on some CPUs, so if we went the ChaCha route we may have actually have had to use ChaCha12 or ChaCha8 instead.
Also, some papers present results for just the weakest variants of Speck (Speck32 and Speck48) while omitting the strongest (Speck128, the one that's planned to be offered for Android), presumably because the authors weren't able to attack it as successfully. I think that's causing some confusion.
I don't see how the ISO standarization process means much for crypto algorithms. It seems very political, and actually it seems that people involved were pretty clear that Speck was rejected primarily for political reasons. Interestingly, ChaCha20 is not an ISO standard either. Does that mean ChaCha20 shouldn't be used?
In any case, given that the status quo on low-end Android devices is no encryption, it would be great to start having them be encrypted. It would be a shame if pushback for non-technical reasons prevents that from happening.
Quoted 11 lines
Quoted 3 lines
(in fact, you'd
probably have a different opinion of it if the authors had simply worked somewhere else and published the exact same algorithm);Again, no need to patronize. I don't actually have a bias like that.
Quoted 2 lines
But I hope you can understand that all *technical* indicators are that Speck is secure enough
That's the thing I'm worried about.
Thanks,
- Eric
v2 cover crypto: Speck support
Let's put the provenance of Speck aside for a moment, and suppose that it is an ideal block cipher. There are still some issues with this patch as it stands.
- The rationale seems off. Consider this bit from the commit message:
Quoted 3 lines
Other AES alternatives such as Twofish, Threefish, Camellia, CAST6, and Serpent aren't fast enough either; it seems that only a modern ARX cipher can provide sufficient performance on these devices.
One of these things is very much not like the others. Threefish _is_ a modern ARX cipher---a tweakable block cipher in fact, precluding the need for XEX-style masking. Is it too slow? Does it not have the correct block size?
Quoted 2 lines
We've also considered a novel length-preserving encryption mode based on ChaCha20 and Poly1305.
I'm very curious about this, namely as to what the role of Poly1305 would be here. ChaCha20's underlying permutation could, of course, be transformed into a 512-bit tweakable block cipher relatively painlessly, retaining the performance of regular ChaCha20 with marginal additional overhead. This would not be a standard construction, but clearly that is not an issue.
But the biggest problem here, in my mind, is that for all the talk of using 128-bit block Speck, this patch tacks on the 64-bit block variant of Speck into the kernel, and speck64-xts as well! As far as I can tell, this is the _only_ instance of a 64-bit XTS instance in the entire codebase. Now, if you wanted a fast 64-bit ARX block cipher, the kernel already had XTEA. Instead, this is adding yet another 64-bit block cipher into the crypto API, in a disk-encryption mode no less, so that it can be misused later. In the disk encryption setting, it's particularly concerning to be using such a small block size, as data volumes can quickly add up to the birthday bound.
Quoted 1 line
It's easy to say that, but do you have an actual suggestion?
I don't know how seriously you are actually asking this, but some 128-bit software-friendly block ciphers could be SPARX, LEA, RC5, or RC6. SPARX, in particular, has similarities to Speck but has some further AES-like design guarantees that other prior ARX block ciphers did not. Some other bitsliced designs, such as Noekeon or SKINNY, may also work well with NEON, but I don't know much about their performance there.
Best regards,
Samuel Neves
v2 cover crypto: Speck support
Hi Samuel,
Quoted 38 lines · Samuel Neves
Let's put the provenance of Speck aside for a moment, and suppose that it is an ideal block cipher. There are still some issues with this patch as it stands.
- The rationale seems off. Consider this bit from the commit message:
Quoted 3 lines
Other AES alternatives such as Twofish, Threefish, Camellia, CAST6, and Serpent aren't fast enough either; it seems that only a modern ARX cipher can provide sufficient performance on these devices.
One of these things is very much not like the others. Threefish _is_ a modern ARX cipher---a tweakable block cipher in fact, precluding the need for XEX-style masking. Is it too slow? Does it not have the correct block size?
Quoted 2 lines
We've also considered a novel length-preserving encryption mode based on ChaCha20 and Poly1305.
I'm very curious about this, namely as to what the role of Poly1305 would be here. ChaCha20's underlying permutation could, of course, be transformed into a 512-bit tweakable block cipher relatively painlessly, retaining the performance of regular ChaCha20 with marginal additional overhead. This would not be a standard construction, but clearly that is not an issue.
But the biggest problem here, in my mind, is that for all the talk of using 128-bit block Speck, this patch tacks on the 64-bit block variant of Speck into the kernel, and speck64-xts as well! As far as I can tell, this is the _only_ instance of a 64-bit XTS instance in the entire codebase. Now, if you wanted a fast 64-bit ARX block cipher, the kernel already had XTEA. Instead, this is adding yet another 64-bit block cipher into the crypto API, in a disk-encryption mode no less, so that it can be misused later. In the disk encryption setting, it's particularly concerning to be using such a small block size, as data volumes can quickly add up to the birthday bound.
Quoted 1 line
It's easy to say that, but do you have an actual suggestion?
Quoted 8 lines
I don't know how seriously you are actually asking this, but some 128-bit software-friendly block ciphers could be SPARX, LEA, RC5, or RC6. SPARX, in particular, has similarities to Speck but has some further AES-like design guarantees that other prior ARX block ciphers did not. Some other bitsliced designs, such as Noekeon or SKINNY, may also work well with NEON, but I don't know much about their performance there.
I agree that my explanation should have been better, and should have considered more crypto algorithms. The main difficulty is that we have extreme performance requirements -- it needs to be 50 MB/s at the very least on even low-end ARM devices like smartwatches. And even with the NEON-accelerated Speck128-XTS performance exceeding that after much optimization, we've been getting a lot of pushback as people want closer to 100 MB/s.
That's why I also included Speck64-XTS in the patches, since it was straightforward to include, and some devices may really need that last 20-30% of performance for encryption to be feasible at all. (And when the choice is between unencrypted and a 64-bit block cipher, used in a context where the weakest points in the cryptosystem are actually elsewhere such as the user's low-entropy PIN and the flash storage doing wear-leveling, I'd certainly take the 64-bit block cipher.) So far we haven't had to use Speck64 though, and if that continues to be the case I'd be fine with Speck64 being removed, leaving just Speck128.
Note that in practice, to have any chance at meeting the performance requirement the cipher needed to be NEON accelerated. That made benchmarking really hard and time-consuming, since to definitely know how an algorithm performs it can take upwards of a week to implement a NEON version. It needs to be very well optimized too, to compare the algorithms fairly -- e.g. with Speck I got a 20% performance improvement on some CPUs just by changing the NEON instructions used to implement the 8-bit rotates, an optimization that is not possible with ciphers that don't use rotate amounts that are multiples of 8. (This was an intentional design choice by the Speck designers; they do know what they're doing, actually.)
Thus, we had to be pretty aggressive about dropping algorithms from consideration if there were preliminary indications that they wouldn't perform well, or had too little cryptanalysis, or had other issues such as an unclear patent situation. Threefish for example I did test the C implementation at
https://github.com/wernerd/Skein3Fish, but on ARM32 it was over 4 times slower than my NEON implementation of Speck128/256-XTS. And I did not see a clear way that it could be improved over 4x with NEON, if at all, so I did not take the long time it would have taken to write an optimized NEON implementation to benchmark it properly. Perhaps that was a mistake. But, time is not unlimited.
RC5 and RC6 use data-dependent rotates which won't perform too well on NEON, also historically those algorithms have been patented. It sounds like the last patents expired last year, but we'd need to double check and be very sure that's really the case.
As for the wide-block mode using ChaCha20 and Poly1305, you'd have to ask Paul Crowley to explain it properly, but briefly it's actually a pseudorandom permutation over an arbitrarily-sized message. So with dm-crypt for example, it would operate on a whole 512-byte sector, and if any bit of the 512-byte plaintext is changed, then every bit in the 512-byte ciphertext would change with 50% probability. To make this possible, the construction uses a polynomial evalution in GF(2^130-5) as a universal hash function, similar to the Poly1305 mode.
Using ChaCha20's underlying 512-bit permutation to build a tweakable block cipher is an interesting idea. But maybe in my crypto-naivety, it is not obvious to me how to do so. Do you have references to any relevant papers? Remember that we strongly prefer a published cipher to a custom one -- even if the core is reused, a mistake may be made in the way it is used. Thus, similarly to Paul's wide-block mode, I'd be concerned that we'd have to self-publish a new construction, then use it with no outside crypto review. *Maybe* it would be straightforward enough to be okay, but to know I'd need to see the details of how it would actually work.
But in the end, Speck seemed like the clear choice because it had multiple NEON implementations available already which showed it could be implemented very efficiently in NEON; it has over 70 cryptanalysis papers (far more than most ciphers) yet the security margin is still similar to AES; it has no intellectual property concerns; there is a paper clearly explaining the design decisions; it is naturally resistant to timing attacks; it supports a 128-bit block size, so it can be easily used in XTS mode; it supports the same key sizes as AES; and it has a simple and understandable design with no "magic numbers" besides 8 and 3 (compare to an actual backdoored algorithm like Dual_EC_DRGB, which basically had a public key embedded in the algorithm). Also as Paul mentioned he is confident in the construction, and he has published cryptanalysis on Salsa20, so his opinion is probably more significant than mine :-)
But I will definitely take a closer look at SPARX and some of the other ciphers you mentioned in case I missed something. I really do appreciate the suggestions, by the way, and in any case we do need to be very well prepared to justify our choices. I just hope that people can understand that we are implementing real-world crypto which must operate under *very* tight performance constraints on ARM processors, and it must be compatible with dm-crypt and fscrypt with no room for ciphertext expansion. Thus, many algorithms which may at first seem reasonable choices had to (unfortunately) be excluded.
Thanks!
Eric
v2 cover crypto: Speck support
Quoted 7 lines · Eric Biggers
I agree that my explanation should have been better, and should have considered more crypto algorithms. The main difficulty is that we have extreme performance requirements -- it needs to be 50 MB/s at the very least on even low-end ARM devices like smartwatches. And even with the NEON-accelerated Speck128-XTS performance exceeding that after much optimization, we've been getting a lot of pushback as people want closer to 100 MB/s.
I couldn't find any NEON-capable ARMv7 chip below 800 MHz, so this would put the performance upper bound around 15 cycles per byte, with the comfortable number being ~7. That's indeed tough, though not impossible.
Quoted 11 lines
That's why I also included Speck64-XTS in the patches, since it was straightforward to include, and some devices may really need that last 20-30% of performance for encryption to be feasible at all. (And when the choice is between unencrypted and a 64-bit block cipher, used in a context where the weakest points in the cryptosystem are actually elsewhere such as the user's low-entropy PIN and the flash storage doing wear-leveling, I'd certainly take the 64-bit block cipher.) So far we haven't had to use Speck64 though, and if that continues to be the case I'd be fine with Speck64 being removed, leaving just Speck128.
I would very much prefer that to be the case. As many of us know, "it's better than nothing" has been often used to justify other bad choices, like RC4, that end up preventing better ones from being adopted. At a time where we're trying to get rid of 64-bit ciphers in TLS, where data volumes per session are comparatively low, it would be unfortunate if the opposite starts happening on encryption at rest.
Quoted 12 lines
Note that in practice, to have any chance at meeting the performance requirement the cipher needed to be NEON accelerated. That made benchmarking really hard and time-consuming, since to definitely know how an algorithm performs it can take upwards of a week to implement a NEON version. It needs to be very well optimized too, to compare the algorithms fairly -- e.g. with Speck I got a 20% performance improvement on some CPUs just by changing the NEON instructions used to implement the 8-bit rotates, an optimization that is not possible with ciphers that don't use rotate amounts that are multiples of 8. (This was an intentional design choice by the Speck designers; they do know what they're doing, actually.)
Quoted 10 lines
Thus, we had to be pretty aggressive about dropping algorithms from consideration if there were preliminary indications that they wouldn't perform well, or had too little cryptanalysis, or had other issues such as an unclear patent situation. Threefish for example I did test the C implementation at
https://github.com/wernerd/Skein3Fish, but on ARM32 it was over 4 times slower than my NEON implementation of Speck128/256-XTS. And I did not see a clear way that it could be improved over 4x with NEON, if at all, so I did not take the long time it would have taken to write an optimized NEON implementation to benchmark it properly. Perhaps that was a mistake. But, time is not unlimited.
In my limited experience with NEON and 64-bit ARX, there's usually a ~2x speedup solely from NEON's native 64-bit operations on ARMv7-A. The extra speedup from encrypting 2 block in parallel is then somewhere between 1x and 2x, depending on various details. Getting near 4x might be feasible, but it is indeed time-consuming to get there.
Quoted 10 lines
As for the wide-block mode using ChaCha20 and Poly1305, you'd have to ask Paul Crowley to explain it properly, but briefly it's actually a pseudorandom permutation over an arbitrarily-sized message. So with dm-crypt for example, it would operate on a whole 512-byte sector, and if any bit of the 512-byte plaintext is changed, then every bit in the 512-byte ciphertext would change with 50% probability. To make this possible, the construction uses a polynomial evalution in GF(2^130-5) as a universal hash function, similar to the Poly1305 mode.
Oh, OK, that sounds like something resembling Naor-Reingold or its relatives. That would work, but with 3 or 4 passes I guess it wouldn't be very fast.
Quoted 11 lines
Using ChaCha20's underlying 512-bit permutation to build a tweakable block cipher is an interesting idea. But maybe in my crypto-naivety, it is not obvious to me how to do so. Do you have references to any relevant papers? Remember that we strongly prefer a published cipher to a custom one -- even if the core is reused, a mistake may be made in the way it is used. Thus, similarly to Paul's wide-block mode, I'd be concerned that we'd have to self-publish a new construction, then use it with no outside crypto review. *Maybe* it would be straightforward enough to be okay, but to know I'd need to see the details of how it would actually work.
This would be the 'tweakable Even-Mansour' construction and its variants. The variant I'm most familiar with would be MEM [1], focusing on software friendliness, but there is other provable security work in the same vein, including [3, 4, 5]. It's very similar to how the XEX mode turns a block cipher into a tweakable block cipher.
In [1, 2] we used a 1024-bit permutation out of BLAKE2 instead of ChaCha20's, but everything translates easily from one to the other. We also included cheap masks for 512-bit permutations, just in case.
[1] https://eprint.iacr.org/2015/999
[2] https://github.com/MEM-AEAD/mem-aead
[3] https://eprint.iacr.org/2015/539
[4] https://eprint.iacr.org/2015/476
[5] https://competitions.cr.yp.to/round2/minalpherv11.pdf
Quoted 14 lines
But in the end, Speck seemed like the clear choice because it had multiple NEON implementations available already which showed it could be implemented very efficiently in NEON; it has over 70 cryptanalysis papers (far more than most ciphers) yet the security margin is still similar to AES; it has no intellectual property concerns; there is a paper clearly explaining the design decisions; it is naturally resistant to timing attacks; it supports a 128-bit block size, so it can be easily used in XTS mode; it supports the same key sizes as AES; and it has a simple and understandable design with no "magic numbers" besides 8 and 3 (compare to an actual backdoored algorithm like
Dual_EC_DRGB, which basically had a public key embedded in the algorithm). Also as Paul mentioned he is confident in the construction, and he has published cryptanalysis on Salsa20, so his opinion is probably more significant than mine :-)
Quoted 9 lines
But I will definitely take a closer look at SPARX and some of the other ciphers you mentioned in case I missed something. I really do appreciate the suggestions, by the way, and in any case we do need to be very well prepared to justify our choices. I just hope that people can understand that we are implementing real-world crypto which must operate under *very* tight performance constraints on ARM processors, and it must be compatible with dm-crypt and fscrypt with no room for ciphertext expansion. Thus, many algorithms which may at first seem reasonable choices had to (unfortunately) be excluded.
I understand it is a tough choice, and it's unfortunate that many of the algorithms we have cater mostly to either the high-hardware-accelerated-end or the extremely low-end, without a lot of good options at the middle-end.
Best regards,
Samuel Neves
v2 cover crypto: Speck support
Quoted 3 lines
Oh, OK, that sounds like something resembling Naor-Reingold or its relatives. That would work, but with 3 or 4 passes I guess it wouldn't be very fast.
It most resembles HCH mode https://eprint.iacr.org/2007/028 using two passes of Poly1305, one pass of ChaCha20, and one invocation of a 128-bit block cipher for the entire block. I have a writeup with a proof that it's a secure tweakable SPRP, but we haven't actually implemented it yet so the "Performance" section is a bit thin. From published benchmarks, Poly1305 is around 2.3 cpb and ChaCha12 around 4.5 cbp on our target platform, so we're hoping to achieve something a little over 7.1 cpb.
Right now we're in a situation where the people who can afford higher-end devices with ARM CE get AES encryption, and the rest of the world gets no encryption, or optional encryption that is rarely enabled because of the performance cost. It's important to me to change that, and right now Speck still looks like a good choice for achieving that end.
v2 cover crypto: Speck support
In reply to Samuel NevesHi Samuel,
Quoted 131 lines · Samuel Neves
Quoted 7 lines · Eric Biggers
I agree that my explanation should have been better, and should have considered more crypto algorithms. The main difficulty is that we have extreme performance requirements -- it needs to be 50 MB/s at the very least on even low-end ARM devices like smartwatches. And even with the NEON-accelerated Speck128-XTS performance exceeding that after much optimization, we've been getting a lot of pushback as people want closer to 100 MB/s.
I couldn't find any NEON-capable ARMv7 chip below 800 MHz, so this would put the performance upper bound around 15 cycles per byte, with the comfortable number being ~7. That's indeed tough, though not impossible.
Quoted 11 lines
That's why I also included Speck64-XTS in the patches, since it was straightforward to include, and some devices may really need that last 20-30% of performance for encryption to be feasible at all. (And when the choice is between unencrypted and a 64-bit block cipher, used in a context where the weakest points in the cryptosystem are actually elsewhere such as the user's low-entropy PIN and the flash storage doing wear-leveling, I'd certainly take the 64-bit block cipher.) So far we haven't had to use Speck64 though, and if that continues to be the case I'd be fine with Speck64 being removed, leaving just Speck128.
I would very much prefer that to be the case. As many of us know, "it's better than nothing" has been often used to justify other bad choices, like RC4, that end up preventing better ones from being adopted. At a time where we're trying to get rid of 64-bit ciphers in TLS, where data volumes per session are comparatively low, it would be unfortunate if the opposite starts happening on encryption at rest.
Quoted 12 lines
Note that in practice, to have any chance at meeting the performance requirement the cipher needed to be NEON accelerated. That made benchmarking really hard and time-consuming, since to definitely know how an algorithm performs it can take upwards of a week to implement a NEON version. It needs to be very well optimized too, to compare the algorithms fairly -- e.g. with Speck I got a 20% performance improvement on some CPUs just by changing the NEON instructions used to implement the 8-bit rotates, an optimization that is not possible with ciphers that don't use rotate amounts that are multiples of 8. (This was an intentional design choice by the Speck designers; they do know what they're doing, actually.)
Quoted 10 lines
Thus, we had to be pretty aggressive about dropping algorithms from consideration if there were preliminary indications that they wouldn't perform well, or had too little cryptanalysis, or had other issues such as an unclear patent situation. Threefish for example I did test the C implementation at
https://github.com/wernerd/Skein3Fish, but on ARM32 it was over 4 times slower than my NEON implementation of Speck128/256-XTS. And I did not see a clear way that it could be improved over 4x with NEON, if at all, so I did not take the long time it would have taken to write an optimized NEON implementation to benchmark it properly. Perhaps that was a mistake. But, time is not unlimited.In my limited experience with NEON and 64-bit ARX, there's usually a ~2x speedup solely from NEON's native 64-bit operations on ARMv7-A. The extra speedup from encrypting 2 block in parallel is then somewhere between 1x and 2x, depending on various details. Getting near 4x might be feasible, but it is indeed time-consuming to get there.
Quoted 10 lines
As for the wide-block mode using ChaCha20 and Poly1305, you'd have to ask Paul Crowley to explain it properly, but briefly it's actually a pseudorandom permutation over an arbitrarily-sized message. So with dm-crypt for example, it would operate on a whole 512-byte sector, and if any bit of the 512-byte plaintext is changed, then every bit in the 512-byte ciphertext would change with 50% probability. To make this possible, the construction uses a polynomial evalution in GF(2^130-5) as a universal hash function, similar to the Poly1305 mode.
Oh, OK, that sounds like something resembling Naor-Reingold or its relatives. That would work, but with 3 or 4 passes I guess it wouldn't be very fast.
Quoted 11 lines
Using ChaCha20's underlying 512-bit permutation to build a tweakable block cipher is an interesting idea. But maybe in my crypto-naivety, it is not obvious to me how to do so. Do you have references to any relevant papers? Remember that we strongly prefer a published cipher to a custom one -- even if the core is reused, a mistake may be made in the way it is used. Thus, similarly to Paul's wide-block mode, I'd be concerned that we'd have to self-publish a new construction, then use it with no outside crypto review. *Maybe* it would be straightforward enough to be okay, but to know I'd need to see the details of how it would actually work.
This would be the 'tweakable Even-Mansour' construction and its variants. The variant I'm most familiar with would be MEM [1], focusing on software friendliness, but there is other provable security work in the same vein, including [3, 4, 5]. It's very similar to how the XEX mode turns a block cipher into a tweakable block cipher.
In [1, 2] we used a 1024-bit permutation out of BLAKE2 instead of ChaCha20's, but everything translates easily from one to the other. We also included cheap masks for 512-bit permutations, just in case.
[1] https://eprint.iacr.org/2015/999
[2] https://github.com/MEM-AEAD/mem-aead
[3] https://eprint.iacr.org/2015/539
[4] https://eprint.iacr.org/2015/476
[5] https://competitions.cr.yp.to/round2/minalpherv11.pdfQuoted 14 lines
But in the end, Speck seemed like the clear choice because it had multiple NEON implementations available already which showed it could be implemented very efficiently in NEON; it has over 70 cryptanalysis papers (far more than most ciphers) yet the security margin is still similar to AES; it has no intellectual property concerns; there is a paper clearly explaining the design decisions; it is naturally resistant to timing attacks; it supports a 128-bit block size, so it can be easily used in XTS mode; it supports the same key sizes as AES; and it has a simple and understandable design with no "magic numbers" besides 8 and 3 (compare to an actual backdoored algorithm like
Dual_EC_DRGB, which basically had a public key embedded in the algorithm). Also as Paul mentioned he is confident in the construction, and he has published cryptanalysis on Salsa20, so his opinion is probably more significant than mine :-)Quoted 9 lines
But I will definitely take a closer look at SPARX and some of the other ciphers you mentioned in case I missed something. I really do appreciate the suggestions, by the way, and in any case we do need to be very well prepared to justify our choices. I just hope that people can understand that we are implementing real-world crypto which must operate under *very* tight performance constraints on ARM processors, and it must be compatible with dm-crypt and fscrypt with no room for ciphertext expansion. Thus, many algorithms which may at first seem reasonable choices had to (unfortunately) be excluded.
Quoted 5 lines
I understand it is a tough choice, and it's unfortunate that many of the algorithms we have cater mostly to either the high-hardware-accelerated-end or the extremely low-end, without a lot of good options at the middle-end.
First, we're planning a publication which explains our choices in more detail, so please treat this as some more preliminary notes.
To make sure we've exhausted as many alternatives as possible, I wrote NEON implementations of all the block ciphers you suggested with the exception of SKINNY (which looked very hardware-oriented and not efficient in software), as well as some that others have suggested. (It was tough, but after doing a couple, it got much easier...) The following shows the decryption performance I'm getting on an ARMv7 platform. Encryption speeds were usually similar, but in our use case we care much more about decryption, as that affects the most critical metrics such as the time to launch applications.
ChaCha8-MEM: 183256 KB/s ChaCha12-MEM: 134833 KB/s Chaskey-LTS-XTS: 99097 KB/s ChaCha20-MEM: 87875 KB/s Speck64/128-XTS: 85332 KB/s Speck128/128-XTS: 73404 KB/s RC5-128/12/256-XTS: 69887 KB/s Speck128/256-XTS: 69597 KB/s RC5-64/12/128-XTS: 69267 KB/s LEA-128-XTS: 67986 KB/s CHAM128/128-XTS: 52982 KB/s LEA-256-XTS: 50429 KB/s Threefish-256: 48349 KB/s RC6-XTS: 46855 KB/s RC5-128/20/256-XTS: 44291 KB/s RC5-64/20/128-XTS: 43924 KB/s NOEKEON-XTS: 40705 KB/s Sparx128/128-XTS: 39191 KB/s XTEA-XTS: 38239 KB/s AES-128-XTS: 25549 KB/s AES-256-XTS: 18640 KB/s
Remember that for dm-crypt or fscrypt over flash storage and/or f2fs, a stream cipher is insecure. Moreover, on these (low-end) devices the status quo is no encryption, and we need every bit of performance available. Anything below 50 MB/s is definitely unacceptable. But even at that speed we get many complaints, so in practice we need something faster. That means that the algorithms close to 50 MB/s, such as Threefish, still aren't fast enough.
ChaCha-MEM (based roughly on your paper: https://eprint.iacr.org/2015/999), has the best performance, especially if we allow for the 12 or 8-round variants. My code for it is based roughly on the existing arch/arm/crypto/chacha20-neon-core.S, but updated to support the inverse permutation (on 4 blocks at a time, using all 16 NEON registers) and do the masking required by MEM. However, ChaCha-MEM would be a pretty bleeding-edge and customized construction, and Paul Crowley and I have concerns about its security. The problem is that the MEM security proof assumes that the underlying permutation has no more detectable structural properties than a randomly selected permutation. However, the ChaCha permutation is known to have certain symmetries, e.g. if the sixteen 32-bit words are (a, a, a, a, b, b, b, b, c, c, c, c, d, d, d, d), then they always map to some (e, e, e, e, f, f, f, f, g, g, g, g, h, h, h, h).
For the MEM mask generation, we can use the "expand 32-byte k" constant to break the symmetry, like is done in the ChaCha stream cipher. However, that's not possible for the inner application of the permutation. So, we'd be using the ChaCha permutation in a manner in which it wasn't intended, and the security of the ChaCha stream cipher wouldn't directly carry over. Granted, it's not impossible that it would be secure, but at the present time it doesn't seem like a good choice to actually field.
Chaskey-LTS is faster than Speck, but unfortunately it's not really a viable option because it has only a 64-bit security level, due to its use of the Even-Mansour construction with a 128-bit key. Of course, it would still be better than nothing, but we prefer a cipher that has a security level in line with what is accepted for modern crypto.
RC5 with the traditional 12 rounds is about as fast as Speck, but there is a known differential attack on that number of rounds. So if we choose RC5 we'd almost certainly have to use the 20-round variant, which is much slower.
That leaves LEA-128-XTS as the only other algorithm that might meet the performance requirement, as it is only slightly slower than Speck128-XTS. It may be the most viable alternative, but beyond the slight performance loss it still has some disadvantages compared to Speck:
- Importantly, the LEA authors forgot to include test vectors, so I'm not yet 100% sure I implemented it correctly. (The Speck authors unfortunately didn't make the endianness of their test vectors clear in their initial publication, but at least they actually provided test vectors!)
- LEA has received some cryptanalysis, but not nearly as much as Speck.
- It took some very heavy optimization to get good LEA performance, much more than I had to do for Speck. My final LEA code has separate code paths for 128-bit and 256-bit keys, and has reordered and preprocessed the round keys, and reordered the operations. As a result, it's harder to see how it maps to the original paper. In contrast, my Speck code is more straightforward and maintainable.
- LEA-256 (256-bit key) is much slower than LEA-128 (128-bit key), as it has 33% more rounds. LEA-256 would not be fast enough, so we would have to use LEA-128. In contrast, with Speck we can use Speck128/256 (256-bit key). We're willing to accept a 128-bit security level, but 256-bit is preferable. (I think the Speck designers took a more informed approach to setting appropriate security margins for a lightweight cipher; it seems that other designers often choose too few or too many rounds, especially as the key length is varied.)
- LEA encryption is also a bit slower than decryption, while with Speck encryption and decryption are almost exactly the same speed.
Note that like Speck, LEA doesn't appear to be approved by a standards organization either; it's just specified in a research paper.
Thus, from a technical perspective, and given the current state of the art in lightweight cryptography, currently Speck128-XTS seems to be the best choice for the problem domain. It's unfortunate that there are so few good options and that the field is so politicized, but it is what it is.
Still, we don't want to abandon HPolyC (Paul's new ChaCha and Poly1305-based wide-block mode), and eventually we hope to offer it as an option as well. But it's not yet published, and it's a more complex algorithm that is harder to implement so I haven't yet had a chance to implement and benchmark it. And we don't want to continue to leave users unprotected while we spend a long time coming up with the perfect algorithm, or for hardware AES support to arrive to all low-end CPUs when it's unclear if/when that will happen.
Again, we're planning a publication which will explain all this in more detail.
Thanks!
Eric
Theodore Y. Ts'o
maintainerQuoted 7 lines · Jason A. Donenfeld
Quoted 6 lines
Note that Linux
doesn't bow down to any particular standards organization, and it offers algorithms that were specified in various places, even some with no more than a publication by the author. In fact, support for SM4 was just added too, which is a Chinese government standard. Are you going to send a patch to remove that too, or is it just NSA designed algorithms that are not okay?
Quoted 8 lines
No need to be belittling; I have much less tinfoil strapped around my head than perhaps you think. I'm not blindly opposed to government-designed algorithms. Take SHA2, for example -- built by the NSA.
But I do care quite a bit about using ciphers that have acceptance of the academic community and a large body of literature documenting its design decisions and analyzing it.....
So where is the large body of literature documenting the design decisions of SM2? Has it received as much analysis as Speck? And if not, why aren't you gunning after it?
- Ted
v2 cover crypto: Speck support
In reply to Jason A. DonenfeldQuoted 5 lines · Jason A. Donenfeld
Can we please not Speck?
It was just rejected by the ISO/IEC.
Yeah, but here was the reason given
(https://www.wikitribune.com/story/2018/04/20/internet/67004/67004/):
A source at an International Organization for Standardization (ISO) meeting of expert delegations in Wuhan, China, told WikiTribune that the U.S. delegation, including NSA officials, refused to provide the standard level of technical information to proceed.
Jeff