crypto: algif_aead - Switch to new AEAD interface

This patch makes use of the new AEAD interface which uses a single
SG list instead of separate lists for the AD and plain text.

Note that the user-space interface now requires both input and
output to be of the same length, and both must include space for
the AD as well as the authentication tag.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Herbert Xu 2015-05-27 17:24:41 +08:00
parent a3f2185a29
commit 19fa77522e

View File

@ -72,7 +72,7 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
{
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
return (ctx->used >= (ctx->aead_assoclen + (ctx->enc ? 0 : as)));
return ctx->used >= ctx->aead_assoclen + as;
}
static void aead_put_sgl(struct sock *sk)
@ -353,12 +353,8 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
unsigned bs = crypto_aead_blocksize(crypto_aead_reqtfm(&ctx->aead_req));
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
struct aead_sg_list *sgl = &ctx->tsgl;
struct scatterlist *sg = NULL;
struct scatterlist assoc[ALG_MAX_PAGES];
size_t assoclen = 0;
unsigned int i = 0;
int err = -EINVAL;
unsigned long used = 0;
@ -407,23 +403,13 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
if (!aead_sufficient_data(ctx))
goto unlock;
outlen = used;
/*
* The cipher operation input data is reduced by the associated data
* length as this data is processed separately later on.
*/
used -= ctx->aead_assoclen;
if (ctx->enc) {
/* round up output buffer to multiple of block size */
outlen = ((used + bs - 1) / bs * bs);
/* add the size needed for the auth tag to be created */
outlen += as;
} else {
/* output data size is input without the authentication tag */
outlen = used - as;
/* round up output buffer to multiple of block size */
outlen = ((outlen + bs - 1) / bs * bs);
}
used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
/* convert iovecs of output buffers into scatterlists */
while (iov_iter_count(&msg->msg_iter)) {
@ -452,47 +438,11 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
if (usedpages < outlen)
goto unlock;
sg_init_table(assoc, ALG_MAX_PAGES);
assoclen = ctx->aead_assoclen;
/*
* Split scatterlist into two: first part becomes AD, second part
* is plaintext / ciphertext. The first part is assigned to assoc
* scatterlist. When this loop finishes, sg points to the start of the
* plaintext / ciphertext.
*/
for (i = 0; i < ctx->tsgl.cur; i++) {
sg = sgl->sg + i;
if (sg->length <= assoclen) {
/* AD is larger than one page */
sg_set_page(assoc + i, sg_page(sg),
sg->length, sg->offset);
assoclen -= sg->length;
if (i >= ctx->tsgl.cur)
goto unlock;
} else if (!assoclen) {
/* current page is to start of plaintext / ciphertext */
if (i)
/* AD terminates at page boundary */
sg_mark_end(assoc + i - 1);
else
/* AD size is zero */
sg_mark_end(assoc);
break;
} else {
/* AD does not terminate at page boundary */
sg_set_page(assoc + i, sg_page(sg),
assoclen, sg->offset);
sg_mark_end(assoc + i);
/* plaintext / ciphertext starts after AD */
sg->length -= assoclen;
sg->offset += assoclen;
break;
}
}
sg_mark_end(sgl->sg + sgl->cur - 1);
aead_request_set_assoc(&ctx->aead_req, assoc, ctx->aead_assoclen);
aead_request_set_crypt(&ctx->aead_req, sg, ctx->rsgl[0].sg, used,
ctx->iv);
aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->rsgl[0].sg,
used, ctx->iv);
aead_request_set_ad(&ctx->aead_req, ctx->aead_assoclen);
err = af_alg_wait_for_completion(ctx->enc ?
crypto_aead_encrypt(&ctx->aead_req) :