~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/crypto/authenc.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.10 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.83 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.153 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.200 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.200 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.76 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Authenc: Simple AEAD wrapper for IPsec
  3  *
  4  * Copyright (c) 2007-2015 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/internal/aead.h>
 14 #include <crypto/internal/hash.h>
 15 #include <crypto/internal/skcipher.h>
 16 #include <crypto/authenc.h>
 17 #include <crypto/null.h>
 18 #include <crypto/scatterwalk.h>
 19 #include <linux/err.h>
 20 #include <linux/init.h>
 21 #include <linux/kernel.h>
 22 #include <linux/module.h>
 23 #include <linux/rtnetlink.h>
 24 #include <linux/slab.h>
 25 #include <linux/spinlock.h>
 26 
 27 struct authenc_instance_ctx {
 28         struct crypto_ahash_spawn auth;
 29         struct crypto_skcipher_spawn enc;
 30         unsigned int reqoff;
 31 };
 32 
 33 struct crypto_authenc_ctx {
 34         struct crypto_ahash *auth;
 35         struct crypto_skcipher *enc;
 36         struct crypto_sync_skcipher *null;
 37 };
 38 
 39 struct authenc_request_ctx {
 40         struct scatterlist src[2];
 41         struct scatterlist dst[2];
 42         char tail[];
 43 };
 44 
 45 static void authenc_request_complete(struct aead_request *req, int err)
 46 {
 47         if (err != -EINPROGRESS)
 48                 aead_request_complete(req, err);
 49 }
 50 
 51 int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
 52                                unsigned int keylen)
 53 {
 54         struct rtattr *rta = (struct rtattr *)key;
 55         struct crypto_authenc_key_param *param;
 56 
 57         if (!RTA_OK(rta, keylen))
 58                 return -EINVAL;
 59         if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
 60                 return -EINVAL;
 61 
 62         /*
 63          * RTA_OK() didn't align the rtattr's payload when validating that it
 64          * fits in the buffer.  Yet, the keys should start on the next 4-byte
 65          * aligned boundary.  To avoid confusion, require that the rtattr
 66          * payload be exactly the param struct, which has a 4-byte aligned size.
 67          */
 68         if (RTA_PAYLOAD(rta) != sizeof(*param))
 69                 return -EINVAL;
 70         BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO);
 71 
 72         param = RTA_DATA(rta);
 73         keys->enckeylen = be32_to_cpu(param->enckeylen);
 74 
 75         key += rta->rta_len;
 76         keylen -= rta->rta_len;
 77 
 78         if (keylen < keys->enckeylen)
 79                 return -EINVAL;
 80 
 81         keys->authkeylen = keylen - keys->enckeylen;
 82         keys->authkey = key;
 83         keys->enckey = key + keys->authkeylen;
 84 
 85         return 0;
 86 }
 87 EXPORT_SYMBOL_GPL(crypto_authenc_extractkeys);
 88 
 89 static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 90                                  unsigned int keylen)
 91 {
 92         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 93         struct crypto_ahash *auth = ctx->auth;
 94         struct crypto_skcipher *enc = ctx->enc;
 95         struct crypto_authenc_keys keys;
 96         int err = -EINVAL;
 97 
 98         if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
 99                 goto badkey;
100 
101         crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
102         crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) &
103                                     CRYPTO_TFM_REQ_MASK);
104         err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
105         crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) &
106                                        CRYPTO_TFM_RES_MASK);
107 
108         if (err)
109                 goto out;
110 
111         crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
112         crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc) &
113                                        CRYPTO_TFM_REQ_MASK);
114         err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
115         crypto_aead_set_flags(authenc, crypto_skcipher_get_flags(enc) &
116                                        CRYPTO_TFM_RES_MASK);
117 
118 out:
119         memzero_explicit(&keys, sizeof(keys));
120         return err;
121 
122 badkey:
123         crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
124         goto out;
125 }
126 
127 static void authenc_geniv_ahash_done(struct crypto_async_request *areq, int err)
128 {
129         struct aead_request *req = areq->data;
130         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
131         struct aead_instance *inst = aead_alg_instance(authenc);
132         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
133         struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
134         struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
135 
136         if (err)
137                 goto out;
138 
139         scatterwalk_map_and_copy(ahreq->result, req->dst,
140                                  req->assoclen + req->cryptlen,
141                                  crypto_aead_authsize(authenc), 1);
142 
143 out:
144         aead_request_complete(req, err);
145 }
146 
147 static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags)
148 {
149         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
150         struct aead_instance *inst = aead_alg_instance(authenc);
151         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
152         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
153         struct crypto_ahash *auth = ctx->auth;
154         struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
155         struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
156         u8 *hash = areq_ctx->tail;
157         int err;
158 
159         hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth),
160                            crypto_ahash_alignmask(auth) + 1);
161 
162         ahash_request_set_tfm(ahreq, auth);
163         ahash_request_set_crypt(ahreq, req->dst, hash,
164                                 req->assoclen + req->cryptlen);
165         ahash_request_set_callback(ahreq, flags,
166                                    authenc_geniv_ahash_done, req);
167 
168         err = crypto_ahash_digest(ahreq);
169         if (err)
170                 return err;
171 
172         scatterwalk_map_and_copy(hash, req->dst, req->assoclen + req->cryptlen,
173                                  crypto_aead_authsize(authenc), 1);
174 
175         return 0;
176 }
177 
178 static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
179                                         int err)
180 {
181         struct aead_request *areq = req->data;
182 
183         if (err)
184                 goto out;
185 
186         err = crypto_authenc_genicv(areq, 0);
187 
188 out:
189         authenc_request_complete(areq, err);
190 }
191 
192 static int crypto_authenc_copy_assoc(struct aead_request *req)
193 {
194         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
195         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
196         SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
197 
198         skcipher_request_set_sync_tfm(skreq, ctx->null);
199         skcipher_request_set_callback(skreq, aead_request_flags(req),
200                                       NULL, NULL);
201         skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen,
202                                    NULL);
203 
204         return crypto_skcipher_encrypt(skreq);
205 }
206 
207 static int crypto_authenc_encrypt(struct aead_request *req)
208 {
209         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
210         struct aead_instance *inst = aead_alg_instance(authenc);
211         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
212         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
213         struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
214         struct crypto_skcipher *enc = ctx->enc;
215         unsigned int cryptlen = req->cryptlen;
216         struct skcipher_request *skreq = (void *)(areq_ctx->tail +
217                                                   ictx->reqoff);
218         struct scatterlist *src, *dst;
219         int err;
220 
221         src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
222         dst = src;
223 
224         if (req->src != req->dst) {
225                 err = crypto_authenc_copy_assoc(req);
226                 if (err)
227                         return err;
228 
229                 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
230         }
231 
232         skcipher_request_set_tfm(skreq, enc);
233         skcipher_request_set_callback(skreq, aead_request_flags(req),
234                                       crypto_authenc_encrypt_done, req);
235         skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
236 
237         err = crypto_skcipher_encrypt(skreq);
238         if (err)
239                 return err;
240 
241         return crypto_authenc_genicv(req, aead_request_flags(req));
242 }
243 
244 static int crypto_authenc_decrypt_tail(struct aead_request *req,
245                                        unsigned int flags)
246 {
247         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
248         struct aead_instance *inst = aead_alg_instance(authenc);
249         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
250         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
251         struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
252         struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
253         struct skcipher_request *skreq = (void *)(areq_ctx->tail +
254                                                   ictx->reqoff);
255         unsigned int authsize = crypto_aead_authsize(authenc);
256         u8 *ihash = ahreq->result + authsize;
257         struct scatterlist *src, *dst;
258 
259         scatterwalk_map_and_copy(ihash, req->src, ahreq->nbytes, authsize, 0);
260 
261         if (crypto_memneq(ihash, ahreq->result, authsize))
262                 return -EBADMSG;
263 
264         src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
265         dst = src;
266 
267         if (req->src != req->dst)
268                 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
269 
270         skcipher_request_set_tfm(skreq, ctx->enc);
271         skcipher_request_set_callback(skreq, aead_request_flags(req),
272                                       req->base.complete, req->base.data);
273         skcipher_request_set_crypt(skreq, src, dst,
274                                    req->cryptlen - authsize, req->iv);
275 
276         return crypto_skcipher_decrypt(skreq);
277 }
278 
279 static void authenc_verify_ahash_done(struct crypto_async_request *areq,
280                                       int err)
281 {
282         struct aead_request *req = areq->data;
283 
284         if (err)
285                 goto out;
286 
287         err = crypto_authenc_decrypt_tail(req, 0);
288 
289 out:
290         authenc_request_complete(req, err);
291 }
292 
293 static int crypto_authenc_decrypt(struct aead_request *req)
294 {
295         struct crypto_aead *authenc = crypto_aead_reqtfm(req);
296         unsigned int authsize = crypto_aead_authsize(authenc);
297         struct aead_instance *inst = aead_alg_instance(authenc);
298         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
299         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
300         struct crypto_ahash *auth = ctx->auth;
301         struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
302         struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
303         u8 *hash = areq_ctx->tail;
304         int err;
305 
306         hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth),
307                            crypto_ahash_alignmask(auth) + 1);
308 
309         ahash_request_set_tfm(ahreq, auth);
310         ahash_request_set_crypt(ahreq, req->src, hash,
311                                 req->assoclen + req->cryptlen - authsize);
312         ahash_request_set_callback(ahreq, aead_request_flags(req),
313                                    authenc_verify_ahash_done, req);
314 
315         err = crypto_ahash_digest(ahreq);
316         if (err)
317                 return err;
318 
319         return crypto_authenc_decrypt_tail(req, aead_request_flags(req));
320 }
321 
322 static int crypto_authenc_init_tfm(struct crypto_aead *tfm)
323 {
324         struct aead_instance *inst = aead_alg_instance(tfm);
325         struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
326         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm);
327         struct crypto_ahash *auth;
328         struct crypto_skcipher *enc;
329         struct crypto_sync_skcipher *null;
330         int err;
331 
332         auth = crypto_spawn_ahash(&ictx->auth);
333         if (IS_ERR(auth))
334                 return PTR_ERR(auth);
335 
336         enc = crypto_spawn_skcipher(&ictx->enc);
337         err = PTR_ERR(enc);
338         if (IS_ERR(enc))
339                 goto err_free_ahash;
340 
341         null = crypto_get_default_null_skcipher();
342         err = PTR_ERR(null);
343         if (IS_ERR(null))
344                 goto err_free_skcipher;
345 
346         ctx->auth = auth;
347         ctx->enc = enc;
348         ctx->null = null;
349 
350         crypto_aead_set_reqsize(
351                 tfm,
352                 sizeof(struct authenc_request_ctx) +
353                 ictx->reqoff +
354                 max_t(unsigned int,
355                       crypto_ahash_reqsize(auth) +
356                       sizeof(struct ahash_request),
357                       sizeof(struct skcipher_request) +
358                       crypto_skcipher_reqsize(enc)));
359 
360         return 0;
361 
362 err_free_skcipher:
363         crypto_free_skcipher(enc);
364 err_free_ahash:
365         crypto_free_ahash(auth);
366         return err;
367 }
368 
369 static void crypto_authenc_exit_tfm(struct crypto_aead *tfm)
370 {
371         struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm);
372 
373         crypto_free_ahash(ctx->auth);
374         crypto_free_skcipher(ctx->enc);
375         crypto_put_default_null_skcipher();
376 }
377 
378 static void crypto_authenc_free(struct aead_instance *inst)
379 {
380         struct authenc_instance_ctx *ctx = aead_instance_ctx(inst);
381 
382         crypto_drop_skcipher(&ctx->enc);
383         crypto_drop_ahash(&ctx->auth);
384         kfree(inst);
385 }
386 
387 static int crypto_authenc_create(struct crypto_template *tmpl,
388                                  struct rtattr **tb)
389 {
390         struct crypto_attr_type *algt;
391         struct aead_instance *inst;
392         struct hash_alg_common *auth;
393         struct crypto_alg *auth_base;
394         struct skcipher_alg *enc;
395         struct authenc_instance_ctx *ctx;
396         const char *enc_name;
397         int err;
398 
399         algt = crypto_get_attr_type(tb);
400         if (IS_ERR(algt))
401                 return PTR_ERR(algt);
402 
403         if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
404                 return -EINVAL;
405 
406         auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
407                               CRYPTO_ALG_TYPE_AHASH_MASK |
408                               crypto_requires_sync(algt->type, algt->mask));
409         if (IS_ERR(auth))
410                 return PTR_ERR(auth);
411 
412         auth_base = &auth->base;
413 
414         enc_name = crypto_attr_alg_name(tb[2]);
415         err = PTR_ERR(enc_name);
416         if (IS_ERR(enc_name))
417                 goto out_put_auth;
418 
419         inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
420         err = -ENOMEM;
421         if (!inst)
422                 goto out_put_auth;
423 
424         ctx = aead_instance_ctx(inst);
425 
426         err = crypto_init_ahash_spawn(&ctx->auth, auth,
427                                       aead_crypto_instance(inst));
428         if (err)
429                 goto err_free_inst;
430 
431         crypto_set_skcipher_spawn(&ctx->enc, aead_crypto_instance(inst));
432         err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
433                                    crypto_requires_sync(algt->type,
434                                                         algt->mask));
435         if (err)
436                 goto err_drop_auth;
437 
438         enc = crypto_spawn_skcipher_alg(&ctx->enc);
439 
440         ctx->reqoff = ALIGN(2 * auth->digestsize + auth_base->cra_alignmask,
441                             auth_base->cra_alignmask + 1);
442 
443         err = -ENAMETOOLONG;
444         if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
445                      "authenc(%s,%s)", auth_base->cra_name,
446                      enc->base.cra_name) >=
447             CRYPTO_MAX_ALG_NAME)
448                 goto err_drop_enc;
449 
450         if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
451                      "authenc(%s,%s)", auth_base->cra_driver_name,
452                      enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
453                 goto err_drop_enc;
454 
455         inst->alg.base.cra_flags = (auth_base->cra_flags |
456                                     enc->base.cra_flags) & CRYPTO_ALG_ASYNC;
457         inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
458                                       auth_base->cra_priority;
459         inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
460         inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
461                                        enc->base.cra_alignmask;
462         inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
463 
464         inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
465         inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
466         inst->alg.maxauthsize = auth->digestsize;
467 
468         inst->alg.init = crypto_authenc_init_tfm;
469         inst->alg.exit = crypto_authenc_exit_tfm;
470 
471         inst->alg.setkey = crypto_authenc_setkey;
472         inst->alg.encrypt = crypto_authenc_encrypt;
473         inst->alg.decrypt = crypto_authenc_decrypt;
474 
475         inst->free = crypto_authenc_free;
476 
477         err = aead_register_instance(tmpl, inst);
478         if (err)
479                 goto err_drop_enc;
480 
481 out:
482         crypto_mod_put(auth_base);
483         return err;
484 
485 err_drop_enc:
486         crypto_drop_skcipher(&ctx->enc);
487 err_drop_auth:
488         crypto_drop_ahash(&ctx->auth);
489 err_free_inst:
490         kfree(inst);
491 out_put_auth:
492         goto out;
493 }
494 
495 static struct crypto_template crypto_authenc_tmpl = {
496         .name = "authenc",
497         .create = crypto_authenc_create,
498         .module = THIS_MODULE,
499 };
500 
501 static int __init crypto_authenc_module_init(void)
502 {
503         return crypto_register_template(&crypto_authenc_tmpl);
504 }
505 
506 static void __exit crypto_authenc_module_exit(void)
507 {
508         crypto_unregister_template(&crypto_authenc_tmpl);
509 }
510 
511 module_init(crypto_authenc_module_init);
512 module_exit(crypto_authenc_module_exit);
513 
514 MODULE_LICENSE("GPL");
515 MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec");
516 MODULE_ALIAS_CRYPTO("authenc");
517 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp