diff options
Diffstat (limited to 'crypto/gcm.c')
-rw-r--r-- | crypto/gcm.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/crypto/gcm.c b/crypto/gcm.c index d539f5e56879..e70afd0c73dd 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <crypto/gf128mul.h> | 11 | #include <crypto/gf128mul.h> |
12 | #include <crypto/internal/aead.h> | ||
12 | #include <crypto/internal/skcipher.h> | 13 | #include <crypto/internal/skcipher.h> |
13 | #include <crypto/scatterwalk.h> | 14 | #include <crypto/scatterwalk.h> |
14 | #include <linux/completion.h> | 15 | #include <linux/completion.h> |
@@ -27,6 +28,11 @@ struct crypto_gcm_ctx { | |||
27 | struct gf128mul_4k *gf128; | 28 | struct gf128mul_4k *gf128; |
28 | }; | 29 | }; |
29 | 30 | ||
31 | struct crypto_rfc4106_ctx { | ||
32 | struct crypto_aead *child; | ||
33 | u8 nonce[4]; | ||
34 | }; | ||
35 | |||
30 | struct crypto_gcm_ghash_ctx { | 36 | struct crypto_gcm_ghash_ctx { |
31 | u32 bytes; | 37 | u32 bytes; |
32 | u32 flags; | 38 | u32 flags; |
@@ -240,6 +246,25 @@ out: | |||
240 | return err; | 246 | return err; |
241 | } | 247 | } |
242 | 248 | ||
249 | static int crypto_gcm_setauthsize(struct crypto_aead *tfm, | ||
250 | unsigned int authsize) | ||
251 | { | ||
252 | switch (authsize) { | ||
253 | case 4: | ||
254 | case 8: | ||
255 | case 12: | ||
256 | case 13: | ||
257 | case 14: | ||
258 | case 15: | ||
259 | case 16: | ||
260 | break; | ||
261 | default: | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
243 | static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, | 268 | static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, |
244 | struct aead_request *req, | 269 | struct aead_request *req, |
245 | unsigned int cryptlen) | 270 | unsigned int cryptlen) |
@@ -472,6 +497,7 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, | |||
472 | inst->alg.cra_init = crypto_gcm_init_tfm; | 497 | inst->alg.cra_init = crypto_gcm_init_tfm; |
473 | inst->alg.cra_exit = crypto_gcm_exit_tfm; | 498 | inst->alg.cra_exit = crypto_gcm_exit_tfm; |
474 | inst->alg.cra_aead.setkey = crypto_gcm_setkey; | 499 | inst->alg.cra_aead.setkey = crypto_gcm_setkey; |
500 | inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize; | ||
475 | inst->alg.cra_aead.encrypt = crypto_gcm_encrypt; | 501 | inst->alg.cra_aead.encrypt = crypto_gcm_encrypt; |
476 | inst->alg.cra_aead.decrypt = crypto_gcm_decrypt; | 502 | inst->alg.cra_aead.decrypt = crypto_gcm_decrypt; |
477 | 503 | ||
@@ -549,6 +575,211 @@ static struct crypto_template crypto_gcm_base_tmpl = { | |||
549 | .module = THIS_MODULE, | 575 | .module = THIS_MODULE, |
550 | }; | 576 | }; |
551 | 577 | ||
578 | static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key, | ||
579 | unsigned int keylen) | ||
580 | { | ||
581 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); | ||
582 | struct crypto_aead *child = ctx->child; | ||
583 | int err; | ||
584 | |||
585 | if (keylen < 4) | ||
586 | return -EINVAL; | ||
587 | |||
588 | keylen -= 4; | ||
589 | memcpy(ctx->nonce, key + keylen, 4); | ||
590 | |||
591 | crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); | ||
592 | crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & | ||
593 | CRYPTO_TFM_REQ_MASK); | ||
594 | err = crypto_aead_setkey(child, key, keylen); | ||
595 | crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & | ||
596 | CRYPTO_TFM_RES_MASK); | ||
597 | |||
598 | return err; | ||
599 | } | ||
600 | |||
601 | static int crypto_rfc4106_setauthsize(struct crypto_aead *parent, | ||
602 | unsigned int authsize) | ||
603 | { | ||
604 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); | ||
605 | |||
606 | switch (authsize) { | ||
607 | case 8: | ||
608 | case 12: | ||
609 | case 16: | ||
610 | break; | ||
611 | default: | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | return crypto_aead_setauthsize(ctx->child, authsize); | ||
616 | } | ||
617 | |||
618 | static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req) | ||
619 | { | ||
620 | struct aead_request *subreq = aead_request_ctx(req); | ||
621 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | ||
622 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead); | ||
623 | struct crypto_aead *child = ctx->child; | ||
624 | u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child), | ||
625 | crypto_aead_alignmask(child) + 1); | ||
626 | |||
627 | memcpy(iv, ctx->nonce, 4); | ||
628 | memcpy(iv + 4, req->iv, 8); | ||
629 | |||
630 | aead_request_set_tfm(subreq, child); | ||
631 | aead_request_set_callback(subreq, req->base.flags, req->base.complete, | ||
632 | req->base.data); | ||
633 | aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv); | ||
634 | aead_request_set_assoc(subreq, req->assoc, req->assoclen); | ||
635 | |||
636 | return subreq; | ||
637 | } | ||
638 | |||
639 | static int crypto_rfc4106_encrypt(struct aead_request *req) | ||
640 | { | ||
641 | req = crypto_rfc4106_crypt(req); | ||
642 | |||
643 | return crypto_aead_encrypt(req); | ||
644 | } | ||
645 | |||
646 | static int crypto_rfc4106_decrypt(struct aead_request *req) | ||
647 | { | ||
648 | req = crypto_rfc4106_crypt(req); | ||
649 | |||
650 | return crypto_aead_decrypt(req); | ||
651 | } | ||
652 | |||
653 | static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm) | ||
654 | { | ||
655 | struct crypto_instance *inst = (void *)tfm->__crt_alg; | ||
656 | struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst); | ||
657 | struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm); | ||
658 | struct crypto_aead *aead; | ||
659 | unsigned long align; | ||
660 | |||
661 | aead = crypto_spawn_aead(spawn); | ||
662 | if (IS_ERR(aead)) | ||
663 | return PTR_ERR(aead); | ||
664 | |||
665 | ctx->child = aead; | ||
666 | |||
667 | align = crypto_aead_alignmask(aead); | ||
668 | align &= ~(crypto_tfm_ctx_alignment() - 1); | ||
669 | tfm->crt_aead.reqsize = sizeof(struct aead_request) + | ||
670 | ALIGN(crypto_aead_reqsize(aead), | ||
671 | crypto_tfm_ctx_alignment()) + | ||
672 | align + 16; | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm) | ||
678 | { | ||
679 | struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm); | ||
680 | |||
681 | crypto_free_aead(ctx->child); | ||
682 | } | ||
683 | |||
684 | static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb) | ||
685 | { | ||
686 | struct crypto_attr_type *algt; | ||
687 | struct crypto_instance *inst; | ||
688 | struct crypto_aead_spawn *spawn; | ||
689 | struct crypto_alg *alg; | ||
690 | const char *ccm_name; | ||
691 | int err; | ||
692 | |||
693 | algt = crypto_get_attr_type(tb); | ||
694 | err = PTR_ERR(algt); | ||
695 | if (IS_ERR(algt)) | ||
696 | return ERR_PTR(err); | ||
697 | |||
698 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) | ||
699 | return ERR_PTR(-EINVAL); | ||
700 | |||
701 | ccm_name = crypto_attr_alg_name(tb[1]); | ||
702 | err = PTR_ERR(ccm_name); | ||
703 | if (IS_ERR(ccm_name)) | ||
704 | return ERR_PTR(err); | ||
705 | |||
706 | inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); | ||
707 | if (!inst) | ||
708 | return ERR_PTR(-ENOMEM); | ||
709 | |||
710 | spawn = crypto_instance_ctx(inst); | ||
711 | crypto_set_aead_spawn(spawn, inst); | ||
712 | err = crypto_grab_aead(spawn, ccm_name, 0, | ||
713 | crypto_requires_sync(algt->type, algt->mask)); | ||
714 | if (err) | ||
715 | goto out_free_inst; | ||
716 | |||
717 | alg = crypto_aead_spawn_alg(spawn); | ||
718 | |||
719 | err = -EINVAL; | ||
720 | |||
721 | /* We only support 16-byte blocks. */ | ||
722 | if (alg->cra_aead.ivsize != 16) | ||
723 | goto out_drop_alg; | ||
724 | |||
725 | /* Not a stream cipher? */ | ||
726 | if (alg->cra_blocksize != 1) | ||
727 | goto out_drop_alg; | ||
728 | |||
729 | err = -ENAMETOOLONG; | ||
730 | if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, | ||
731 | "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME || | ||
732 | snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, | ||
733 | "rfc4106(%s)", alg->cra_driver_name) >= | ||
734 | CRYPTO_MAX_ALG_NAME) | ||
735 | goto out_drop_alg; | ||
736 | |||
737 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; | ||
738 | inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; | ||
739 | inst->alg.cra_priority = alg->cra_priority; | ||
740 | inst->alg.cra_blocksize = 1; | ||
741 | inst->alg.cra_alignmask = alg->cra_alignmask; | ||
742 | inst->alg.cra_type = &crypto_nivaead_type; | ||
743 | |||
744 | inst->alg.cra_aead.ivsize = 8; | ||
745 | inst->alg.cra_aead.maxauthsize = 16; | ||
746 | |||
747 | inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx); | ||
748 | |||
749 | inst->alg.cra_init = crypto_rfc4106_init_tfm; | ||
750 | inst->alg.cra_exit = crypto_rfc4106_exit_tfm; | ||
751 | |||
752 | inst->alg.cra_aead.setkey = crypto_rfc4106_setkey; | ||
753 | inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize; | ||
754 | inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt; | ||
755 | inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt; | ||
756 | |||
757 | inst->alg.cra_aead.geniv = "seqiv"; | ||
758 | |||
759 | out: | ||
760 | return inst; | ||
761 | |||
762 | out_drop_alg: | ||
763 | crypto_drop_aead(spawn); | ||
764 | out_free_inst: | ||
765 | kfree(inst); | ||
766 | inst = ERR_PTR(err); | ||
767 | goto out; | ||
768 | } | ||
769 | |||
770 | static void crypto_rfc4106_free(struct crypto_instance *inst) | ||
771 | { | ||
772 | crypto_drop_spawn(crypto_instance_ctx(inst)); | ||
773 | kfree(inst); | ||
774 | } | ||
775 | |||
776 | static struct crypto_template crypto_rfc4106_tmpl = { | ||
777 | .name = "rfc4106", | ||
778 | .alloc = crypto_rfc4106_alloc, | ||
779 | .free = crypto_rfc4106_free, | ||
780 | .module = THIS_MODULE, | ||
781 | }; | ||
782 | |||
552 | static int __init crypto_gcm_module_init(void) | 783 | static int __init crypto_gcm_module_init(void) |
553 | { | 784 | { |
554 | int err; | 785 | int err; |
@@ -561,9 +792,15 @@ static int __init crypto_gcm_module_init(void) | |||
561 | if (err) | 792 | if (err) |
562 | goto out_undo_base; | 793 | goto out_undo_base; |
563 | 794 | ||
795 | err = crypto_register_template(&crypto_rfc4106_tmpl); | ||
796 | if (err) | ||
797 | goto out_undo_gcm; | ||
798 | |||
564 | out: | 799 | out: |
565 | return err; | 800 | return err; |
566 | 801 | ||
802 | out_undo_gcm: | ||
803 | crypto_unregister_template(&crypto_gcm_tmpl); | ||
567 | out_undo_base: | 804 | out_undo_base: |
568 | crypto_unregister_template(&crypto_gcm_base_tmpl); | 805 | crypto_unregister_template(&crypto_gcm_base_tmpl); |
569 | goto out; | 806 | goto out; |
@@ -571,6 +808,7 @@ out_undo_base: | |||
571 | 808 | ||
572 | static void __exit crypto_gcm_module_exit(void) | 809 | static void __exit crypto_gcm_module_exit(void) |
573 | { | 810 | { |
811 | crypto_unregister_template(&crypto_rfc4106_tmpl); | ||
574 | crypto_unregister_template(&crypto_gcm_tmpl); | 812 | crypto_unregister_template(&crypto_gcm_tmpl); |
575 | crypto_unregister_template(&crypto_gcm_base_tmpl); | 813 | crypto_unregister_template(&crypto_gcm_base_tmpl); |
576 | } | 814 | } |
@@ -582,3 +820,4 @@ MODULE_LICENSE("GPL"); | |||
582 | MODULE_DESCRIPTION("Galois/Counter Mode"); | 820 | MODULE_DESCRIPTION("Galois/Counter Mode"); |
583 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); | 821 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); |
584 | MODULE_ALIAS("gcm_base"); | 822 | MODULE_ALIAS("gcm_base"); |
823 | MODULE_ALIAS("rfc4106"); | ||