forked from Minki/linux
crypto: atmel-aes - properly set IV after {en,de}crypt
Certain cipher modes like CTS expect the IV (req->info) of ablkcipher_request (or equivalently req->iv of skcipher_request) to contain the last ciphertext block when the {en,de}crypt operation is done. Fix this issue for the Atmel AES hardware engine. The tcrypt test case for cts(cbc(aes)) is now correctly passed. In the case of in-place decryption, copy the ciphertext in an intermediate buffer before decryption. Signed-off-by: Romain Izard <romain.izard.pro@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
142a27f0a7
commit
91308019ec
@ -111,6 +111,7 @@ struct atmel_aes_base_ctx {
|
||||
int keylen;
|
||||
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
|
||||
u16 block_size;
|
||||
bool is_aead;
|
||||
};
|
||||
|
||||
struct atmel_aes_ctx {
|
||||
@ -157,6 +158,7 @@ struct atmel_aes_authenc_ctx {
|
||||
|
||||
struct atmel_aes_reqctx {
|
||||
unsigned long mode;
|
||||
u32 lastc[AES_BLOCK_SIZE / sizeof(u32)];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
|
||||
@ -498,12 +500,34 @@ static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
|
||||
static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
|
||||
{
|
||||
#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
|
||||
atmel_aes_authenc_complete(dd, err);
|
||||
if (dd->ctx->is_aead)
|
||||
atmel_aes_authenc_complete(dd, err);
|
||||
#endif
|
||||
|
||||
clk_disable(dd->iclk);
|
||||
dd->flags &= ~AES_FLAGS_BUSY;
|
||||
|
||||
if (!dd->ctx->is_aead) {
|
||||
struct ablkcipher_request *req =
|
||||
ablkcipher_request_cast(dd->areq);
|
||||
struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
struct crypto_ablkcipher *ablkcipher =
|
||||
crypto_ablkcipher_reqtfm(req);
|
||||
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
|
||||
if (rctx->mode & AES_FLAGS_ENCRYPT) {
|
||||
scatterwalk_map_and_copy(req->info, req->dst,
|
||||
req->nbytes - ivsize, ivsize, 0);
|
||||
} else {
|
||||
if (req->src == req->dst) {
|
||||
memcpy(req->info, rctx->lastc, ivsize);
|
||||
} else {
|
||||
scatterwalk_map_and_copy(req->info, req->src,
|
||||
req->nbytes - ivsize, ivsize, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dd->is_async)
|
||||
dd->areq->complete(dd->areq, err);
|
||||
|
||||
@ -1072,11 +1096,11 @@ static int atmel_aes_ctr_start(struct atmel_aes_dev *dd)
|
||||
|
||||
static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
|
||||
{
|
||||
struct atmel_aes_base_ctx *ctx;
|
||||
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
|
||||
struct atmel_aes_base_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
|
||||
struct atmel_aes_reqctx *rctx;
|
||||
struct atmel_aes_dev *dd;
|
||||
|
||||
ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
|
||||
switch (mode & AES_FLAGS_OPMODE_MASK) {
|
||||
case AES_FLAGS_CFB8:
|
||||
ctx->block_size = CFB8_BLOCK_SIZE;
|
||||
@ -1098,6 +1122,7 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
|
||||
ctx->block_size = AES_BLOCK_SIZE;
|
||||
break;
|
||||
}
|
||||
ctx->is_aead = false;
|
||||
|
||||
dd = atmel_aes_find_dev(ctx);
|
||||
if (!dd)
|
||||
@ -1106,6 +1131,13 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
|
||||
rctx = ablkcipher_request_ctx(req);
|
||||
rctx->mode = mode;
|
||||
|
||||
if (!(mode & AES_FLAGS_ENCRYPT) && (req->src == req->dst)) {
|
||||
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
|
||||
scatterwalk_map_and_copy(rctx->lastc, req->src,
|
||||
(req->nbytes - ivsize), ivsize, 0);
|
||||
}
|
||||
|
||||
return atmel_aes_handle_queue(dd, &req->base);
|
||||
}
|
||||
|
||||
@ -1740,6 +1772,7 @@ static int atmel_aes_gcm_crypt(struct aead_request *req,
|
||||
|
||||
ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
|
||||
ctx->block_size = AES_BLOCK_SIZE;
|
||||
ctx->is_aead = true;
|
||||
|
||||
dd = atmel_aes_find_dev(ctx);
|
||||
if (!dd)
|
||||
@ -2224,6 +2257,7 @@ static int atmel_aes_authenc_crypt(struct aead_request *req,
|
||||
|
||||
rctx->base.mode = mode;
|
||||
ctx->block_size = AES_BLOCK_SIZE;
|
||||
ctx->is_aead = true;
|
||||
|
||||
dd = atmel_aes_find_dev(ctx);
|
||||
if (!dd)
|
||||
|
Loading…
Reference in New Issue
Block a user