Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: aesni - refactor scatterlist processing

Currently, the gcm(aes-ni) driver open codes the scatterlist handling
that is encapsulated by the skcipher walk API. So let's switch to that
instead.

Also, move the handling at the end of gcmaes_crypt_by_sg() that is
dependent on whether we are encrypting or decrypting into the callers,
which always do one or the other.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Ard Biesheuvel and committed by
Herbert Xu
83c83e65 2694e23f

+56 -83
+56 -83
arch/x86/crypto/aesni-intel_glue.c
··· 638 638 639 639 static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req, 640 640 unsigned int assoclen, u8 *hash_subkey, 641 - u8 *iv, void *aes_ctx) 641 + u8 *iv, void *aes_ctx, u8 *auth_tag, 642 + unsigned long auth_tag_len) 642 643 { 643 - struct crypto_aead *tfm = crypto_aead_reqtfm(req); 644 - unsigned long auth_tag_len = crypto_aead_authsize(tfm); 645 644 const struct aesni_gcm_tfm_s *gcm_tfm = aesni_gcm_tfm; 646 645 u8 databuf[sizeof(struct gcm_context_data) + (AESNI_ALIGN - 8)] __aligned(8); 647 646 struct gcm_context_data *data = PTR_ALIGN((void *)databuf, AESNI_ALIGN); 648 - struct scatter_walk dst_sg_walk = {}; 649 647 unsigned long left = req->cryptlen; 650 - unsigned long len, srclen, dstlen; 651 648 struct scatter_walk assoc_sg_walk; 652 - struct scatter_walk src_sg_walk; 653 - struct scatterlist src_start[2]; 654 - struct scatterlist dst_start[2]; 655 - struct scatterlist *src_sg; 656 - struct scatterlist *dst_sg; 657 - u8 *src, *dst, *assoc; 649 + struct skcipher_walk walk; 658 650 u8 *assocmem = NULL; 659 - u8 authTag[16]; 651 + u8 *assoc; 652 + int err; 660 653 661 654 if (!enc) 662 655 left -= auth_tag_len; ··· 676 683 scatterwalk_map_and_copy(assoc, req->src, 0, assoclen, 0); 677 684 } 678 685 679 - if (left) { 680 - src_sg = scatterwalk_ffwd(src_start, req->src, req->assoclen); 681 - scatterwalk_start(&src_sg_walk, src_sg); 682 - if (req->src != req->dst) { 683 - dst_sg = scatterwalk_ffwd(dst_start, req->dst, 684 - req->assoclen); 685 - scatterwalk_start(&dst_sg_walk, dst_sg); 686 - } 687 - } 688 - 689 686 kernel_fpu_begin(); 690 687 gcm_tfm->init(aes_ctx, data, iv, hash_subkey, assoc, assoclen); 691 - if (req->src != req->dst) { 692 - while (left) { 693 - src = scatterwalk_map(&src_sg_walk); 694 - dst = scatterwalk_map(&dst_sg_walk); 695 - srclen = scatterwalk_clamp(&src_sg_walk, left); 696 - dstlen = scatterwalk_clamp(&dst_sg_walk, left); 697 - len = min(srclen, dstlen); 698 - if (len) { 699 - if (enc) 700 - gcm_tfm->enc_update(aes_ctx, data, 701 - dst, src, len); 702 - else 703 - gcm_tfm->dec_update(aes_ctx, data, 704 - dst, src, len); 705 - } 706 - left -= len; 707 - 708 - scatterwalk_unmap(src); 709 - scatterwalk_unmap(dst); 710 - scatterwalk_advance(&src_sg_walk, len); 711 - scatterwalk_advance(&dst_sg_walk, len); 712 - scatterwalk_done(&src_sg_walk, 0, left); 713 - scatterwalk_done(&dst_sg_walk, 1, left); 714 - } 715 - } else { 716 - while (left) { 717 - dst = src = scatterwalk_map(&src_sg_walk); 718 - len = scatterwalk_clamp(&src_sg_walk, left); 719 - if (len) { 720 - if (enc) 721 - gcm_tfm->enc_update(aes_ctx, data, 722 - src, src, len); 723 - else 724 - gcm_tfm->dec_update(aes_ctx, data, 725 - src, src, len); 726 - } 727 - left -= len; 728 - scatterwalk_unmap(src); 729 - scatterwalk_advance(&src_sg_walk, len); 730 - scatterwalk_done(&src_sg_walk, 1, left); 731 - } 732 - } 733 - gcm_tfm->finalize(aes_ctx, data, authTag, auth_tag_len); 734 688 kernel_fpu_end(); 735 689 736 690 if (!assocmem) ··· 685 745 else 686 746 kfree(assocmem); 687 747 688 - if (!enc) { 689 - u8 authTagMsg[16]; 748 + err = enc ? skcipher_walk_aead_encrypt(&walk, req, false) 749 + : skcipher_walk_aead_decrypt(&walk, req, false); 690 750 691 - /* Copy out original authTag */ 692 - scatterwalk_map_and_copy(authTagMsg, req->src, 693 - req->assoclen + req->cryptlen - 694 - auth_tag_len, 695 - auth_tag_len, 0); 751 + while (walk.nbytes > 0) { 752 + kernel_fpu_begin(); 753 + (enc ? gcm_tfm->enc_update 754 + : gcm_tfm->dec_update)(aes_ctx, data, walk.dst.virt.addr, 755 + walk.src.virt.addr, walk.nbytes); 756 + kernel_fpu_end(); 696 757 697 - /* Compare generated tag with passed in tag. */ 698 - return crypto_memneq(authTagMsg, authTag, auth_tag_len) ? 699 - -EBADMSG : 0; 758 + err = skcipher_walk_done(&walk, 0); 700 759 } 701 760 702 - /* Copy in the authTag */ 703 - scatterwalk_map_and_copy(authTag, req->dst, 704 - req->assoclen + req->cryptlen, 705 - auth_tag_len, 1); 761 + if (err) 762 + return err; 763 + 764 + kernel_fpu_begin(); 765 + gcm_tfm->finalize(aes_ctx, data, auth_tag, auth_tag_len); 766 + kernel_fpu_end(); 706 767 707 768 return 0; 708 769 } ··· 711 770 static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen, 712 771 u8 *hash_subkey, u8 *iv, void *aes_ctx) 713 772 { 714 - return gcmaes_crypt_by_sg(true, req, assoclen, hash_subkey, iv, 715 - aes_ctx); 773 + struct crypto_aead *tfm = crypto_aead_reqtfm(req); 774 + unsigned long auth_tag_len = crypto_aead_authsize(tfm); 775 + u8 auth_tag[16]; 776 + int err; 777 + 778 + err = gcmaes_crypt_by_sg(true, req, assoclen, hash_subkey, iv, aes_ctx, 779 + auth_tag, auth_tag_len); 780 + if (err) 781 + return err; 782 + 783 + scatterwalk_map_and_copy(auth_tag, req->dst, 784 + req->assoclen + req->cryptlen, 785 + auth_tag_len, 1); 786 + return 0; 716 787 } 717 788 718 789 static int gcmaes_decrypt(struct aead_request *req, unsigned int assoclen, 719 790 u8 *hash_subkey, u8 *iv, void *aes_ctx) 720 791 { 721 - return gcmaes_crypt_by_sg(false, req, assoclen, hash_subkey, iv, 722 - aes_ctx); 792 + struct crypto_aead *tfm = crypto_aead_reqtfm(req); 793 + unsigned long auth_tag_len = crypto_aead_authsize(tfm); 794 + u8 auth_tag_msg[16]; 795 + u8 auth_tag[16]; 796 + int err; 797 + 798 + err = gcmaes_crypt_by_sg(false, req, assoclen, hash_subkey, iv, aes_ctx, 799 + auth_tag, auth_tag_len); 800 + if (err) 801 + return err; 802 + 803 + /* Copy out original auth_tag */ 804 + scatterwalk_map_and_copy(auth_tag_msg, req->src, 805 + req->assoclen + req->cryptlen - auth_tag_len, 806 + auth_tag_len, 0); 807 + 808 + /* Compare generated tag with passed in tag. */ 809 + if (crypto_memneq(auth_tag_msg, auth_tag, auth_tag_len)) { 810 + memzero_explicit(auth_tag, sizeof(auth_tag)); 811 + return -EBADMSG; 812 + } 813 + return 0; 723 814 } 724 815 725 816 static int helper_rfc4106_encrypt(struct aead_request *req)