As it stands salsa20 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/salsa20_generic.c |   20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c
index 3418869dabefd..dd4b4cc8e76b9 100644
--- a/crypto/salsa20_generic.c
+++ b/crypto/salsa20_generic.c
@@ -21,7 +21,10 @@
 
 #include <asm/unaligned.h>
 #include <crypto/internal/skcipher.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/string.h>
 
 #define SALSA20_IV_SIZE        8
 #define SALSA20_MIN_KEY_SIZE  16
@@ -32,6 +35,11 @@ struct salsa20_ctx {
        u32 initial_state[16];
 };
 
+struct salsa20_reqctx {
+       u32 state[16];
+       bool init;
+};
+
 static void salsa20_block(u32 *state, __le32 *stream)
 {
        u32 x[16];
@@ -154,13 +162,16 @@ static int salsa20_crypt(struct skcipher_request *req)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
        const struct salsa20_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct salsa20_reqctx *rctx = skcipher_request_ctx(req);
        struct skcipher_walk walk;
-       u32 state[16];
        int err;
 
        err = skcipher_walk_virt(&walk, req, false);
 
-       salsa20_init(state, ctx, req->iv);
+       if (!rctx->init)
+               salsa20_init(rctx->state, ctx, req->iv);
+
+       rctx->init = req->base.flags & CRYPTO_TFM_REQ_MORE;
 
        while (walk.nbytes > 0) {
                unsigned int nbytes = walk.nbytes;
@@ -168,8 +179,8 @@ static int salsa20_crypt(struct skcipher_request *req)
                if (nbytes < walk.total)
                        nbytes = round_down(nbytes, walk.stride);
 
-               salsa20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
-                               nbytes);
+               salsa20_docrypt(rctx->state, walk.dst.virt.addr,
+                               walk.src.virt.addr, nbytes);
                err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
        }
 
@@ -188,6 +199,7 @@ static struct skcipher_alg alg = {
        .max_keysize            = SALSA20_MAX_KEY_SIZE,
        .ivsize                 = SALSA20_IV_SIZE,
        .chunksize              = SALSA20_BLOCK_SIZE,
+       .reqsize                = sizeof(struct salsa20_reqctx),
        .setkey                 = salsa20_setkey,
        .encrypt                = salsa20_crypt,
        .decrypt                = salsa20_crypt,

Reply via email to