aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/aead.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-12-12 06:23:36 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2008-01-10 16:16:51 -0500
commit5b6d2d7fdf806f2b5a9352416f9e670911fc4748 (patch)
treed2eda87839e1b5de18c691ecff6e6074a35c09f0 /crypto/aead.c
parentaedb30dc49eeecd48558b601c47e0b3f9e42c602 (diff)
[CRYPTO] aead: Add aead_geniv_alloc/aead_geniv_free
This patch creates the infrastructure to help the construction of IV generator templates that wrap around AEAD algorithms by adding an IV generator to them. This is useful for AEAD algorithms with no built-in IV generator or to replace their built-in generator. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/aead.c')
-rw-r--r--crypto/aead.c216
1 files changed, 211 insertions, 5 deletions
diff --git a/crypto/aead.c b/crypto/aead.c
index 15335ed9010a..9f7aca891926 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -12,14 +12,16 @@
12 * 12 *
13 */ 13 */
14 14
15#include <crypto/algapi.h> 15#include <crypto/internal/aead.h>
16#include <linux/errno.h> 16#include <linux/err.h>
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22 22
23#include "internal.h"
24
23static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, 25static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
24 unsigned int keylen) 26 unsigned int keylen)
25{ 27{
@@ -55,18 +57,20 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
55 57
56int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 58int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
57{ 59{
60 struct aead_tfm *crt = crypto_aead_crt(tfm);
58 int err; 61 int err;
59 62
60 if (authsize > crypto_aead_alg(tfm)->maxauthsize) 63 if (authsize > crypto_aead_alg(tfm)->maxauthsize)
61 return -EINVAL; 64 return -EINVAL;
62 65
63 if (crypto_aead_alg(tfm)->setauthsize) { 66 if (crypto_aead_alg(tfm)->setauthsize) {
64 err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); 67 err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize);
65 if (err) 68 if (err)
66 return err; 69 return err;
67 } 70 }
68 71
69 crypto_aead_crt(tfm)->authsize = authsize; 72 crypto_aead_crt(crt->base)->authsize = authsize;
73 crt->authsize = authsize;
70 return 0; 74 return 0;
71} 75}
72EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); 76EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
@@ -90,11 +94,13 @@ static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
90 if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) 94 if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
91 return -EINVAL; 95 return -EINVAL;
92 96
93 crt->setkey = setkey; 97 crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
98 alg->setkey : setkey;
94 crt->encrypt = alg->encrypt; 99 crt->encrypt = alg->encrypt;
95 crt->decrypt = alg->decrypt; 100 crt->decrypt = alg->decrypt;
96 crt->givencrypt = alg->givencrypt ?: no_givcrypt; 101 crt->givencrypt = alg->givencrypt ?: no_givcrypt;
97 crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; 102 crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
103 crt->base = __crypto_aead_cast(tfm);
98 crt->ivsize = alg->ivsize; 104 crt->ivsize = alg->ivsize;
99 crt->authsize = alg->maxauthsize; 105 crt->authsize = alg->maxauthsize;
100 106
@@ -111,6 +117,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
111 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 117 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
112 seq_printf(m, "ivsize : %u\n", aead->ivsize); 118 seq_printf(m, "ivsize : %u\n", aead->ivsize);
113 seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); 119 seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
120 seq_printf(m, "geniv : %s\n", aead->geniv ?: "<built-in>");
114} 121}
115 122
116const struct crypto_type crypto_aead_type = { 123const struct crypto_type crypto_aead_type = {
@@ -122,5 +129,204 @@ const struct crypto_type crypto_aead_type = {
122}; 129};
123EXPORT_SYMBOL_GPL(crypto_aead_type); 130EXPORT_SYMBOL_GPL(crypto_aead_type);
124 131
132static int aead_null_givencrypt(struct aead_givcrypt_request *req)
133{
134 return crypto_aead_encrypt(&req->areq);
135}
136
137static int aead_null_givdecrypt(struct aead_givcrypt_request *req)
138{
139 return crypto_aead_decrypt(&req->areq);
140}
141
142static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
143{
144 struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
145 struct aead_tfm *crt = &tfm->crt_aead;
146
147 if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
148 return -EINVAL;
149
150 crt->setkey = setkey;
151 crt->encrypt = alg->encrypt;
152 crt->decrypt = alg->decrypt;
153 if (!alg->ivsize) {
154 crt->givencrypt = aead_null_givencrypt;
155 crt->givdecrypt = aead_null_givdecrypt;
156 }
157 crt->base = __crypto_aead_cast(tfm);
158 crt->ivsize = alg->ivsize;
159 crt->authsize = alg->maxauthsize;
160
161 return 0;
162}
163
164static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
165 __attribute__ ((unused));
166static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
167{
168 struct aead_alg *aead = &alg->cra_aead;
169
170 seq_printf(m, "type : nivaead\n");
171 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
172 seq_printf(m, "ivsize : %u\n", aead->ivsize);
173 seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
174 seq_printf(m, "geniv : %s\n", aead->geniv);
175}
176
177const struct crypto_type crypto_nivaead_type = {
178 .ctxsize = crypto_aead_ctxsize,
179 .init = crypto_init_nivaead_ops,
180#ifdef CONFIG_PROC_FS
181 .show = crypto_nivaead_show,
182#endif
183};
184EXPORT_SYMBOL_GPL(crypto_nivaead_type);
185
186static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn,
187 const char *name, u32 type, u32 mask)
188{
189 struct crypto_alg *alg;
190 int err;
191
192 type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
193 type |= CRYPTO_ALG_TYPE_AEAD;
194 mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV;
195
196 alg = crypto_alg_mod_lookup(name, type, mask);
197 if (IS_ERR(alg))
198 return PTR_ERR(alg);
199
200 err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
201 crypto_mod_put(alg);
202 return err;
203}
204
205struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
206 struct rtattr **tb, u32 type,
207 u32 mask)
208{
209 const char *name;
210 struct crypto_aead_spawn *spawn;
211 struct crypto_attr_type *algt;
212 struct crypto_instance *inst;
213 struct crypto_alg *alg;
214 int err;
215
216 algt = crypto_get_attr_type(tb);
217 err = PTR_ERR(algt);
218 if (IS_ERR(algt))
219 return ERR_PTR(err);
220
221 if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) &
222 algt->mask)
223 return ERR_PTR(-EINVAL);
224
225 name = crypto_attr_alg_name(tb[1]);
226 err = PTR_ERR(name);
227 if (IS_ERR(name))
228 return ERR_PTR(err);
229
230 inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
231 if (!inst)
232 return ERR_PTR(-ENOMEM);
233
234 spawn = crypto_instance_ctx(inst);
235
236 /* Ignore async algorithms if necessary. */
237 mask |= crypto_requires_sync(algt->type, algt->mask);
238
239 crypto_set_aead_spawn(spawn, inst);
240 err = crypto_grab_nivaead(spawn, name, type, mask);
241 if (err)
242 goto err_free_inst;
243
244 alg = crypto_aead_spawn_alg(spawn);
245
246 err = -EINVAL;
247 if (!alg->cra_aead.ivsize)
248 goto err_drop_alg;
249
250 /*
251 * This is only true if we're constructing an algorithm with its
252 * default IV generator. For the default generator we elide the
253 * template name and double-check the IV generator.
254 */
255 if (algt->mask & CRYPTO_ALG_GENIV) {
256 if (strcmp(tmpl->name, alg->cra_aead.geniv))
257 goto err_drop_alg;
258
259 memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
260 memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
261 CRYPTO_MAX_ALG_NAME);
262 } else {
263 err = -ENAMETOOLONG;
264 if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
265 "%s(%s)", tmpl->name, alg->cra_name) >=
266 CRYPTO_MAX_ALG_NAME)
267 goto err_drop_alg;
268 if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
269 "%s(%s)", tmpl->name, alg->cra_driver_name) >=
270 CRYPTO_MAX_ALG_NAME)
271 goto err_drop_alg;
272 }
273
274 inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV;
275 inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
276 inst->alg.cra_priority = alg->cra_priority;
277 inst->alg.cra_blocksize = alg->cra_blocksize;
278 inst->alg.cra_alignmask = alg->cra_alignmask;
279 inst->alg.cra_type = &crypto_aead_type;
280
281 inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
282 inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
283 inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
284
285 inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
286 inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
287 inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt;
288 inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt;
289
290out:
291 return inst;
292
293err_drop_alg:
294 crypto_drop_aead(spawn);
295err_free_inst:
296 kfree(inst);
297 inst = ERR_PTR(err);
298 goto out;
299}
300EXPORT_SYMBOL_GPL(aead_geniv_alloc);
301
302void aead_geniv_free(struct crypto_instance *inst)
303{
304 crypto_drop_aead(crypto_instance_ctx(inst));
305 kfree(inst);
306}
307EXPORT_SYMBOL_GPL(aead_geniv_free);
308
309int aead_geniv_init(struct crypto_tfm *tfm)
310{
311 struct crypto_instance *inst = (void *)tfm->__crt_alg;
312 struct crypto_aead *aead;
313
314 aead = crypto_spawn_aead(crypto_instance_ctx(inst));
315 if (IS_ERR(aead))
316 return PTR_ERR(aead);
317
318 tfm->crt_aead.base = aead;
319 tfm->crt_aead.reqsize += crypto_aead_reqsize(aead);
320
321 return 0;
322}
323EXPORT_SYMBOL_GPL(aead_geniv_init);
324
325void aead_geniv_exit(struct crypto_tfm *tfm)
326{
327 crypto_free_aead(tfm->crt_aead.base);
328}
329EXPORT_SYMBOL_GPL(aead_geniv_exit);
330
125MODULE_LICENSE("GPL"); 331MODULE_LICENSE("GPL");
126MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); 332MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");