2020-07-28 07:19:43

by Herbert Xu

[permalink] [raw]
Subject: [v3 PATCH 10/31] crypto: chacha-generic - Add support for chaining

As it stands chacha cannot do chaining. That is, it has to handle
each request as a whole. This patch adds support for chaining when
the CRYPTO_TFM_REQ_MORE flag is set.

Signed-off-by: Herbert Xu <[email protected]>
---

crypto/chacha_generic.c | 43 +++++++++++++++++++++++++--------------
include/crypto/internal/chacha.h | 8 ++++++-
2 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/crypto/chacha_generic.c b/crypto/chacha_generic.c
index 8beea79ab1178..f74ac54d7aa5b 100644
--- a/crypto/chacha_generic.c
+++ b/crypto/chacha_generic.c
@@ -6,22 +6,21 @@
* Copyright (C) 2018 Google LLC
*/

-#include <asm/unaligned.h>
-#include <crypto/algapi.h>
#include <crypto/internal/chacha.h>
-#include <crypto/internal/skcipher.h>
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/string.h>

-static int chacha_stream_xor(struct skcipher_request *req,
- const struct chacha_ctx *ctx, const u8 *iv)
+static int chacha_stream_xor(struct skcipher_request *req, int nrounds)
{
+ struct chacha_reqctx *rctx = skcipher_request_ctx(req);
struct skcipher_walk walk;
- u32 state[16];
+ u32 *state = rctx->state;
int err;

- err = skcipher_walk_virt(&walk, req, false);
+ rctx->init = req->base.flags & CRYPTO_TFM_REQ_MORE;

- chacha_init_generic(state, ctx->key, iv);
+ err = skcipher_walk_virt(&walk, req, false);

while (walk.nbytes > 0) {
unsigned int nbytes = walk.nbytes;
@@ -30,7 +29,7 @@ static int chacha_stream_xor(struct skcipher_request *req,
nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);

chacha_crypt_generic(state, walk.dst.virt.addr,
- walk.src.virt.addr, nbytes, ctx->nrounds);
+ walk.src.virt.addr, nbytes, nrounds);
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
}

@@ -40,30 +39,41 @@ static int chacha_stream_xor(struct skcipher_request *req,
static int crypto_chacha_crypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct chacha_reqctx *rctx = skcipher_request_ctx(req);
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);

- return chacha_stream_xor(req, ctx, req->iv);
+ if (!rctx->init)
+ chacha_init_generic(rctx->state, ctx->key, req->iv);
+
+ return chacha_stream_xor(req, ctx->nrounds);
}

static int crypto_xchacha_crypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct chacha_reqctx *rctx = skcipher_request_ctx(req);
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
- struct chacha_ctx subctx;
- u32 state[16];
+ int nrounds = ctx->nrounds;
+ u32 *state = rctx->state;
u8 real_iv[16];
+ u32 key[8];
+
+ if (rctx->init)
+ goto skip_init;

/* Compute the subkey given the original key and first 128 nonce bits */
chacha_init_generic(state, ctx->key, req->iv);
- hchacha_block_generic(state, subctx.key, ctx->nrounds);
- subctx.nrounds = ctx->nrounds;
+ hchacha_block_generic(state, key, nrounds);

/* Build the real IV */
memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */

+ chacha_init_generic(state, key, real_iv);
+
+skip_init:
/* Generate the stream and XOR it with the data */
- return chacha_stream_xor(req, &subctx, real_iv);
+ return chacha_stream_xor(req, nrounds);
}

static struct skcipher_alg algs[] = {
@@ -79,6 +89,7 @@ static struct skcipher_alg algs[] = {
.max_keysize = CHACHA_KEY_SIZE,
.ivsize = CHACHA_IV_SIZE,
.chunksize = CHACHA_BLOCK_SIZE,
+ .reqsize = sizeof(struct chacha_reqctx),
.setkey = chacha20_setkey,
.encrypt = crypto_chacha_crypt,
.decrypt = crypto_chacha_crypt,
@@ -94,6 +105,7 @@ static struct skcipher_alg algs[] = {
.max_keysize = CHACHA_KEY_SIZE,
.ivsize = XCHACHA_IV_SIZE,
.chunksize = CHACHA_BLOCK_SIZE,
+ .reqsize = sizeof(struct chacha_reqctx),
.setkey = chacha20_setkey,
.encrypt = crypto_xchacha_crypt,
.decrypt = crypto_xchacha_crypt,
@@ -109,6 +121,7 @@ static struct skcipher_alg algs[] = {
.max_keysize = CHACHA_KEY_SIZE,
.ivsize = XCHACHA_IV_SIZE,
.chunksize = CHACHA_BLOCK_SIZE,
+ .reqsize = sizeof(struct chacha_reqctx),
.setkey = chacha12_setkey,
.encrypt = crypto_xchacha_crypt,
.decrypt = crypto_xchacha_crypt,
diff --git a/include/crypto/internal/chacha.h b/include/crypto/internal/chacha.h
index b085dc1ac1516..149ff90fa4afd 100644
--- a/include/crypto/internal/chacha.h
+++ b/include/crypto/internal/chacha.h
@@ -3,15 +3,21 @@
#ifndef _CRYPTO_INTERNAL_CHACHA_H
#define _CRYPTO_INTERNAL_CHACHA_H

+#include <asm/unaligned.h>
#include <crypto/chacha.h>
#include <crypto/internal/skcipher.h>
-#include <linux/crypto.h>
+#include <linux/kernel.h>

struct chacha_ctx {
u32 key[8];
int nrounds;
};

+struct chacha_reqctx {
+ u32 state[16];
+ bool init;
+};
+
static inline int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keysize, int nrounds)
{


2020-08-10 15:23:21

by Horia Geanta

[permalink] [raw]
Subject: Re: [v3 PATCH 10/31] crypto: chacha-generic - Add support for chaining

On 7/28/2020 10:19 AM, Herbert Xu wrote:
> @@ -40,30 +39,41 @@ static int chacha_stream_xor(struct skcipher_request *req,
> static int crypto_chacha_crypt(struct skcipher_request *req)
> {
> struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> + struct chacha_reqctx *rctx = skcipher_request_ctx(req);
> struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
>
> - return chacha_stream_xor(req, ctx, req->iv);
> + if (!rctx->init)
> + chacha_init_generic(rctx->state, ctx->key, req->iv);
It would probably be better to rename "init" to "no_init" or "final".

Horia

2020-08-11 00:58:32

by Herbert Xu

[permalink] [raw]
Subject: Re: [v3 PATCH 10/31] crypto: chacha-generic - Add support for chaining

On Mon, Aug 10, 2020 at 06:20:16PM +0300, Horia Geantă wrote:
> On 7/28/2020 10:19 AM, Herbert Xu wrote:
> > @@ -40,30 +39,41 @@ static int chacha_stream_xor(struct skcipher_request *req,
> > static int crypto_chacha_crypt(struct skcipher_request *req)
> > {
> > struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
> > + struct chacha_reqctx *rctx = skcipher_request_ctx(req);
> > struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
> >
> > - return chacha_stream_xor(req, ctx, req->iv);
> > + if (!rctx->init)
> > + chacha_init_generic(rctx->state, ctx->key, req->iv);
> It would probably be better to rename "init" to "no_init" or "final".

This turns out to be broken so it'll disappear anyway. It'll
be replaced with a request flag instead.

Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt