diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2005-07-06 16:52:09 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2005-07-06 16:52:09 -0400 |
| commit | 95477377995aefa2ec1654a9a3777bd57ea99146 (patch) | |
| tree | 7aa4d6173de13c81c2fa0e4d2f9e0de22e141b6a /crypto | |
| parent | 40725181b74be6b0e3bdc8c05bd1e0b9873ec5cc (diff) | |
[CRYPTO] Add alignmask for low-level cipher implementations
The VIA Padlock device requires the input and output buffers to
be aligned on 16-byte boundaries. This patch adds the alignmask
attribute for low-level cipher implementations to indicate their
alignment requirements.
The mid-level crypt() function will copy the input/output buffers
if they are not aligned correctly before they are passed to the
low-level implementation.
Strictly speaking, some of the software implementations require
the buffers to be aligned on 4-byte boundaries as they do 32-bit
loads. However, it is not clear whether it is better to copy
the buffers or pay the penalty for unaligned loads/stores.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/api.c | 6 | ||||
| -rw-r--r-- | crypto/cipher.c | 43 | ||||
| -rw-r--r-- | crypto/scatterwalk.h | 6 |
3 files changed, 48 insertions, 7 deletions
diff --git a/crypto/api.c b/crypto/api.c index 394169a8577d..f55856b21992 100644 --- a/crypto/api.c +++ b/crypto/api.c | |||
| @@ -168,6 +168,12 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
| 168 | { | 168 | { |
| 169 | int ret = 0; | 169 | int ret = 0; |
| 170 | struct crypto_alg *q; | 170 | struct crypto_alg *q; |
| 171 | |||
| 172 | if (alg->cra_alignmask & (alg->cra_alignmask + 1)) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | if (alg->cra_alignmask > PAGE_SIZE) | ||
| 176 | return -EINVAL; | ||
| 171 | 177 | ||
| 172 | down_write(&crypto_alg_sem); | 178 | down_write(&crypto_alg_sem); |
| 173 | 179 | ||
diff --git a/crypto/cipher.c b/crypto/cipher.c index 54c4a560070d..85eb12f8e564 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c | |||
| @@ -41,8 +41,10 @@ static unsigned int crypt_slow(const struct cipher_desc *desc, | |||
| 41 | struct scatter_walk *in, | 41 | struct scatter_walk *in, |
| 42 | struct scatter_walk *out, unsigned int bsize) | 42 | struct scatter_walk *out, unsigned int bsize) |
| 43 | { | 43 | { |
| 44 | u8 src[bsize]; | 44 | unsigned int alignmask = desc->tfm->__crt_alg->cra_alignmask; |
| 45 | u8 dst[bsize]; | 45 | u8 buffer[bsize * 2 + alignmask]; |
| 46 | u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); | ||
| 47 | u8 *dst = src + bsize; | ||
| 46 | unsigned int n; | 48 | unsigned int n; |
| 47 | 49 | ||
| 48 | n = scatterwalk_copychunks(src, in, bsize, 0); | 50 | n = scatterwalk_copychunks(src, in, bsize, 0); |
| @@ -59,15 +61,24 @@ static unsigned int crypt_slow(const struct cipher_desc *desc, | |||
| 59 | static inline unsigned int crypt_fast(const struct cipher_desc *desc, | 61 | static inline unsigned int crypt_fast(const struct cipher_desc *desc, |
| 60 | struct scatter_walk *in, | 62 | struct scatter_walk *in, |
| 61 | struct scatter_walk *out, | 63 | struct scatter_walk *out, |
| 62 | unsigned int nbytes) | 64 | unsigned int nbytes, u8 *tmp) |
| 63 | { | 65 | { |
| 64 | u8 *src, *dst; | 66 | u8 *src, *dst; |
| 65 | 67 | ||
| 66 | src = in->data; | 68 | src = in->data; |
| 67 | dst = scatterwalk_samebuf(in, out) ? src : out->data; | 69 | dst = scatterwalk_samebuf(in, out) ? src : out->data; |
| 68 | 70 | ||
| 71 | if (tmp) { | ||
| 72 | memcpy(tmp, in->data, nbytes); | ||
| 73 | src = tmp; | ||
| 74 | dst = tmp; | ||
| 75 | } | ||
| 76 | |||
| 69 | nbytes = desc->prfn(desc, dst, src, nbytes); | 77 | nbytes = desc->prfn(desc, dst, src, nbytes); |
| 70 | 78 | ||
| 79 | if (tmp) | ||
| 80 | memcpy(out->data, tmp, nbytes); | ||
| 81 | |||
| 71 | scatterwalk_advance(in, nbytes); | 82 | scatterwalk_advance(in, nbytes); |
| 72 | scatterwalk_advance(out, nbytes); | 83 | scatterwalk_advance(out, nbytes); |
| 73 | 84 | ||
| @@ -87,6 +98,8 @@ static int crypt(const struct cipher_desc *desc, | |||
| 87 | struct scatter_walk walk_in, walk_out; | 98 | struct scatter_walk walk_in, walk_out; |
| 88 | struct crypto_tfm *tfm = desc->tfm; | 99 | struct crypto_tfm *tfm = desc->tfm; |
| 89 | const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); | 100 | const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); |
| 101 | unsigned int alignmask = tfm->__crt_alg->cra_alignmask; | ||
| 102 | unsigned long buffer = 0; | ||
| 90 | 103 | ||
| 91 | if (!nbytes) | 104 | if (!nbytes) |
| 92 | return 0; | 105 | return 0; |
| @@ -100,16 +113,27 @@ static int crypt(const struct cipher_desc *desc, | |||
| 100 | scatterwalk_start(&walk_out, dst); | 113 | scatterwalk_start(&walk_out, dst); |
| 101 | 114 | ||
| 102 | for(;;) { | 115 | for(;;) { |
| 103 | unsigned int n; | 116 | unsigned int n = nbytes; |
| 117 | u8 *tmp = NULL; | ||
| 118 | |||
| 119 | if (!scatterwalk_aligned(&walk_in, alignmask) || | ||
| 120 | !scatterwalk_aligned(&walk_out, alignmask)) { | ||
| 121 | if (!buffer) { | ||
| 122 | buffer = __get_free_page(GFP_ATOMIC); | ||
| 123 | if (!buffer) | ||
| 124 | n = 0; | ||
| 125 | } | ||
| 126 | tmp = (u8 *)buffer; | ||
| 127 | } | ||
| 104 | 128 | ||
| 105 | scatterwalk_map(&walk_in, 0); | 129 | scatterwalk_map(&walk_in, 0); |
| 106 | scatterwalk_map(&walk_out, 1); | 130 | scatterwalk_map(&walk_out, 1); |
| 107 | 131 | ||
| 108 | n = scatterwalk_clamp(&walk_in, nbytes); | 132 | n = scatterwalk_clamp(&walk_in, n); |
| 109 | n = scatterwalk_clamp(&walk_out, n); | 133 | n = scatterwalk_clamp(&walk_out, n); |
| 110 | 134 | ||
| 111 | if (likely(n >= bsize)) | 135 | if (likely(n >= bsize)) |
| 112 | n = crypt_fast(desc, &walk_in, &walk_out, n); | 136 | n = crypt_fast(desc, &walk_in, &walk_out, n, tmp); |
| 113 | else | 137 | else |
| 114 | n = crypt_slow(desc, &walk_in, &walk_out, bsize); | 138 | n = crypt_slow(desc, &walk_in, &walk_out, bsize); |
| 115 | 139 | ||
| @@ -119,10 +143,15 @@ static int crypt(const struct cipher_desc *desc, | |||
| 119 | scatterwalk_done(&walk_out, 1, nbytes); | 143 | scatterwalk_done(&walk_out, 1, nbytes); |
| 120 | 144 | ||
| 121 | if (!nbytes) | 145 | if (!nbytes) |
| 122 | return 0; | 146 | break; |
| 123 | 147 | ||
| 124 | crypto_yield(tfm); | 148 | crypto_yield(tfm); |
| 125 | } | 149 | } |
| 150 | |||
| 151 | if (buffer) | ||
| 152 | free_page(buffer); | ||
| 153 | |||
| 154 | return 0; | ||
| 126 | } | 155 | } |
| 127 | 156 | ||
| 128 | static unsigned int cbc_process_encrypt(const struct cipher_desc *desc, | 157 | static unsigned int cbc_process_encrypt(const struct cipher_desc *desc, |
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h index 5495bb970816..e79925c474a3 100644 --- a/crypto/scatterwalk.h +++ b/crypto/scatterwalk.h | |||
| @@ -55,6 +55,12 @@ static inline void scatterwalk_advance(struct scatter_walk *walk, | |||
| 55 | walk->len_this_segment -= nbytes; | 55 | walk->len_this_segment -= nbytes; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, | ||
| 59 | unsigned int alignmask) | ||
| 60 | { | ||
| 61 | return !(walk->offset & alignmask); | ||
| 62 | } | ||
| 63 | |||
| 58 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); | 64 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); |
| 59 | int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); | 65 | int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); |
| 60 | void scatterwalk_map(struct scatter_walk *walk, int out); | 66 | void scatterwalk_map(struct scatter_walk *walk, int out); |
