summaryrefslogtreecommitdiff
path: root/drivers/crypto/rockchip
diff options
context:
space:
mode:
authorZhang Zhijie <zhangzj@rock-chips.com>2019-02-13 16:24:39 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2019-02-22 12:47:26 +0800
commitc1c214adcb56d36433480c8fedf772498e7e539c (patch)
treed004bb086c251293f2c59ee96423307ff022c8f1 /drivers/crypto/rockchip
parent4359669a087633132203c52d67dd8c31e09e7b2e (diff)
crypto: rockchip - update new iv to device in multiple operations
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>
Diffstat (limited to 'drivers/crypto/rockchip')
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.h1
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c34
2 files changed, 35 insertions, 0 deletions
diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
index 417c445d8dea..54ee5b3ed9db 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.h
+++ b/drivers/crypto/rockchip/rk3288_crypto.h
@@ -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 {
diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
index fe2fc6c7b51b..02dac6ae7e53 100644
--- a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
+++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
@@ -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",