]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - crypto/echainiv.c
crypto: echainiv - Copy AD along with plain text
[mirror_ubuntu-hirsute-kernel.git] / crypto / echainiv.c
index e5a9878e65325e2bc072e63d9612c05b311a94d2..02d054300a9ab84ae36e0b3c8906a9a53db41dca 100644 (file)
@@ -67,7 +67,7 @@ static int echainiv_setauthsize(struct crypto_aead *tfm,
 }
 
 /* We don't care if we get preempted and read/write IVs from the next CPU. */
-void echainiv_read_iv(u8 *dst, unsigned size)
+static void echainiv_read_iv(u8 *dst, unsigned size)
 {
        u32 *a = (u32 *)dst;
        u32 __percpu *b = echainiv_iv;
@@ -78,7 +78,7 @@ void echainiv_read_iv(u8 *dst, unsigned size)
        }
 }
 
-void echainiv_write_iv(const u8 *src, unsigned size)
+static void echainiv_write_iv(const u8 *src, unsigned size)
 {
        const u32 *a = (const u32 *)src;
        u32 __percpu *b = echainiv_iv;
@@ -167,6 +167,9 @@ static int echainiv_encrypt_compat(struct aead_request *req)
        __be64 seq;
        int err;
 
+       if (req->cryptlen < ivsize)
+               return -EINVAL;
+
        compl = req->base.complete;
        data = req->base.data;
 
@@ -212,31 +215,26 @@ static int echainiv_encrypt(struct aead_request *req)
        crypto_completion_t compl;
        void *data;
        u8 *info;
-       unsigned int ivsize;
+       unsigned int ivsize = crypto_aead_ivsize(geniv);
        int err;
 
+       if (req->cryptlen < ivsize)
+               return -EINVAL;
+
        aead_request_set_tfm(subreq, ctx->child);
 
        compl = echainiv_encrypt_complete;
        data = req;
        info = req->iv;
 
-       ivsize = crypto_aead_ivsize(geniv);
-
        if (req->src != req->dst) {
-               struct scatterlist src[2];
-               struct scatterlist dst[2];
                struct blkcipher_desc desc = {
                        .tfm = ctx->null,
                };
 
                err = crypto_blkcipher_encrypt(
-                       &desc,
-                       scatterwalk_ffwd(dst, req->dst,
-                                        req->assoclen + ivsize),
-                       scatterwalk_ffwd(src, req->src,
-                                        req->assoclen + ivsize),
-                       req->cryptlen - ivsize);
+                       &desc, req->dst, req->src,
+                       req->assoclen + req->cryptlen);
                if (err)
                        return err;
        }
@@ -255,7 +253,7 @@ static int echainiv_encrypt(struct aead_request *req)
        aead_request_set_callback(subreq, req->base.flags, compl, data);
        aead_request_set_crypt(subreq, req->dst, req->dst,
                               req->cryptlen - ivsize, info);
-       aead_request_set_ad(subreq, req->assoclen + ivsize, 0);
+       aead_request_set_ad(subreq, req->assoclen + ivsize);
 
        crypto_xor(info, ctx->salt, ivsize);
        scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
