]> git.baikalelectronics.ru Git - kernel.git/commitdiff
crypto: cavium/nitrox - Fix cbc ciphers self test failures
authorNagadheeraj Rottela <rnagadheeraj@marvell.com>
Tue, 17 Sep 2019 06:36:50 +0000 (06:36 +0000)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 4 Oct 2019 15:06:13 +0000 (01:06 +1000)
Self test failures are due to wrong output IV. This patch fixes this
issue by copying back output IV into skcipher request.

Signed-off-by: Nagadheeraj Rottela <rnagadheeraj@marvell.com>
Reviewed-by: Srikanth Jampala <jsrikanth@marvell.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/cavium/nitrox/nitrox_req.h
drivers/crypto/cavium/nitrox/nitrox_skcipher.c

index f69ba02c4d2561a2e1d983409ca4b42ce02549d1..12282c1b14f547fbfb9d8cf14787fd40df5e96f7 100644 (file)
@@ -10,6 +10,8 @@
 #define PENDING_SIG    0xFFFFFFFFFFFFFFFFUL
 #define PRIO 4001
 
+typedef void (*sereq_completion_t)(void *req, int err);
+
 /**
  * struct gphdr - General purpose Header
  * @param0: first parameter.
@@ -203,12 +205,14 @@ struct nitrox_crypto_ctx {
                struct flexi_crypto_context *fctx;
        } u;
        struct crypto_ctx_hdr *chdr;
+       sereq_completion_t callback;
 };
 
 struct nitrox_kcrypt_request {
        struct se_crypto_request creq;
        u8 *src;
        u8 *dst;
+       u8 *iv_out;
 };
 
 /**
index 3cdce1f0f257cf3cc454e63c63339a2de0c52272..ec3aaadc6fd7f13c78f16bef5799a3366e4aa37a 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <crypto/aes.h>
 #include <crypto/skcipher.h>
+#include <crypto/scatterwalk.h>
 #include <crypto/ctr.h>
 #include <crypto/internal/des.h>
 #include <crypto/xts.h>
@@ -47,6 +48,63 @@ static enum flexi_cipher flexi_cipher_type(const char *name)
        return cipher->value;
 }
 
+static void free_src_sglist(struct skcipher_request *skreq)
+{
+       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
+
+       kfree(nkreq->src);
+}
+
+static void free_dst_sglist(struct skcipher_request *skreq)
+{
+       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
+
+       kfree(nkreq->dst);
+}
+
+static void nitrox_skcipher_callback(void *arg, int err)
+{
+       struct skcipher_request *skreq = arg;
+
+       free_src_sglist(skreq);
+       free_dst_sglist(skreq);
+       if (err) {
+               pr_err_ratelimited("request failed status 0x%0x\n", err);
+               err = -EINVAL;
+       }
+
+       skcipher_request_complete(skreq, err);
+}
+
+static void nitrox_cbc_cipher_callback(void *arg, int err)
+{
+       struct skcipher_request *skreq = arg;
+       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
+       struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(skreq);
+       int ivsize = crypto_skcipher_ivsize(cipher);
+       unsigned int start = skreq->cryptlen - ivsize;
+
+       if (err) {
+               nitrox_skcipher_callback(arg, err);
+               return;
+       }
+
+       if (nkreq->creq.ctrl.s.arg == ENCRYPT) {
+               scatterwalk_map_and_copy(skreq->iv, skreq->dst, start, ivsize,
+                                        0);
+       } else {
+               if (skreq->src != skreq->dst) {
+                       scatterwalk_map_and_copy(skreq->iv, skreq->src, start,
+                                                ivsize, 0);
+               } else {
+                       memcpy(skreq->iv, nkreq->iv_out, ivsize);
+                       kfree(nkreq->iv_out);
+               }
+       }
+
+       nitrox_skcipher_callback(arg, err);
+}
+
 static int nitrox_skcipher_init(struct crypto_skcipher *tfm)
 {
        struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(tfm);
@@ -63,6 +121,8 @@ static int nitrox_skcipher_init(struct crypto_skcipher *tfm)
                nitrox_put_device(nctx->ndev);
                return -ENOMEM;
        }
+
+       nctx->callback = nitrox_skcipher_callback;
        nctx->chdr = chdr;
        nctx->u.ctx_handle = (uintptr_t)((u8 *)chdr->vaddr +
                                         sizeof(struct ctx_hdr));
@@ -71,6 +131,19 @@ static int nitrox_skcipher_init(struct crypto_skcipher *tfm)
        return 0;
 }
 
+static int nitrox_cbc_init(struct crypto_skcipher *tfm)
+{
+       int err;
+       struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(tfm);
+
+       err = nitrox_skcipher_init(tfm);
+       if (err)
+               return err;
+
+       nctx->callback = nitrox_cbc_cipher_callback;
+       return 0;
+}
+
 static void nitrox_skcipher_exit(struct crypto_skcipher *tfm)
 {
        struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(tfm);
@@ -173,34 +246,6 @@ static int alloc_dst_sglist(struct skcipher_request *skreq, int ivsize)
        return 0;
 }
 
-static void free_src_sglist(struct skcipher_request *skreq)
-{
-       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
-
-       kfree(nkreq->src);
-}
-
-static void free_dst_sglist(struct skcipher_request *skreq)
-{
-       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
-
-       kfree(nkreq->dst);
-}
-
-static void nitrox_skcipher_callback(void *arg, int err)
-{
-       struct skcipher_request *skreq = arg;
-
-       free_src_sglist(skreq);
-       free_dst_sglist(skreq);
-       if (err) {
-               pr_err_ratelimited("request failed status 0x%0x\n", err);
-               err = -EINVAL;
-       }
-
-       skcipher_request_complete(skreq, err);
-}
-
 static int nitrox_skcipher_crypt(struct skcipher_request *skreq, bool enc)
 {
        struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(skreq);
@@ -240,8 +285,28 @@ static int nitrox_skcipher_crypt(struct skcipher_request *skreq, bool enc)
        }
 
        /* send the crypto request */
