aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/authenc.c
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 /crypto/authenc.c
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>
Diffstat (limited to 'crypto/authenc.c')
-rw-r--r--crypto/authenc.c400
1 files changed, 400 insertions, 0 deletions
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");