@@ -270,22 +268,28 @@ static int echainiv_decrypt_compat(struct aead_request *req)
 {
        struct crypto_aead *geniv = crypto_aead_reqtfm(req);
        struct echainiv_ctx *ctx = crypto_aead_ctx(geniv);
-       struct aead_request *subreq = aead_request_ctx(req);
+       struct echainiv_request_ctx *rctx = aead_request_ctx(req);
+       struct aead_request *subreq = &rctx->subreq.areq;
        crypto_completion_t compl;
        void *data;
-       unsigned int ivsize;
+       unsigned int ivsize = crypto_aead_ivsize(geniv);
+
+       if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
+               return -EINVAL;
 
        aead_request_set_tfm(subreq, ctx->child);
 
        compl = req->base.complete;
        data = req->base.data;
 
-       ivsize = crypto_aead_ivsize(geniv);
-
        aead_request_set_callback(subreq, req->base.flags, compl, data);
-       aead_request_set_crypt(subreq, req->src, req->dst,
+       aead_request_set_crypt(subreq,
+                              scatterwalk_ffwd(rctx->src, req->src,
+                                               req->assoclen + ivsize),
+                              scatterwalk_ffwd(rctx->dst, req->dst,
+                                               req->assoclen + ivsize),
                               req->cryptlen - ivsize, req->iv);
-       aead_request_set_ad(subreq, req->assoclen, ivsize);
+       aead_request_set_assoc(subreq, req->src, req->assoclen);
 
        scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
 
@@ -299,19 +303,20 @@ static int echainiv_decrypt(struct aead_request *req)
        struct aead_request *subreq = aead_request_ctx(req);
        crypto_completion_t compl;
        void *data;
-       unsigned int ivsize;
+       unsigned int ivsize = crypto_aead_ivsize(geniv);
+
+       if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
+               return -EINVAL;
 
        aead_request_set_tfm(subreq, ctx->child);
 
        compl = req->base.complete;
        data = req->base.data;
 
-       ivsize = crypto_aead_ivsize(geniv);
-
        aead_request_set_callback(subreq, req->base.flags, compl, data);
        aead_request_set_crypt(subreq, req->src, req->dst,
                               req->cryptlen - ivsize, req->iv);
-       aead_request_set_ad(subreq, req->assoclen + ivsize, 0);
+       aead_request_set_ad(subreq, req->assoclen + ivsize);
 
        scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
        if (req->src != req->dst)
@@ -430,26 +435,24 @@ static void echainiv_exit(struct crypto_tfm *tfm)
        crypto_put_default_null_skcipher();
 }
 
-static struct crypto_template echainiv_tmpl;
-
-static struct crypto_instance *echainiv_aead_alloc(struct rtattr **tb)
+static int echainiv_aead_create(struct crypto_template *tmpl,
+                               struct rtattr **tb)
 {
        struct aead_instance *inst;
        struct crypto_aead_spawn *spawn;
        struct aead_alg *alg;
+       int err;
 
-       inst = aead_geniv_alloc(&echainiv_tmpl, tb, 0, 0);
+       inst = aead_geniv_alloc(tmpl, tb, 0, 0);
 
        if (IS_ERR(inst))
-               goto out;
+               return PTR_ERR(inst);
 
+       err = -EINVAL;
        if (inst->alg.ivsize < sizeof(u64) ||
            inst->alg.ivsize & (sizeof(u32) - 1) ||
-           inst->alg.ivsize > MAX_IV_SIZE) {
-               aead_geniv_free(inst);
-               inst = ERR_PTR(-EINVAL);
-               goto out;
-       }
+           inst->alg.ivsize > MAX_IV_SIZE)
+               goto free_inst;
 
        spawn = aead_instance_ctx(inst);
        alg = crypto_spawn_aead_alg(spawn);
@@ -474,26 +477,32 @@ static struct crypto_instance *echainiv_aead_alloc(struct rtattr **tb)
                inst->alg.base.cra_exit = echainiv_compat_exit;
        }
 
+       err = aead_register_instance(tmpl, inst);
+       if (err)
+               goto free_inst;
+
 out:
-       return aead_crypto_instance(inst);
+       return err;
+
+free_inst:
+       aead_geniv_free(inst);
+       goto out;
 }
 
-static struct crypto_instance *echainiv_alloc(struct rtattr **tb)
+static int echainiv_create(struct crypto_template *tmpl, struct rtattr **tb)
 {
-       struct crypto_instance *inst;
        int err;
 
        err = crypto_get_default_rng();
        if (err)
-               return ERR_PTR(err);
-
-       inst = echainiv_aead_alloc(tb);
+               goto out;
 
-       if (IS_ERR(inst))
+       err = echainiv_aead_create(tmpl, tb);
+       if (err)
                goto put_rng;
 
 out:
-       return inst;
+       return err;
 
 put_rng:
        crypto_put_default_rng();
@@ -508,7 +517,7 @@ static void echainiv_free(struct crypto_instance *inst)
 
 static struct crypto_template echainiv_tmpl = {
        .name = "echainiv",
-       .alloc = echainiv_alloc,
+       .create = echainiv_create,
        .free = echainiv_free,
        .module = THIS_MODULE,
 };