Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

Linux/crypto/echainiv.c

  1 /*
  2  * echainiv: Encrypted Chain IV Generator
  3  *
  4  * This generator generates an IV based on a sequence number by multiplying
  5  * it with a salt and then encrypting it with the same key as used to encrypt
  6  * the plain text.  This algorithm requires that the block size be equal
  7  * to the IV size.  It is mainly useful for CBC.
  8  *
  9  * This generator can only be used by algorithms where authentication
 10  * is performed after encryption (i.e., authenc).
 11  *
 12  * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
 13  *
 14  * This program is free software; you can redistribute it and/or modify it
 15  * under the terms of the GNU General Public License as published by the Free
 16  * Software Foundation; either version 2 of the License, or (at your option)
 17  * any later version.
 18  *
 19  */
 20 
 21 #include <crypto/internal/geniv.h>
 22 #include <crypto/scatterwalk.h>
 23 #include <crypto/skcipher.h>
 24 #include <linux/err.h>
 25 #include <linux/init.h>
 26 #include <linux/kernel.h>
 27 #include <linux/module.h>
 28 #include <linux/slab.h>
 29 #include <linux/string.h>
 30 
 31 static int echainiv_encrypt(struct aead_request *req)
 32 {
 33         struct crypto_aead *geniv = crypto_aead_reqtfm(req);
 34         struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
 35         struct aead_request *subreq = aead_request_ctx(req);
 36         __be64 nseqno;
 37         u64 seqno;
 38         u8 *info;
 39         unsigned int ivsize = crypto_aead_ivsize(geniv);
 40         int err;
 41 
 42         if (req->cryptlen < ivsize)
 43                 return -EINVAL;
 44 
 45         aead_request_set_tfm(subreq, ctx->child);
 46 
 47         info = req->iv;
 48 
 49         if (req->src != req->dst) {
 50                 SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
 51 
 52                 skcipher_request_set_tfm(nreq, ctx->sknull);
 53                 skcipher_request_set_callback(nreq, req->base.flags,
 54                                               NULL, NULL);
 55                 skcipher_request_set_crypt(nreq, req->src, req->dst,
 56                                            req->assoclen + req->cryptlen,
 57                                            NULL);
 58 
 59                 err = crypto_skcipher_encrypt(nreq);
 60                 if (err)
 61                         return err;
 62         }
 63 
 64         aead_request_set_callback(subreq, req->base.flags,
 65                                   req->base.complete, req->base.data);
 66         aead_request_set_crypt(subreq, req->dst, req->dst,
 67                                req->cryptlen, info);
 68         aead_request_set_ad(subreq, req->assoclen);
 69 
 70         memcpy(&nseqno, info + ivsize - 8, 8);
 71         seqno = be64_to_cpu(nseqno);
 72         memset(info, 0, ivsize);
 73 
 74         scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
 75 
 76         do {
 77                 u64 a;
 78 
 79                 memcpy(&a, ctx->salt + ivsize - 8, 8);
 80 
 81                 a |= 1;
 82                 a *= seqno;
 83 
 84                 memcpy(info + ivsize - 8, &a, 8);
 85         } while ((ivsize -= 8));
 86 
 87         return crypto_aead_encrypt(subreq);
 88 }
 89 
 90 static int echainiv_decrypt(struct aead_request *req)
 91 {
 92         struct crypto_aead *geniv = crypto_aead_reqtfm(req);
 93         struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
 94         struct aead_request *subreq = aead_request_ctx(req);
 95         crypto_completion_t compl;
 96         void *data;
 97         unsigned int ivsize = crypto_aead_ivsize(geniv);
 98 
 99         if (req->cryptlen < ivsize)
100                 return -EINVAL;
101 
102         aead_request_set_tfm(subreq, ctx->child);
103 
104         compl = req->base.complete;
105         data = req->base.data;
106 
107         aead_request_set_callback(subreq, req->base.flags, compl, data);
108         aead_request_set_crypt(subreq, req->src, req->dst,
109                                req->cryptlen - ivsize, req->iv);
110         aead_request_set_ad(subreq, req->assoclen + ivsize);
111 
112         scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
113 
114         return crypto_aead_decrypt(subreq);
115 }
116 
117 static int echainiv_aead_create(struct crypto_template *tmpl,
118                                 struct rtattr **tb)
119 {
120         struct aead_instance *inst;
121         struct crypto_aead_spawn *spawn;
122         struct aead_alg *alg;
123         int err;
124 
125         inst = aead_geniv_alloc(tmpl, tb, 0, 0);
126 
127         if (IS_ERR(inst))
128                 return PTR_ERR(inst);
129 
130         spawn = aead_instance_ctx(inst);
131         alg = crypto_spawn_aead_alg(spawn);
132 
133         err = -EINVAL;
134         if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize)
135                 goto free_inst;
136 
137         inst->alg.encrypt = echainiv_encrypt;
138         inst->alg.decrypt = echainiv_decrypt;
139 
140         inst->alg.init = aead_init_geniv;
141         inst->alg.exit = aead_exit_geniv;
142 
143         inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
144         inst->alg.base.cra_ctxsize += inst->alg.ivsize;
145 
146         inst->free = aead_geniv_free;
147 
148         err = aead_register_instance(tmpl, inst);
149         if (err)
150                 goto free_inst;
151 
152 out:
153         return err;
154 
155 free_inst:
156         aead_geniv_free(inst);
157         goto out;
158 }
159 
160 static void echainiv_free(struct crypto_instance *inst)
161 {
162         aead_geniv_free(aead_instance(inst));
163 }
164 
165 static struct crypto_template echainiv_tmpl = {
166         .name = "echainiv",
167         .create = echainiv_aead_create,
168         .free = echainiv_free,
169         .module = THIS_MODULE,
170 };
171 
172 static int __init echainiv_module_init(void)
173 {
174         return crypto_register_template(&echainiv_tmpl);
175 }
176 
177 static void __exit echainiv_module_exit(void)
178 {
179         crypto_unregister_template(&echainiv_tmpl);
180 }
181 
182 module_init(echainiv_module_init);
183 module_exit(echainiv_module_exit);
184 
185 MODULE_LICENSE("GPL");
186 MODULE_DESCRIPTION("Encrypted Chain IV Generator");
187 MODULE_ALIAS_CRYPTO("echainiv");
188 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us