diff options
-rw-r--r-- | arch/x86/crypto/aesni-intel_glue.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index de986f9395d5..acbe7e8336d8 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c | |||
@@ -791,6 +791,127 @@ static int generic_gcmaes_set_authsize(struct crypto_aead *tfm, | |||
791 | return 0; | 791 | return 0; |
792 | } | 792 | } |
793 | 793 | ||
794 | static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req, | ||
795 | unsigned int assoclen, u8 *hash_subkey, | ||
796 | u8 *iv, void *aes_ctx) | ||
797 | { | ||
798 | struct crypto_aead *tfm = crypto_aead_reqtfm(req); | ||
799 | unsigned long auth_tag_len = crypto_aead_authsize(tfm); | ||
800 | struct gcm_context_data data AESNI_ALIGN_ATTR; | ||
801 | struct scatter_walk dst_sg_walk = {}; | ||
802 | unsigned long left = req->cryptlen; | ||
803 | unsigned long len, srclen, dstlen; | ||
804 | struct scatter_walk assoc_sg_walk; | ||
805 | struct scatter_walk src_sg_walk; | ||
806 | struct scatterlist src_start[2]; | ||
807 | struct scatterlist dst_start[2]; | ||
808 | struct scatterlist *src_sg; | ||
809 | struct scatterlist *dst_sg; | ||
810 | u8 *src, *dst, *assoc; | ||
811 | u8 *assocmem = NULL; | ||
812 | u8 authTag[16]; | ||
813 | |||
814 | if (!enc) | ||
815 | left -= auth_tag_len; | ||
816 | |||
817 | /* Linearize assoc, if not already linear */ | ||
818 | if (req->src->length >= assoclen && req->src->length && | ||
819 | (!PageHighMem(sg_page(req->src)) || | ||
820 | req->src->offset + req->src->length < PAGE_SIZE)) { | ||
821 | scatterwalk_start(&assoc_sg_walk, req->src); | ||
822 | assoc = scatterwalk_map(&assoc_sg_walk); | ||
823 | } else { | ||
824 | /* assoc can be any length, so must be on heap */ | ||
825 | assocmem = kmalloc(assoclen, GFP_ATOMIC); | ||
826 | if (unlikely(!assocmem)) | ||
827 | return -ENOMEM; | ||
828 | assoc = assocmem; | ||
829 | |||
830 | scatterwalk_map_and_copy(assoc, req->src, 0, assoclen, 0); | ||
831 | } | ||
832 | |||
833 | src_sg = scatterwalk_ffwd(src_start, req->src, req->assoclen); | ||
834 | scatterwalk_start(&src_sg_walk, src_sg); | ||
835 | if (req->src != req->dst) { | ||
836 | dst_sg = scatterwalk_ffwd(dst_start, req->dst, req->assoclen); | ||
837 | scatterwalk_start(&dst_sg_walk, dst_sg); | ||
838 | } | ||
839 | |||
840 | kernel_fpu_begin(); | ||
841 | aesni_gcm_init(aes_ctx, &data, iv, | ||
842 | hash_subkey, assoc, assoclen); | ||
843 | if (req->src != req->dst) { | ||
844 | while (left) { | ||
845 | src = scatterwalk_map(&src_sg_walk); | ||
846 | dst = scatterwalk_map(&dst_sg_walk); | ||
847 | srclen = scatterwalk_clamp(&src_sg_walk, left); | ||
848 | dstlen = scatterwalk_clamp(&dst_sg_walk, left); | ||
849 | len = min(srclen, dstlen); | ||
850 | if (len) { | ||
851 | if (enc) | ||
852 | aesni_gcm_enc_update(aes_ctx, &data, | ||
853 | dst, src, len); | ||
854 | else | ||
855 | aesni_gcm_dec_update(aes_ctx, &data, | ||
856 | dst, src, len); | ||
857 | } | ||
858 | left -= len; | ||
859 | |||
860 | scatterwalk_unmap(src); | ||
861 | scatterwalk_unmap(dst); | ||
862 | scatterwalk_advance(&src_sg_walk, len); | ||
863 | scatterwalk_advance(&dst_sg_walk, len); | ||
864 | scatterwalk_done(&src_sg_walk, 0, left); | ||
865 | scatterwalk_done(&dst_sg_walk, 1, left); | ||
866 | } | ||
867 | } else { | ||
868 | while (left) { | ||
869 | dst = src = scatterwalk_map(&src_sg_walk); | ||
870 | len = scatterwalk_clamp(&src_sg_walk, left); | ||
871 | if (len) { | ||
872 | if (enc) | ||
873 | aesni_gcm_enc_update(aes_ctx, &data, | ||
874 | src, src, len); | ||
875 | else | ||
876 | aesni_gcm_dec_update(aes_ctx, &data, | ||
877 | src, src, len); | ||
878 | } | ||
879 | left -= len; | ||
880 | scatterwalk_unmap(src); | ||
881 | scatterwalk_advance(&src_sg_walk, len); | ||
882 | scatterwalk_done(&src_sg_walk, 1, left); | ||
883 | } | ||
884 | } | ||
885 | aesni_gcm_finalize(aes_ctx, &data, authTag, auth_tag_len); | ||
886 | kernel_fpu_end(); | ||
887 | |||
888 | if (!assocmem) | ||
889 | scatterwalk_unmap(assoc); | ||
890 | else | ||
891 | kfree(assocmem); | ||
892 | |||
893 | if (!enc) { | ||
894 | u8 authTagMsg[16]; | ||
895 | |||
896 | /* Copy out original authTag */ | ||
897 | scatterwalk_map_and_copy(authTagMsg, req->src, | ||
898 | req->assoclen + req->cryptlen - | ||
899 | auth_tag_len, | ||
900 | auth_tag_len, 0); | ||
901 | |||
902 | /* Compare generated tag with passed in tag. */ | ||
903 | return crypto_memneq(authTagMsg, authTag, auth_tag_len) ? | ||
904 | -EBADMSG : 0; | ||
905 | } | ||
906 | |||
907 | /* Copy in the authTag */ | ||
908 | scatterwalk_map_and_copy(authTag, req->dst, | ||
909 | req->assoclen + req->cryptlen, | ||
910 | auth_tag_len, 1); | ||
911 | |||
912 | return 0; | ||
913 | } | ||
914 | |||
794 | static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen, | 915 | static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen, |
795 | u8 *hash_subkey, u8 *iv, void *aes_ctx) | 916 | u8 *hash_subkey, u8 *iv, void *aes_ctx) |
796 | { | 917 | { |
@@ -802,6 +923,12 @@ static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen, | |||
802 | struct scatter_walk dst_sg_walk = {}; | 923 | struct scatter_walk dst_sg_walk = {}; |
803 | struct gcm_context_data data AESNI_ALIGN_ATTR; | 924 | struct gcm_context_data data AESNI_ALIGN_ATTR; |
804 | 925 | ||
926 | if (((struct crypto_aes_ctx *)aes_ctx)->key_length != AES_KEYSIZE_128 || | ||
927 | aesni_gcm_enc_tfm == aesni_gcm_enc || | ||
928 | req->cryptlen < AVX_GEN2_OPTSIZE) { | ||
929 | return gcmaes_crypt_by_sg(true, req, assoclen, hash_subkey, iv, | ||
930 | aes_ctx); | ||
931 | } | ||
805 | if (sg_is_last(req->src) && | 932 | if (sg_is_last(req->src) && |
806 | (!PageHighMem(sg_page(req->src)) || | 933 | (!PageHighMem(sg_page(req->src)) || |
807 | req->src->offset + req->src->length <= PAGE_SIZE) && | 934 | req->src->offset + req->src->length <= PAGE_SIZE) && |
@@ -868,6 +995,12 @@ static int gcmaes_decrypt(struct aead_request *req, unsigned int assoclen, | |||
868 | struct gcm_context_data data AESNI_ALIGN_ATTR; | 995 | struct gcm_context_data data AESNI_ALIGN_ATTR; |
869 | int retval = 0; | 996 | int retval = 0; |
870 | 997 | ||
998 | if (((struct crypto_aes_ctx *)aes_ctx)->key_length != AES_KEYSIZE_128 || | ||
999 | aesni_gcm_enc_tfm == aesni_gcm_enc || | ||
1000 | req->cryptlen < AVX_GEN2_OPTSIZE) { | ||
1001 | return gcmaes_crypt_by_sg(false, req, assoclen, hash_subkey, iv, | ||
1002 | aes_ctx); | ||
1003 | } | ||
871 | tempCipherLen = (unsigned long)(req->cryptlen - auth_tag_len); | 1004 | tempCipherLen = (unsigned long)(req->cryptlen - auth_tag_len); |
872 | 1005 | ||
873 | if (sg_is_last(req->src) && | 1006 | if (sg_is_last(req->src) && |