-       return nitrox_process_se_request(nctx->ndev, creq,
-                                        nitrox_skcipher_callback, skreq);
+       return nitrox_process_se_request(nctx->ndev, creq, nctx->callback,
+                                        skreq);
+}
+
+static int nitrox_cbc_decrypt(struct skcipher_request *skreq)
+{
+       struct nitrox_kcrypt_request *nkreq = skcipher_request_ctx(skreq);
+       struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(skreq);
+       int ivsize = crypto_skcipher_ivsize(cipher);
+       gfp_t flags = (skreq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+                       GFP_KERNEL : GFP_ATOMIC;
+       unsigned int start = skreq->cryptlen - ivsize;
+
+       if (skreq->src != skreq->dst)
+               return nitrox_skcipher_crypt(skreq, false);
+
+       nkreq->iv_out = kmalloc(ivsize, flags);
+       if (!nkreq->iv_out)
+               return -ENOMEM;
+
+       scatterwalk_map_and_copy(nkreq->iv_out, skreq->src, start, ivsize, 0);
+       return nitrox_skcipher_crypt(skreq, false);
 }
 
 static int nitrox_aes_encrypt(struct skcipher_request *skreq)
@@ -340,8 +405,8 @@ static struct skcipher_alg nitrox_skciphers[] = { {
        .ivsize = AES_BLOCK_SIZE,
        .setkey = nitrox_aes_setkey,
        .encrypt = nitrox_aes_encrypt,
-       .decrypt = nitrox_aes_decrypt,
-       .init = nitrox_skcipher_init,
+       .decrypt = nitrox_cbc_decrypt,
+       .init = nitrox_cbc_init,
        .exit = nitrox_skcipher_exit,
 }, {
        .base = {
@@ -455,8 +520,8 @@ static struct skcipher_alg nitrox_skciphers[] = { {
        .ivsize = DES3_EDE_BLOCK_SIZE,
        .setkey = nitrox_3des_setkey,
        .encrypt = nitrox_3des_encrypt,
-       .decrypt = nitrox_3des_decrypt,
-       .init = nitrox_skcipher_init,
+       .decrypt = nitrox_cbc_decrypt,
+       .init = nitrox_cbc_init,
        .exit = nitrox_skcipher_exit,
 }, {
        .base = {