diff options
Diffstat (limited to 'arch/s390/crypto/aes_s390.c')
| -rw-r--r-- | arch/s390/crypto/aes_s390.c | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index b3feabd39f31..cf3c0089bef2 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
| 28 | #include <linux/spinlock.h> | ||
| 28 | #include "crypt_s390.h" | 29 | #include "crypt_s390.h" |
| 29 | 30 | ||
| 30 | #define AES_KEYLEN_128 1 | 31 | #define AES_KEYLEN_128 1 |
| @@ -32,6 +33,7 @@ | |||
| 32 | #define AES_KEYLEN_256 4 | 33 | #define AES_KEYLEN_256 4 |
| 33 | 34 | ||
| 34 | static u8 *ctrblk; | 35 | static u8 *ctrblk; |
| 36 | static DEFINE_SPINLOCK(ctrblk_lock); | ||
| 35 | static char keylen_flag; | 37 | static char keylen_flag; |
| 36 | 38 | ||
| 37 | struct s390_aes_ctx { | 39 | struct s390_aes_ctx { |
| @@ -758,43 +760,67 @@ static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, | |||
| 758 | return aes_set_key(tfm, in_key, key_len); | 760 | return aes_set_key(tfm, in_key, key_len); |
| 759 | } | 761 | } |
| 760 | 762 | ||
| 763 | static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) | ||
| 764 | { | ||
| 765 | unsigned int i, n; | ||
| 766 | |||
| 767 | /* only use complete blocks, max. PAGE_SIZE */ | ||
| 768 | n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1); | ||
| 769 | for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { | ||
| 770 | memcpy(ctrptr + i, ctrptr + i - AES_BLOCK_SIZE, | ||
| 771 | AES_BLOCK_SIZE); | ||
| 772 | crypto_inc(ctrptr + i, AES_BLOCK_SIZE); | ||
| 773 | } | ||
| 774 | return n; | ||
| 775 | } | ||
| 776 | |||
| 761 | static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, | 777 | static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, |
| 762 | struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) | 778 | struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) |
| 763 | { | 779 | { |
| 764 | int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); | 780 | int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); |
| 765 | unsigned int i, n, nbytes; | 781 | unsigned int n, nbytes; |
| 766 | u8 buf[AES_BLOCK_SIZE]; | 782 | u8 buf[AES_BLOCK_SIZE], ctrbuf[AES_BLOCK_SIZE]; |
| 767 | u8 *out, *in; | 783 | u8 *out, *in, *ctrptr = ctrbuf; |
| 768 | 784 | ||
| 769 | if (!walk->nbytes) | 785 | if (!walk->nbytes) |
| 770 | return ret; | 786 | return ret; |
| 771 | 787 | ||
| 772 | memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE); | 788 | if (spin_trylock(&ctrblk_lock)) |
| 789 | ctrptr = ctrblk; | ||
| 790 | |||
| 791 | memcpy(ctrptr, walk->iv, AES_BLOCK_SIZE); | ||
| 773 | while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { | 792 | while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { |
| 774 | out = walk->dst.virt.addr; | 793 | out = walk->dst.virt.addr; |
| 775 | in = walk->src.virt.addr; | 794 | in = walk->src.virt.addr; |
| 776 | while (nbytes >= AES_BLOCK_SIZE) { | 795 | while (nbytes >= AES_BLOCK_SIZE) { |
| 777 | /* only use complete blocks, max. PAGE_SIZE */ | 796 | if (ctrptr == ctrblk) |
| 778 | n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : | 797 | n = __ctrblk_init(ctrptr, nbytes); |
| 779 | nbytes & ~(AES_BLOCK_SIZE - 1); | 798 | else |
| 780 | for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { | 799 | n = AES_BLOCK_SIZE; |
| 781 | memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE, | 800 | ret = crypt_s390_kmctr(func, sctx->key, out, in, |
| 782 | AES_BLOCK_SIZE); | 801 | n, ctrptr); |
| 783 | crypto_inc(ctrblk + i, AES_BLOCK_SIZE); | 802 | if (ret < 0 || ret != n) { |
| 784 | } | 803 | if (ctrptr == ctrblk) |
| 785 | ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk); | 804 | spin_unlock(&ctrblk_lock); |
| 786 | if (ret < 0 || ret != n) | ||
| 787 | return -EIO; | 805 | return -EIO; |
| 806 | } | ||
| 788 | if (n > AES_BLOCK_SIZE) | 807 | if (n > AES_BLOCK_SIZE) |
| 789 | memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE, | 808 | memcpy(ctrptr, ctrptr + n - AES_BLOCK_SIZE, |
| 790 | AES_BLOCK_SIZE); | 809 | AES_BLOCK_SIZE); |
| 791 | crypto_inc(ctrblk, AES_BLOCK_SIZE); | 810 | crypto_inc(ctrptr, AES_BLOCK_SIZE); |
| 792 | out += n; | 811 | out += n; |
| 793 | in += n; | 812 | in += n; |
| 794 | nbytes -= n; | 813 | nbytes -= n; |
| 795 | } | 814 | } |
| 796 | ret = blkcipher_walk_done(desc, walk, nbytes); | 815 | ret = blkcipher_walk_done(desc, walk, nbytes); |
| 797 | } | 816 | } |
| 817 | if (ctrptr == ctrblk) { | ||
| 818 | if (nbytes) | ||
| 819 | memcpy(ctrbuf, ctrptr, AES_BLOCK_SIZE); | ||
| 820 | else | ||
| 821 | memcpy(walk->iv, ctrptr, AES_BLOCK_SIZE); | ||
| 822 | spin_unlock(&ctrblk_lock); | ||
| 823 | } | ||
| 798 | /* | 824 | /* |
| 799 | * final block may be < AES_BLOCK_SIZE, copy only nbytes | 825 | * final block may be < AES_BLOCK_SIZE, copy only nbytes |
| 800 | */ | 826 | */ |
| @@ -802,14 +828,15 @@ static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, | |||
| 802 | out = walk->dst.virt.addr; | 828 | out = walk->dst.virt.addr; |
| 803 | in = walk->src.virt.addr; | 829 | in = walk->src.virt.addr; |
| 804 | ret = crypt_s390_kmctr(func, sctx->key, buf, in, | 830 | ret = crypt_s390_kmctr(func, sctx->key, buf, in, |
| 805 | AES_BLOCK_SIZE, ctrblk); | 831 | AES_BLOCK_SIZE, ctrbuf); |
| 806 | if (ret < 0 || ret != AES_BLOCK_SIZE) | 832 | if (ret < 0 || ret != AES_BLOCK_SIZE) |
| 807 | return -EIO; | 833 | return -EIO; |
| 808 | memcpy(out, buf, nbytes); | 834 | memcpy(out, buf, nbytes); |
| 809 | crypto_inc(ctrblk, AES_BLOCK_SIZE); | 835 | crypto_inc(ctrbuf, AES_BLOCK_SIZE); |
| 810 | ret = blkcipher_walk_done(desc, walk, 0); | 836 | ret = blkcipher_walk_done(desc, walk, 0); |
| 837 | memcpy(walk->iv, ctrbuf, AES_BLOCK_SIZE); | ||
| 811 | } | 838 | } |
| 812 | memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE); | 839 | |
| 813 | return ret; | 840 | return ret; |
| 814 | } | 841 | } |
| 815 | 842 | ||
