crypto: gcm - Use new IV convention
This patch converts rfc4106 to the new calling convention where
the IV is now part of the AD and needs to be skipped. This patch
also makes use of the new type-safe way of freeing instances.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 7d32d47..0c9e33b 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -38,6 +38,12 @@
u8 nonce[4];
};
+struct crypto_rfc4106_req_ctx {
+ struct scatterlist src[3];
+ struct scatterlist dst[3];
+ struct aead_request subreq;
+};
+
struct crypto_rfc4543_instance_ctx {
struct crypto_aead_spawn aead;
};
@@ -601,6 +607,15 @@
crypto_free_ablkcipher(ctx->ctr);
}
+static void crypto_gcm_free(struct aead_instance *inst)
+{
+ struct gcm_instance_ctx *ctx = aead_instance_ctx(inst);
+
+ crypto_drop_skcipher(&ctx->ctr);
+ crypto_drop_ahash(&ctx->ghash);
+ kfree(inst);
+}
+
static int crypto_gcm_create_common(struct crypto_template *tmpl,
struct rtattr **tb,
const char *full_name,
@@ -619,7 +634,8 @@
if (IS_ERR(algt))
return PTR_ERR(algt);
- if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+ if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_AEAD_NEW)) &
+ algt->mask)
return -EINVAL;
ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
@@ -674,6 +690,7 @@
inst->alg.base.cra_flags = (ghash->base.cra_flags | ctr->cra_flags) &
CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_flags |= CRYPTO_ALG_AEAD_NEW;
inst->alg.base.cra_priority = (ghash->base.cra_priority +
ctr->cra_priority) / 2;
inst->alg.base.cra_blocksize = 1;
@@ -689,6 +706,8 @@
inst->alg.encrypt = crypto_gcm_encrypt;
inst->alg.decrypt = crypto_gcm_decrypt;
+ inst->free = crypto_gcm_free;
+
err = aead_register_instance(tmpl, inst);
if (err)
goto out_put_ctr;
@@ -728,19 +747,9 @@
ctr_name, "ghash");
}
-static void crypto_gcm_free(struct crypto_instance *inst)
-{
- struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst);
-
- crypto_drop_skcipher(&ctx->ctr);
- crypto_drop_ahash(&ctx->ghash);
- kfree(aead_instance(inst));
-}
-
static struct crypto_template crypto_gcm_tmpl = {
.name = "gcm",
.create = crypto_gcm_create,
- .free = crypto_gcm_free,
.module = THIS_MODULE,
};
@@ -770,7 +779,6 @@
static struct crypto_template crypto_gcm_base_tmpl = {
.name = "gcm_base",
.create = crypto_gcm_base_create,
- .free = crypto_gcm_free,
.module = THIS_MODULE,
};
@@ -816,27 +824,50 @@
static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
{
- struct aead_request *subreq = aead_request_ctx(req);
+ struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req);
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
+ struct aead_request *subreq = &rctx->subreq;
struct crypto_aead *child = ctx->child;
+ struct scatterlist *sg;
u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
crypto_aead_alignmask(child) + 1);
+ scatterwalk_map_and_copy(iv + 12, req->src, 0, req->assoclen - 8, 0);
+
memcpy(iv, ctx->nonce, 4);
memcpy(iv + 4, req->iv, 8);
+ sg_init_table(rctx->src, 3);
+ sg_set_buf(rctx->src, iv + 12, req->assoclen - 8);
+ sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
+ if (sg != rctx->src + 1)
+ sg_chain(rctx->src, 2, sg);
+
+ if (req->src != req->dst) {
+ sg_init_table(rctx->dst, 3);
+ sg_set_buf(rctx->dst, iv + 12, req->assoclen - 8);
+ sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
+ if (sg != rctx->dst + 1)
+ sg_chain(rctx->dst, 2, sg);
+ }
+
aead_request_set_tfm(subreq, child);
aead_request_set_callback(subreq, req->base.flags, req->base.complete,
req->base.data);
- aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
- aead_request_set_ad(subreq, req->assoclen);
+ aead_request_set_crypt(subreq, rctx->src,
+ req->src == req->dst ? rctx->src : rctx->dst,
+ req->cryptlen, iv);
+ aead_request_set_ad(subreq, req->assoclen - 8);
return subreq;
}
static int crypto_rfc4106_encrypt(struct aead_request *req)
{
+ if (req->assoclen != 16 && req->assoclen != 20)
+ return -EINVAL;
+
req = crypto_rfc4106_crypt(req);
return crypto_aead_encrypt(req);
@@ -844,6 +875,9 @@
static int crypto_rfc4106_decrypt(struct aead_request *req)
{
+ if (req->assoclen != 16 && req->assoclen != 20)
+ return -EINVAL;
+
req = crypto_rfc4106_crypt(req);
return crypto_aead_decrypt(req);
@@ -867,9 +901,9 @@
align &= ~(crypto_tfm_ctx_alignment() - 1);
crypto_aead_set_reqsize(
tfm,
- sizeof(struct aead_request) +
+ sizeof(struct crypto_rfc4106_req_ctx) +
ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
- align + 12);
+ align + 24);
return 0;
}
@@ -881,6 +915,12 @@
crypto_free_aead(ctx->child);
}
+static void crypto_rfc4106_free(struct aead_instance *inst)
+{
+ crypto_drop_aead(aead_instance_ctx(inst));
+ kfree(inst);
+}
+
static int crypto_rfc4106_create(struct crypto_template *tmpl,
struct rtattr **tb)
{
@@ -895,7 +935,8 @@
if (IS_ERR(algt))
return PTR_ERR(algt);
- if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+ if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_AEAD_NEW)) &
+ algt->mask)
return -EINVAL;
ccm_name = crypto_attr_alg_name(tb[1]);
@@ -934,7 +975,8 @@
CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
- inst->alg.base.cra_flags |= alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_flags |= CRYPTO_ALG_AEAD_NEW;
inst->alg.base.cra_priority = alg->base.cra_priority;
inst->alg.base.cra_blocksize = 1;
inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
@@ -952,6 +994,8 @@
inst->alg.encrypt = crypto_rfc4106_encrypt;
inst->alg.decrypt = crypto_rfc4106_decrypt;
+ inst->free = crypto_rfc4106_free;
+
err = aead_register_instance(tmpl, inst);
if (err)
goto out_drop_alg;
@@ -966,16 +1010,9 @@
goto out;
}
-static void crypto_rfc4106_free(struct crypto_instance *inst)
-{
- crypto_drop_aead(crypto_instance_ctx(inst));
- kfree(aead_instance(inst));
-}
-
static struct crypto_template crypto_rfc4106_tmpl = {
.name = "rfc4106",
.create = crypto_rfc4106_create,
- .free = crypto_rfc4106_free,
.module = THIS_MODULE,
};
@@ -1114,6 +1151,15 @@
crypto_put_default_null_skcipher();
}
+static void crypto_rfc4543_free(struct aead_instance *inst)
+{
+ struct crypto_rfc4543_instance_ctx *ctx = aead_instance_ctx(inst);
+
+ crypto_drop_aead(&ctx->aead);
+
+ kfree(inst);
+}
+
static int crypto_rfc4543_create(struct crypto_template *tmpl,
struct rtattr **tb)
{
@@ -1129,7 +1175,8 @@
if (IS_ERR(algt))
return PTR_ERR(algt);
- if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+ if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_AEAD_NEW)) &
+ algt->mask)
return -EINVAL;
ccm_name = crypto_attr_alg_name(tb[1]);
@@ -1170,6 +1217,7 @@
goto out_drop_alg;
inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_flags |= CRYPTO_ALG_AEAD_NEW;
inst->alg.base.cra_priority = alg->base.cra_priority;
inst->alg.base.cra_blocksize = 1;
inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
@@ -1187,6 +1235,8 @@
inst->alg.encrypt = crypto_rfc4543_encrypt;
inst->alg.decrypt = crypto_rfc4543_decrypt;
+ inst->free = crypto_rfc4543_free,
+
err = aead_register_instance(tmpl, inst);
if (err)
goto out_drop_alg;
@@ -1201,19 +1251,9 @@
goto out;
}
-static void crypto_rfc4543_free(struct crypto_instance *inst)
-{
- struct crypto_rfc4543_instance_ctx *ctx = crypto_instance_ctx(inst);
-
- crypto_drop_aead(&ctx->aead);
-
- kfree(aead_instance(inst));
-}
-
static struct crypto_template crypto_rfc4543_tmpl = {
.name = "rfc4543",
.create = crypto_rfc4543_create,
- .free = crypto_rfc4543_free,
.module = THIS_MODULE,
};