diff options
| -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"); | ||
