Commit c1c214ad authored by Zhang Zhijie's avatar Zhang Zhijie Committed by Herbert Xu

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: default avatarEric Biggers <ebiggers@google.com>
Fixes: 433cd2c6 ("crypto: rockchip - add crypto driver for rk3288")
Cc: <stable@vger.kernel.org> # v4.5+
Signed-off-by: default avatarZhang Zhijie <zhangzj@rock-chips.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 4359669a
...@@ -245,6 +245,7 @@ struct rk_cipher_ctx { ...@@ -245,6 +245,7 @@ struct rk_cipher_ctx {
struct rk_crypto_info *dev; struct rk_crypto_info *dev;
unsigned int keylen; unsigned int keylen;
u32 mode; u32 mode;
u8 iv[AES_BLOCK_SIZE];
}; };
enum alg_type { enum alg_type {
......
...@@ -242,6 +242,17 @@ static void crypto_dma_start(struct rk_crypto_info *dev) ...@@ -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) static int rk_set_data_start(struct rk_crypto_info *dev)
{ {
int err; 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); err = dev->load_data(dev, dev->sg_src, dev->sg_dst);
if (!err) if (!err)
...@@ -286,6 +297,28 @@ static void rk_iv_copyback(struct rk_crypto_info *dev) ...@@ -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); 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: /* return:
* true some err was occurred * true some err was occurred
* fault no err, continue * fault no err, continue
...@@ -307,6 +340,7 @@ static int rk_ablk_rx(struct rk_crypto_info *dev) ...@@ -307,6 +340,7 @@ static int rk_ablk_rx(struct rk_crypto_info *dev)
} }
} }
if (dev->left_bytes) { if (dev->left_bytes) {
rk_update_iv(dev);
if (dev->aligned) { if (dev->aligned) {
if (sg_is_last(dev->sg_src)) { if (sg_is_last(dev->sg_src)) {
dev_err(dev->dev, "[%s:%d] Lack of data\n", dev_err(dev->dev, "[%s:%d] Lack of data\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment