@@ -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,
@@ -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)
{
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 <herbert@gondor.apana.org.au> --- crypto/chacha_generic.c | 43 +++++++++++++++++++++++++-------------- include/crypto/internal/chacha.h | 8 ++++++- 2 files changed, 35 insertions(+), 16 deletions(-)