summaryrefslogtreecommitdiff
path: root/crypto/gcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/gcm.c')
-rw-r--r--crypto/gcm.c102
1 files changed, 68 insertions, 34 deletions
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 7d32d4720564..ddb4f29b2fe6 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -38,6 +38,12 @@ struct crypto_rfc4106_ctx {
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 @@ static void crypto_gcm_exit_tfm(struct crypto_aead *tfm)
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,
@@ -689,6 +704,8 @@ static int crypto_gcm_create_common(struct crypto_template *tmpl,
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 +745,9 @@ static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
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 +777,6 @@ static int crypto_gcm_base_create(struct crypto_template *tmpl,
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 +822,50 @@ static int crypto_rfc4106_setauthsize(struct crypto_aead *parent,
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 +873,9 @@ static int crypto_rfc4106_encrypt(struct aead_request *req)
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 +899,9 @@ static int crypto_rfc4106_init_tfm(struct crypto_aead *tfm)
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 +913,12 @@ static void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm)
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)
{
@@ -934,7 +972,7 @@ static int crypto_rfc4106_create(struct crypto_template *tmpl,
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_priority = alg->base.cra_priority;
inst->alg.base.cra_blocksize = 1;
inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
@@ -952,6 +990,8 @@ static int crypto_rfc4106_create(struct crypto_template *tmpl,
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 +1006,9 @@ out_free_inst:
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 +1147,15 @@ static void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm)
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)
{
@@ -1187,6 +1229,8 @@ static int crypto_rfc4543_create(struct crypto_template *tmpl,
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 +1245,9 @@ out_free_inst:
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,
};