| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Ard Biesheuvel <ardb@kernel.org> |
| Date: Fri, 8 Nov 2019 13:22:09 +0100 |
| Subject: [PATCH] crypto: x86/chacha - depend on generic chacha library instead |
| of crypto driver |
| |
| commit 28e8d89b1ce8d2e7badfb5f69971dd635acb8863 upstream. |
| |
| In preparation of extending the x86 ChaCha driver to also expose the ChaCha |
| library interface, drop the dependency on the chacha_generic crypto driver |
| as a non-SIMD fallback, and depend on the generic ChaCha library directly. |
| This way, we only pull in the code we actually need, without registering |
| a set of ChaCha skciphers that we will never use. |
| |
| Since turning the FPU on and off is cheap these days, simplify the SIMD |
| routine by dropping the per-page yield, which makes for a cleaner switch |
| to the library API as well. This also allows use to invoke the skcipher |
| walk routines in non-atomic mode. |
| |
| Signed-off-by: Ard Biesheuvel <ardb@kernel.org> |
| Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> |
| --- |
| arch/x86/crypto/chacha_glue.c | 90 ++++++++++++++--------------------- |
| crypto/Kconfig | 2 +- |
| 2 files changed, 36 insertions(+), 56 deletions(-) |
| |
| --- a/arch/x86/crypto/chacha_glue.c |
| +++ b/arch/x86/crypto/chacha_glue.c |
| @@ -123,37 +123,38 @@ static void chacha_dosimd(u32 *state, u8 |
| } |
| } |
| |
| -static int chacha_simd_stream_xor(struct skcipher_walk *walk, |
| +static int chacha_simd_stream_xor(struct skcipher_request *req, |
| const struct chacha_ctx *ctx, const u8 *iv) |
| { |
| u32 *state, state_buf[16 + 2] __aligned(8); |
| - int next_yield = 4096; /* bytes until next FPU yield */ |
| - int err = 0; |
| + struct skcipher_walk walk; |
| + int err; |
| + |
| + err = skcipher_walk_virt(&walk, req, false); |
| |
| BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); |
| state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); |
| |
| - crypto_chacha_init(state, ctx, iv); |
| + chacha_init_generic(state, ctx->key, iv); |
| |
| - while (walk->nbytes > 0) { |
| - unsigned int nbytes = walk->nbytes; |
| + while (walk.nbytes > 0) { |
| + unsigned int nbytes = walk.nbytes; |
| |
| - if (nbytes < walk->total) { |
| - nbytes = round_down(nbytes, walk->stride); |
| - next_yield -= nbytes; |
| - } |
| - |
| - chacha_dosimd(state, walk->dst.virt.addr, walk->src.virt.addr, |
| - nbytes, ctx->nrounds); |
| + if (nbytes < walk.total) |
| + nbytes = round_down(nbytes, walk.stride); |
| |
| - if (next_yield <= 0) { |
| - /* temporarily allow preemption */ |
| - kernel_fpu_end(); |
| + if (!crypto_simd_usable()) { |
| + chacha_crypt_generic(state, walk.dst.virt.addr, |
| + walk.src.virt.addr, nbytes, |
| + ctx->nrounds); |
| + } else { |
| kernel_fpu_begin(); |
| - next_yield = 4096; |
| + chacha_dosimd(state, walk.dst.virt.addr, |
| + walk.src.virt.addr, nbytes, |
| + ctx->nrounds); |
| + kernel_fpu_end(); |
| } |
| - |
| - err = skcipher_walk_done(walk, walk->nbytes - nbytes); |
| + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); |
| } |
| |
| return err; |
| @@ -163,55 +164,34 @@ static int chacha_simd(struct skcipher_r |
| { |
| struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
| struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); |
| - struct skcipher_walk walk; |
| - int err; |
| - |
| - if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) |
| - return crypto_chacha_crypt(req); |
| |
| - err = skcipher_walk_virt(&walk, req, true); |
| - if (err) |
| - return err; |
| - |
| - kernel_fpu_begin(); |
| - err = chacha_simd_stream_xor(&walk, ctx, req->iv); |
| - kernel_fpu_end(); |
| - return err; |
| + return chacha_simd_stream_xor(req, ctx, req->iv); |
| } |
| |
| static int xchacha_simd(struct skcipher_request *req) |
| { |
| struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
| struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); |
| - struct skcipher_walk walk; |
| - struct chacha_ctx subctx; |
| u32 *state, state_buf[16 + 2] __aligned(8); |
| + struct chacha_ctx subctx; |
| u8 real_iv[16]; |
| - int err; |
| - |
| - if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) |
| - return crypto_xchacha_crypt(req); |
| - |
| - err = skcipher_walk_virt(&walk, req, true); |
| - if (err) |
| - return err; |
| |
| BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); |
| state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); |
| - crypto_chacha_init(state, ctx, req->iv); |
| + chacha_init_generic(state, ctx->key, req->iv); |
| |
| - kernel_fpu_begin(); |
| - |
| - hchacha_block_ssse3(state, subctx.key, ctx->nrounds); |
| + if (req->cryptlen > CHACHA_BLOCK_SIZE && crypto_simd_usable()) { |
| + kernel_fpu_begin(); |
| + hchacha_block_ssse3(state, subctx.key, ctx->nrounds); |
| + kernel_fpu_end(); |
| + } else { |
| + hchacha_block_generic(state, subctx.key, ctx->nrounds); |
| + } |
| subctx.nrounds = ctx->nrounds; |
| |
| memcpy(&real_iv[0], req->iv + 24, 8); |
| memcpy(&real_iv[8], req->iv + 16, 8); |
| - err = chacha_simd_stream_xor(&walk, &subctx, real_iv); |
| - |
| - kernel_fpu_end(); |
| - |
| - return err; |
| + return chacha_simd_stream_xor(req, &subctx, real_iv); |
| } |
| |
| static struct skcipher_alg algs[] = { |
| @@ -227,7 +207,7 @@ static struct skcipher_alg algs[] = { |
| .max_keysize = CHACHA_KEY_SIZE, |
| .ivsize = CHACHA_IV_SIZE, |
| .chunksize = CHACHA_BLOCK_SIZE, |
| - .setkey = crypto_chacha20_setkey, |
| + .setkey = chacha20_setkey, |
| .encrypt = chacha_simd, |
| .decrypt = chacha_simd, |
| }, { |
| @@ -242,7 +222,7 @@ static struct skcipher_alg algs[] = { |
| .max_keysize = CHACHA_KEY_SIZE, |
| .ivsize = XCHACHA_IV_SIZE, |
| .chunksize = CHACHA_BLOCK_SIZE, |
| - .setkey = crypto_chacha20_setkey, |
| + .setkey = chacha20_setkey, |
| .encrypt = xchacha_simd, |
| .decrypt = xchacha_simd, |
| }, { |
| @@ -257,7 +237,7 @@ static struct skcipher_alg algs[] = { |
| .max_keysize = CHACHA_KEY_SIZE, |
| .ivsize = XCHACHA_IV_SIZE, |
| .chunksize = CHACHA_BLOCK_SIZE, |
| - .setkey = crypto_chacha12_setkey, |
| + .setkey = chacha12_setkey, |
| .encrypt = xchacha_simd, |
| .decrypt = xchacha_simd, |
| }, |
| --- a/crypto/Kconfig |
| +++ b/crypto/Kconfig |
| @@ -1417,7 +1417,7 @@ config CRYPTO_CHACHA20_X86_64 |
| tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)" |
| depends on X86 && 64BIT |
| select CRYPTO_BLKCIPHER |
| - select CRYPTO_CHACHA20 |
| + select CRYPTO_LIB_CHACHA_GENERIC |
| help |
| SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20, |
| XChaCha20, and XChaCha12 stream ciphers. |