]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
crypto: rockchip - update new iv to device in multiple operations
authorZhang Zhijie <zhangzj@rock-chips.com>
Wed, 13 Feb 2019 08:24:39 +0000 (16:24 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Mar 2019 13:35:10 +0000 (14:35 +0100)
commit c1c214adcb56d36433480c8fedf772498e7e539c upstream.

For chain mode in cipher(eg. AES-CBC/DES-CBC), the iv is continuously
updated in the operation. The new iv value should be written to device
register by software.

Reported-by: Eric Biggers <ebiggers@google.com>
Fixes: 433cd2c617bf ("crypto: rockchip - add crypto driver for rk3288")
Cc: <stable@vger.kernel.org> # v4.5+
Signed-off-by: Zhang Zhijie <zhangzj@rock-chips.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/crypto/rockchip/rk3288_crypto.h
drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c

index 417c445d8dea4b8bd46b92d2da9f254239614a0a..54ee5b3ed9db8d23b13c0f34dc82d146503ec491 100644 (file)
@@ -245,6 +245,7 @@ struct rk_cipher_ctx {
        struct rk_crypto_info           *dev;
        unsigned int                    keylen;
        u32                             mode;
+       u8                              iv[AES_BLOCK_SIZE];
 };
 
 enum alg_type {
index ea5a6da054965dc8d1e53e6ddf40c135cd085f9d..23305f22072fe78f564e77ff964da2886bbdfb2c 100644 (file)
@@ -242,6 +242,17 @@ static void crypto_dma_start(struct rk_crypto_info *dev)
 static int rk_set_data_start(struct rk_crypto_info *dev)
 {
        int err;
+       struct ablkcipher_request *req =
+               ablkcipher_request_cast(dev->async_req);
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       u32 ivsize = crypto_ablkcipher_ivsize(tfm);
+       u8 *src_last_blk = page_address(sg_page(dev->sg_src)) +
+               dev->sg_src->offset + dev->sg_src->length - ivsize;
+
+       /* store the iv that need to be updated in chain mode */
+       if (ctx->mode & RK_CRYPTO_DEC)
+               memcpy(ctx->iv, src_last_blk, ivsize);
 
        err = dev->load_data(dev, dev->sg_src, dev->sg_dst);
        if (!err)
@@ -286,6 +297,28 @@ static void rk_iv_copyback(struct rk_crypto_info *dev)
                memcpy_fromio(req->info, dev->reg + RK_CRYPTO_AES_IV_0, ivsize);
 }
 
+static void rk_update_iv(struct rk_crypto_info *dev)
+{
+       struct ablkcipher_request *req =
+               ablkcipher_request_cast(dev->async_req);
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct rk_cipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       u32 ivsize = crypto_ablkcipher_ivsize(tfm);
+       u8 *new_iv = NULL;
+
+       if (ctx->mode & RK_CRYPTO_DEC) {
+               new_iv = ctx->iv;
+       } else {
+               new_iv = page_address(sg_page(dev->sg_dst)) +
+                        dev->sg_dst->offset + dev->sg_dst->length - ivsize;
+       }
+
+       if (ivsize == DES_BLOCK_SIZE)
+               memcpy_toio(dev->reg + RK_CRYPTO_TDES_IV_0, new_iv, ivsize);
+       else if (ivsize == AES_BLOCK_SIZE)
+               memcpy_toio(dev->reg + RK_CRYPTO_AES_IV_0, new_iv, ivsize);
+}
+
 /* return:
  *     true    some err was occurred
  *     fault   no err, continue
@@ -307,6 +340,7 @@ static int rk_ablk_rx(struct rk_crypto_info *dev)
                }
        }
        if (dev->left_bytes) {
+               rk_update_iv(dev);
                if (dev->aligned) {
                        if (sg_is_last(dev->sg_src)) {
                                dev_err(dev->dev, "[%s:%d] Lack of data\n",