aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-08-30 04:24:15 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:55:43 -0400
commit3c09f17c3d11f3e98928f55b600e6de22f58017a (patch)
tree1c707e78054804fba65719a6dc87bc555fe9566b
parentb16c3a2e2c0307f5370b2b5e18bcbe1437b5f3d8 (diff)
[CRYPTO] aead: Add authenc
This patch adds the authenc algorithm which constructs an AEAD algorithm from an asynchronous block cipher and a hash. The construction is done by concatenating the encrypted result from the cipher with the output from the hash, as is used by the IPsec ESP protocol. The authenc algorithm exists as a template with four parameters: authenc(auth, authsize, enc, enckeylen). The authentication algorithm, the authentication size (i.e., truncating the output of the authentication algorithm), the encryption algorithm, and the encryption key length. Both the size field and the key length field are in bytes. For example, AES-128 with SHA1-HMAC would be represented by authenc(hmac(sha1), 12, cbc(aes), 16) The key for the authenc algorithm is the concatenation of the keys for the authentication algorithm with the encryption algorithm. For the above example, if a key of length 36 bytes is given, then hmac(sha1) would receive the first 20 bytes while the last 16 would be given to cbc(aes). Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/Kconfig8
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/algapi.c23
-rw-r--r--crypto/authenc.c400
-rw-r--r--include/crypto/algapi.h44
5 files changed, 472 insertions, 4 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index f42bc7715f48..05f46dfdf185 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -483,6 +483,14 @@ config CRYPTO_TEST
483 help 483 help
484 Quick & dirty crypto test module. 484 Quick & dirty crypto test module.
485 485
486config CRYPTO_AUTHENC
487 tristate "Authenc support"
488 select CRYPTO_AEAD
489 select CRYPTO_MANAGER
490 help
491 Authenc: Combined mode wrapper for IPsec.
492 This is required for IPSec.
493
486source "drivers/crypto/Kconfig" 494source "drivers/crypto/Kconfig"
487 495
488endif # if CRYPTO 496endif # if CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index 7e1d5b899033..da256665aae9 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_CRYPTO_SEED) += seed.o
50obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o 50obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
51obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o 51obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
52obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o 52obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
53obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
53 54
54obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o 55obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
55 56
diff --git a/crypto/algapi.c b/crypto/algapi.c
index d9559609b525..d891f56f0e8c 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -470,9 +470,8 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type)
470} 470}
471EXPORT_SYMBOL_GPL(crypto_check_attr_type); 471EXPORT_SYMBOL_GPL(crypto_check_attr_type);
472 472
473struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) 473struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
474{ 474{
475 struct rtattr *rta = tb[1];
476 struct crypto_attr_alg *alga; 475 struct crypto_attr_alg *alga;
477 476
478 if (!rta) 477 if (!rta)
@@ -487,7 +486,25 @@ struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask)
487 486
488 return crypto_alg_mod_lookup(alga->name, type, mask); 487 return crypto_alg_mod_lookup(alga->name, type, mask);
489} 488}
490EXPORT_SYMBOL_GPL(crypto_get_attr_alg); 489EXPORT_SYMBOL_GPL(crypto_attr_alg);
490
491int crypto_attr_u32(struct rtattr *rta, u32 *num)
492{
493 struct crypto_attr_u32 *nu32;
494
495 if (!rta)
496 return -ENOENT;
497 if (RTA_PAYLOAD(rta) < sizeof(*nu32))
498 return -EINVAL;
499 if (rta->rta_type != CRYPTOA_U32)
500 return -EINVAL;
501
502 nu32 = RTA_DATA(rta);
503 *num = nu32->num;
504
505 return 0;
506}
507EXPORT_SYMBOL_GPL(crypto_attr_u32);
491 508
492struct crypto_instance *crypto_alloc_instance(const char *name, 509struct crypto_instance *crypto_alloc_instance(const char *name,
493 struct crypto_alg *alg) 510 struct crypto_alg *alg)
diff --git a/crypto/authenc.c b/crypto/authenc.c
new file mode 100644
index 000000000000..86b3ac88eab7
--- /dev/null
+++ b/crypto/authenc.c
@@ -0,0 +1,400 @@
1/*
2 * Authenc: Simple AEAD wrapper for IPsec
3 *
4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 */
12
13#include <crypto/algapi.h>
14#include <linux/err.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/spinlock.h>
20
21#include "scatterwalk.h"
22
23struct authenc_instance_ctx {
24 struct crypto_spawn auth;
25 struct crypto_spawn enc;
26
27 unsigned int authsize;
28 unsigned int enckeylen;
29};
30
31struct crypto_authenc_ctx {
32 spinlock_t auth_lock;
33 struct crypto_hash *auth;
34 struct crypto_ablkcipher *enc;
35};
36
37static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
38 unsigned int keylen)
39{
40 struct authenc_instance_ctx *ictx =
41 crypto_instance_ctx(crypto_aead_alg_instance(authenc));
42 unsigned int enckeylen = ictx->enckeylen;
43 unsigned int authkeylen;
44 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
45 struct crypto_hash *auth = ctx->auth;
46 struct crypto_ablkcipher *enc = ctx->enc;
47 int err = -EINVAL;
48
49 if (keylen < enckeylen) {
50 crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
51 goto out;
52 }
53 authkeylen = keylen - enckeylen;
54
55 crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
56 crypto_hash_set_flags(auth, crypto_aead_get_flags(authenc) &
57 CRYPTO_TFM_REQ_MASK);
58 err = crypto_hash_setkey(auth, key, authkeylen);
59 crypto_aead_set_flags(authenc, crypto_hash_get_flags(auth) &
60 CRYPTO_TFM_RES_MASK);
61
62 if (err)
63 goto out;
64
65 crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
66 crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) &
67 CRYPTO_TFM_REQ_MASK);
68 err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen);
69 crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) &
70 CRYPTO_TFM_RES_MASK);
71
72out:
73 return err;
74}
75
76static int crypto_authenc_hash(struct aead_request *req)
77{
78 struct crypto_aead *authenc = crypto_aead_reqtfm(req);
79 struct authenc_instance_ctx *ictx =
80 crypto_instance_ctx(crypto_aead_alg_instance(authenc));
81 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
82 struct crypto_hash *auth = ctx->auth;
83 struct hash_desc desc = {
84 .tfm = auth,
85 };
86 u8 *hash = aead_request_ctx(req);
87 struct scatterlist *dst;
88 unsigned int cryptlen;
89 int err;
90
91 hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth),
92 crypto_hash_alignmask(auth) + 1);
93
94 spin_lock_bh(&ctx->auth_lock);
95 err = crypto_hash_init(&desc);
96 if (err)
97 goto auth_unlock;
98
99 err = crypto_hash_update(&desc, req->assoc, req->assoclen);
100 if (err)
101 goto auth_unlock;
102
103 cryptlen = req->cryptlen;
104 dst = req->dst;
105 err = crypto_hash_update(&desc, dst, cryptlen);
106 if (err)
107 goto auth_unlock;
108
109 err = crypto_hash_final(&desc, hash);
110auth_unlock:
111 spin_unlock_bh(&ctx->auth_lock);
112
113 if (err)
114 return err;
115
116 scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1);
117 return 0;
118}
119
120static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
121 int err)
122{
123 if (!err)
124 err = crypto_authenc_hash(req->data);
125
126 aead_request_complete(req->data, err);
127}
128
129static int crypto_authenc_encrypt(struct aead_request *req)
130{
131 struct crypto_aead *authenc = crypto_aead_reqtfm(req);
132 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
133 struct ablkcipher_request *abreq = aead_request_ctx(req);
134 int err;
135
136 ablkcipher_request_set_tfm(abreq, ctx->enc);
137 ablkcipher_request_set_callback(abreq, aead_request_flags(req),
138 crypto_authenc_encrypt_done, req);
139 ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
140 req->iv);
141
142 err = crypto_ablkcipher_encrypt(abreq);
143 if (err)
144 return err;
145
146 return crypto_authenc_hash(req);
147}
148
149static int crypto_authenc_verify(struct aead_request *req)
150{
151 struct crypto_aead *authenc = crypto_aead_reqtfm(req);
152 struct authenc_instance_ctx *ictx =
153 crypto_instance_ctx(crypto_aead_alg_instance(authenc));
154 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
155 struct crypto_hash *auth = ctx->auth;
156 struct hash_desc desc = {
157 .tfm = auth,
158 .flags = aead_request_flags(req),
159 };
160 u8 *ohash = aead_request_ctx(req);
161 u8 *ihash;
162 struct scatterlist *src;
163 unsigned int cryptlen;
164 unsigned int authsize;
165 int err;
166
167 ohash = (u8 *)ALIGN((unsigned long)ohash + crypto_hash_alignmask(auth),
168 crypto_hash_alignmask(auth) + 1);
169 ihash = ohash + crypto_hash_digestsize(auth);
170
171 spin_lock_bh(&ctx->auth_lock);
172 err = crypto_hash_init(&desc);
173 if (err)
174 goto auth_unlock;
175
176 err = crypto_hash_update(&desc, req->assoc, req->assoclen);
177 if (err)
178 goto auth_unlock;
179
180 cryptlen = req->cryptlen;
181 src = req->src;
182 err = crypto_hash_update(&desc, src, cryptlen);
183 if (err)
184 goto auth_unlock;
185
186 err = crypto_hash_final(&desc, ohash);
187auth_unlock:
188 spin_unlock_bh(&ctx->auth_lock);
189
190 if (err)
191 return err;
192
193 authsize = ictx->authsize;
194 scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0);
195 return memcmp(ihash, ohash, authsize) ? -EINVAL : 0;
196}
197
198static void crypto_authenc_decrypt_done(struct crypto_async_request *req,
199 int err)
200{
201 aead_request_complete(req->data, err);
202}
203
204static int crypto_authenc_decrypt(struct aead_request *req)
205{
206 struct crypto_aead *authenc = crypto_aead_reqtfm(req);
207 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
208 struct ablkcipher_request *abreq = aead_request_ctx(req);
209 int err;
210
211 err = crypto_authenc_verify(req);
212 if (err)
213 return err;
214
215 ablkcipher_request_set_tfm(abreq, ctx->enc);
216 ablkcipher_request_set_callback(abreq, aead_request_flags(req),
217 crypto_authenc_decrypt_done, req);
218 ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
219 req->iv);
220
221 return crypto_ablkcipher_decrypt(abreq);
222}
223
224static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
225{
226 struct crypto_instance *inst = (void *)tfm->__crt_alg;
227 struct authenc_instance_ctx *ictx = crypto_instance_ctx(inst);
228 struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
229 struct crypto_hash *auth;
230 struct crypto_ablkcipher *enc;
231 unsigned int digestsize;
232 int err;
233
234 auth = crypto_spawn_hash(&ictx->auth);
235 if (IS_ERR(auth))
236 return PTR_ERR(auth);
237
238 err = -EINVAL;
239 digestsize = crypto_hash_digestsize(auth);
240 if (ictx->authsize > digestsize)
241 goto err_free_hash;
242
243 enc = crypto_spawn_ablkcipher(&ictx->enc);
244 err = PTR_ERR(enc);
245 if (IS_ERR(enc))
246 goto err_free_hash;
247
248 ctx->auth = auth;
249 ctx->enc = enc;
250 tfm->crt_aead.reqsize = max_t(unsigned int,
251 (crypto_hash_alignmask(auth) &
252 ~(crypto_tfm_ctx_alignment() - 1)) +
253 digestsize * 2,
254 sizeof(struct ablkcipher_request) +
255 crypto_ablkcipher_reqsize(enc));
256
257 spin_lock_init(&ctx->auth_lock);
258
259 return 0;
260
261err_free_hash:
262 crypto_free_hash(auth);
263 return err;
264}
265
266static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm)
267{
268 struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
269
270 crypto_free_hash(ctx->auth);
271 crypto_free_ablkcipher(ctx->enc);
272}
273
274static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
275{
276 struct crypto_instance *inst;
277 struct crypto_alg *auth;
278 struct crypto_alg *enc;
279 struct authenc_instance_ctx *ctx;
280 unsigned int authsize;
281 unsigned int enckeylen;
282 int err;
283
284 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD);
285 if (err)
286 return ERR_PTR(err);
287
288 auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
289 CRYPTO_ALG_TYPE_HASH_MASK);
290 if (IS_ERR(auth))
291 return ERR_PTR(PTR_ERR(auth));
292
293 err = crypto_attr_u32(tb[2], &authsize);
294 inst = ERR_PTR(err);
295 if (err)
296 goto out_put_auth;
297
298 enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER,
299 CRYPTO_ALG_TYPE_MASK);
300 inst = ERR_PTR(PTR_ERR(enc));
301 if (IS_ERR(enc))
302 goto out_put_auth;
303
304 err = crypto_attr_u32(tb[4], &enckeylen);
305 if (err)
306 goto out_put_enc;
307
308 inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
309 err = -ENOMEM;
310 if (!inst)
311 goto out_put_enc;
312
313 err = -ENAMETOOLONG;
314 if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
315 "authenc(%s, %u, %s, %u)", auth->cra_name, authsize,
316 enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME)
317 goto err_free_inst;
318
319 if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
320 "authenc(%s, %u, %s, %u)", auth->cra_driver_name,
321 authsize, enc->cra_driver_name, enckeylen) >=
322 CRYPTO_MAX_ALG_NAME)
323 goto err_free_inst;
324
325 ctx = crypto_instance_ctx(inst);
326 ctx->authsize = authsize;
327 ctx->enckeylen = enckeylen;
328
329 err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
330 if (err)
331 goto err_free_inst;
332
333 err = crypto_init_spawn(&ctx->enc, enc, inst, CRYPTO_ALG_TYPE_MASK);
334 if (err)
335 goto err_drop_auth;
336
337 inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
338 inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
339 inst->alg.cra_blocksize = enc->cra_blocksize;
340 inst->alg.cra_alignmask = max(auth->cra_alignmask, enc->cra_alignmask);
341 inst->alg.cra_type = &crypto_aead_type;
342
343 inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize;
344 inst->alg.cra_aead.authsize = authsize;
345
346 inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
347
348 inst->alg.cra_init = crypto_authenc_init_tfm;
349 inst->alg.cra_exit = crypto_authenc_exit_tfm;
350
351 inst->alg.cra_aead.setkey = crypto_authenc_setkey;
352 inst->alg.cra_aead.encrypt = crypto_authenc_encrypt;
353 inst->alg.cra_aead.decrypt = crypto_authenc_decrypt;
354
355out:
356 crypto_mod_put(enc);
357out_put_auth:
358 crypto_mod_put(auth);
359 return inst;
360
361err_drop_auth:
362 crypto_drop_spawn(&ctx->auth);
363err_free_inst:
364 kfree(inst);
365out_put_enc:
366 inst = ERR_PTR(err);
367 goto out;
368}
369
370static void crypto_authenc_free(struct crypto_instance *inst)
371{
372 struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
373
374 crypto_drop_spawn(&ctx->enc);
375 crypto_drop_spawn(&ctx->auth);
376 kfree(inst);
377}
378
379static struct crypto_template crypto_authenc_tmpl = {
380 .name = "authenc",
381 .alloc = crypto_authenc_alloc,
382 .free = crypto_authenc_free,
383 .module = THIS_MODULE,
384};
385
386static int __init crypto_authenc_module_init(void)
387{
388 return crypto_register_template(&crypto_authenc_tmpl);
389}
390
391static void __exit crypto_authenc_module_exit(void)
392{
393 crypto_unregister_template(&crypto_authenc_tmpl);
394}
395
396module_init(crypto_authenc_module_init);
397module_exit(crypto_authenc_module_exit);
398
399MODULE_LICENSE("GPL");
400MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec");
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index cd721a7ce78f..4af72dc21202 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -112,7 +112,8 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
112 112
113struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); 113struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
114int crypto_check_attr_type(struct rtattr **tb, u32 type); 114int crypto_check_attr_type(struct rtattr **tb, u32 type);
115struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask); 115struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask);
116int crypto_attr_u32(struct rtattr *rta, u32 *num);
116struct crypto_instance *crypto_alloc_instance(const char *name, 117struct crypto_instance *crypto_alloc_instance(const char *name,
117 struct crypto_alg *alg); 118 struct crypto_alg *alg);
118 119
@@ -171,6 +172,26 @@ static inline struct aead_alg *crypto_aead_alg(struct crypto_aead *tfm)
171 return &crypto_aead_tfm(tfm)->__crt_alg->cra_aead; 172 return &crypto_aead_tfm(tfm)->__crt_alg->cra_aead;
172} 173}
173 174
175static inline void *crypto_aead_ctx(struct crypto_aead *tfm)
176{
177 return crypto_tfm_ctx(&tfm->base);
178}
179
180static inline struct crypto_instance *crypto_aead_alg_instance(
181 struct crypto_aead *aead)
182{
183 return crypto_tfm_alg_instance(&aead->base);
184}
185
186static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher(
187 struct crypto_spawn *spawn)
188{
189 u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
190 u32 mask = CRYPTO_ALG_TYPE_MASK;
191
192 return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
193}
194
174static inline struct crypto_blkcipher *crypto_spawn_blkcipher( 195static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
175 struct crypto_spawn *spawn) 196 struct crypto_spawn *spawn)
176{ 197{
@@ -257,5 +278,26 @@ static inline int ablkcipher_tfm_in_queue(struct crypto_queue *queue,
257 return crypto_tfm_in_queue(queue, crypto_ablkcipher_tfm(tfm)); 278 return crypto_tfm_in_queue(queue, crypto_ablkcipher_tfm(tfm));
258} 279}
259 280
281static inline void *aead_request_ctx(struct aead_request *req)
282{
283 return req->__ctx;
284}
285
286static inline void aead_request_complete(struct aead_request *req, int err)
287{
288 req->base.complete(&req->base, err);
289}
290
291static inline u32 aead_request_flags(struct aead_request *req)
292{
293 return req->base.flags;
294}
295
296static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb,
297 u32 type, u32 mask)
298{
299 return crypto_attr_alg(tb[1], type, mask);
300}
301
260#endif /* _CRYPTO_ALGAPI_H */ 302#endif /* _CRYPTO_ALGAPI_H */
261 303