aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorOndrej Mosnacek <omosnace@redhat.com>2018-09-11 03:40:08 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2018-09-21 01:24:50 -0400
commit78105c7e769b8cfa4a4d59027807882b560a2634 (patch)
treeff211fdd504cc542305edf17729d7aade33f7feb /crypto
parent2e5d2f33d1dbd551f14634483c7ea81e5119d689 (diff)
crypto: xts - Drop use of auxiliary buffer
Since commit acb9b159c784 ("crypto: gf128mul - define gf128mul_x_* in gf128mul.h"), the gf128mul_x_*() functions are very fast and therefore caching the computed XTS tweaks has only negligible advantage over computing them twice. In fact, since the current caching implementation limits the size of the calls to the child ecb(...) algorithm to PAGE_SIZE (usually 4096 B), it is often actually slower than the simple recomputing implementation. This patch simplifies the XTS template to recompute the XTS tweaks from scratch in the second pass and thus also removes the need to allocate a dynamic buffer using kmalloc(). As discussed at [1], the use of kmalloc causes deadlocks with dm-crypt. PERFORMANCE RESULTS I measured time to encrypt/decrypt a memory buffer of varying sizes with xts(ecb-aes-aesni) using a tool I wrote ([2]) and the results suggest that after this patch the performance is either better or comparable for both small and large buffers. Note that there is a lot of noise in the measurements, but the overall difference is easy to see. Old code: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) xts(aes) 256 64 331 328 xts(aes) 384 64 332 333 xts(aes) 512 64 338 348 xts(aes) 256 512 889 920 xts(aes) 384 512 1019 993 xts(aes) 512 512 1032 990 xts(aes) 256 4096 2152 2292 xts(aes) 384 4096 2453 2597 xts(aes) 512 4096 3041 2641 xts(aes) 256 16384 9443 8027 xts(aes) 384 16384 8536 8925 xts(aes) 512 16384 9232 9417 xts(aes) 256 32768 16383 14897 xts(aes) 384 32768 17527 16102 xts(aes) 512 32768 18483 17322 New code: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) xts(aes) 256 64 328 324 xts(aes) 384 64 324 319 xts(aes) 512 64 320 322 xts(aes) 256 512 476 473 xts(aes) 384 512 509 492 xts(aes) 512 512 531 514 xts(aes) 256 4096 2132 1829 xts(aes) 384 4096 2357 2055 xts(aes) 512 4096 2178 2027 xts(aes) 256 16384 6920 6983 xts(aes) 384 16384 8597 7505 xts(aes) 512 16384 7841 8164 xts(aes) 256 32768 13468 12307 xts(aes) 384 32768 14808 13402 xts(aes) 512 32768 15753 14636 [1] https://lkml.org/lkml/2018/8/23/1315 [2] https://gitlab.com/omos/linux-crypto-bench Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/xts.c269
1 files changed, 46 insertions, 223 deletions
diff --git a/crypto/xts.c b/crypto/xts.c
index ccf55fbb8bc2..847f54f76789 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -26,8 +26,6 @@
26#include <crypto/b128ops.h> 26#include <crypto/b128ops.h>
27#include <crypto/gf128mul.h> 27#include <crypto/gf128mul.h>
28 28
29#define XTS_BUFFER_SIZE 128u
30
31struct priv { 29struct priv {
32 struct crypto_skcipher *child; 30 struct crypto_skcipher *child;
33 struct crypto_cipher *tweak; 31 struct crypto_cipher *tweak;
@@ -39,19 +37,7 @@ struct xts_instance_ctx {
39}; 37};
40 38
41struct rctx { 39struct rctx {
42 le128 buf[XTS_BUFFER_SIZE / sizeof(le128)];
43
44 le128 t; 40 le128 t;
45
46 le128 *ext;
47
48 struct scatterlist srcbuf[2];
49 struct scatterlist dstbuf[2];
50 struct scatterlist *src;
51 struct scatterlist *dst;
52
53 unsigned int left;
54
55 struct skcipher_request subreq; 41 struct skcipher_request subreq;
56}; 42};
57 43
@@ -96,81 +82,27 @@ static int setkey(struct crypto_skcipher *parent, const u8 *key,
96 return err; 82 return err;
97} 83}
98 84
99static int post_crypt(struct skcipher_request *req) 85/*
86 * We compute the tweak masks twice (both before and after the ECB encryption or
87 * decryption) to avoid having to allocate a temporary buffer and/or make
88 * mutliple calls to the 'ecb(..)' instance, which usually would be slower than
89 * just doing the gf128mul_x_ble() calls again.
90 */
91static int xor_tweak(struct skcipher_request *req, bool second_pass)
100{ 92{
101 struct rctx *rctx = skcipher_request_ctx(req); 93 struct rctx *rctx = skcipher_request_ctx(req);
102 le128 *buf = rctx->ext ?: rctx->buf; 94 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
103 struct skcipher_request *subreq;
104 const int bs = XTS_BLOCK_SIZE; 95 const int bs = XTS_BLOCK_SIZE;
105 struct skcipher_walk w; 96 struct skcipher_walk w;
106 struct scatterlist *sg; 97 le128 t = rctx->t;
107 unsigned offset;
108 int err; 98 int err;
109 99
110 subreq = &rctx->subreq; 100 if (second_pass) {
111 err = skcipher_walk_virt(&w, subreq, false); 101 req = &rctx->subreq;
112 102 /* set to our TFM to enforce correct alignment: */
113 while (w.nbytes) { 103 skcipher_request_set_tfm(req, tfm);
114 unsigned int avail = w.nbytes;
115 le128 *wdst;
116
117 wdst = w.dst.virt.addr;
118
119 do {
120 le128_xor(wdst, buf++, wdst);
121 wdst++;
122 } while ((avail -= bs) >= bs);
123
124 err = skcipher_walk_done(&w, avail);
125 } 104 }
126 105 err = skcipher_walk_virt(&w, req, false);
127 rctx->left -= subreq->cryptlen;
128
129 if (err || !rctx->left)
130 goto out;
131
132 rctx->dst = rctx->dstbuf;
133
134 scatterwalk_done(&w.out, 0, 1);
135 sg = w.out.sg;
136 offset = w.out.offset;
137
138 if (rctx->dst != sg) {
139 rctx->dst[0] = *sg;
140 sg_unmark_end(rctx->dst);
141 scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 2);
142 }
143 rctx->dst[0].length -= offset - sg->offset;
144 rctx->dst[0].offset = offset;
145
146out:
147 return err;
148}
149
150static int pre_crypt(struct skcipher_request *req)
151{
152 struct rctx *rctx = skcipher_request_ctx(req);
153 le128 *buf = rctx->ext ?: rctx->buf;
154 struct skcipher_request *subreq;
155 const int bs = XTS_BLOCK_SIZE;
156 struct skcipher_walk w;
157 struct scatterlist *sg;
158 unsigned cryptlen;
159 unsigned offset;
160 bool more;
161 int err;
162
163 subreq = &rctx->subreq;
164 cryptlen = subreq->cryptlen;
165
166 more = rctx->left > cryptlen;
167 if (!more)
168 cryptlen = rctx->left;
169
170 skcipher_request_set_crypt(subreq, rctx->src, rctx->dst,
171 cryptlen, NULL);
172
173 err = skcipher_walk_virt(&w, subreq, false);
174 106
175 while (w.nbytes) { 107 while (w.nbytes) {
176 unsigned int avail = w.nbytes; 108 unsigned int avail = w.nbytes;
@@ -181,180 +113,71 @@ static int pre_crypt(struct skcipher_request *req)
181 wdst = w.dst.virt.addr; 113 wdst = w.dst.virt.addr;
182 114
183 do { 115 do {
184 *buf++ = rctx->t; 116 le128_xor(wdst++, &t, wsrc++);
185 le128_xor(wdst++, &rctx->t, wsrc++); 117 gf128mul_x_ble(&t, &t);
186 gf128mul_x_ble(&rctx->t, &rctx->t);
187 } while ((avail -= bs) >= bs); 118 } while ((avail -= bs) >= bs);
188 119
189 err = skcipher_walk_done(&w, avail); 120 err = skcipher_walk_done(&w, avail);
190 } 121 }
191 122
192 skcipher_request_set_crypt(subreq, rctx->dst, rctx->dst,
193 cryptlen, NULL);
194
195 if (err || !more)
196 goto out;
197
198 rctx->src = rctx->srcbuf;
199
200 scatterwalk_done(&w.in, 0, 1);
201 sg = w.in.sg;
202 offset = w.in.offset;
203
204 if (rctx->src != sg) {
205 rctx->src[0] = *sg;
206 sg_unmark_end(rctx->src);
207 scatterwalk_crypto_chain(rctx->src, sg_next(sg), 2);
208 }
209 rctx->src[0].length -= offset - sg->offset;
210 rctx->src[0].offset = offset;
211
212out:
213 return err; 123 return err;
214} 124}
215 125
216static int init_crypt(struct skcipher_request *req, crypto_completion_t done) 126static int xor_tweak_pre(struct skcipher_request *req)
217{ 127{
218 struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 128 return xor_tweak(req, false);
219 struct rctx *rctx = skcipher_request_ctx(req);
220 struct skcipher_request *subreq;
221 gfp_t gfp;
222
223 subreq = &rctx->subreq;
224 skcipher_request_set_tfm(subreq, ctx->child);
225 skcipher_request_set_callback(subreq, req->base.flags, done, req);
226
227 gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
228 GFP_ATOMIC;
229 rctx->ext = NULL;
230
231 subreq->cryptlen = XTS_BUFFER_SIZE;
232 if (req->cryptlen > XTS_BUFFER_SIZE) {
233 unsigned int n = min(req->cryptlen, (unsigned int)PAGE_SIZE);
234
235 rctx->ext = kmalloc(n, gfp);
236 if (rctx->ext)
237 subreq->cryptlen = n;
238 }
239
240 rctx->src = req->src;
241 rctx->dst = req->dst;
242 rctx->left = req->cryptlen;
243
244 /* calculate first value of T */
245 crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv);
246
247 return 0;
248} 129}
249 130
250static void exit_crypt(struct skcipher_request *req) 131static int xor_tweak_post(struct skcipher_request *req)
251{ 132{
252 struct rctx *rctx = skcipher_request_ctx(req); 133 return xor_tweak(req, true);
253
254 rctx->left = 0;
255
256 if (rctx->ext)
257 kzfree(rctx->ext);
258} 134}
259 135
260static int do_encrypt(struct skcipher_request *req, int err) 136static void crypt_done(struct crypto_async_request *areq, int err)
261{
262 struct rctx *rctx = skcipher_request_ctx(req);
263 struct skcipher_request *subreq;
264
265 subreq = &rctx->subreq;
266
267 while (!err && rctx->left) {
268 err = pre_crypt(req) ?:
269 crypto_skcipher_encrypt(subreq) ?:
270 post_crypt(req);
271
272 if (err == -EINPROGRESS || err == -EBUSY)
273 return err;
274 }
275
276 exit_crypt(req);
277 return err;
278}
279
280static void encrypt_done(struct crypto_async_request *areq, int err)
281{ 137{
282 struct skcipher_request *req = areq->data; 138 struct skcipher_request *req = areq->data;
283 struct skcipher_request *subreq;
284 struct rctx *rctx;
285
286 rctx = skcipher_request_ctx(req);
287
288 if (err == -EINPROGRESS) {
289 if (rctx->left != req->cryptlen)
290 return;
291 goto out;
292 }
293
294 subreq = &rctx->subreq;
295 subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
296 139
297 err = do_encrypt(req, err ?: post_crypt(req)); 140 if (!err)
298 if (rctx->left) 141 err = xor_tweak_post(req);
299 return;
300 142
301out:
302 skcipher_request_complete(req, err); 143 skcipher_request_complete(req, err);
303} 144}
304 145
305static int encrypt(struct skcipher_request *req) 146static void init_crypt(struct skcipher_request *req)
306{
307 return do_encrypt(req, init_crypt(req, encrypt_done));
308}
309
310static int do_decrypt(struct skcipher_request *req, int err)
311{ 147{
148 struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
312 struct rctx *rctx = skcipher_request_ctx(req); 149 struct rctx *rctx = skcipher_request_ctx(req);
313 struct skcipher_request *subreq; 150 struct skcipher_request *subreq = &rctx->subreq;
314
315 subreq = &rctx->subreq;
316 151
317 while (!err && rctx->left) { 152 skcipher_request_set_tfm(subreq, ctx->child);
318 err = pre_crypt(req) ?: 153 skcipher_request_set_callback(subreq, req->base.flags, crypt_done, req);
319 crypto_skcipher_decrypt(subreq) ?: 154 skcipher_request_set_crypt(subreq, req->dst, req->dst,
320 post_crypt(req); 155 req->cryptlen, NULL);
321
322 if (err == -EINPROGRESS || err == -EBUSY)
323 return err;
324 }
325 156
326 exit_crypt(req); 157 /* calculate first value of T */
327 return err; 158 crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv);
328} 159}
329 160
330static void decrypt_done(struct crypto_async_request *areq, int err) 161static int encrypt(struct skcipher_request *req)
331{ 162{
332 struct skcipher_request *req = areq->data; 163 struct rctx *rctx = skcipher_request_ctx(req);
333 struct skcipher_request *subreq; 164 struct skcipher_request *subreq = &rctx->subreq;
334 struct rctx *rctx;
335
336 rctx = skcipher_request_ctx(req);
337
338 if (err == -EINPROGRESS) {
339 if (rctx->left != req->cryptlen)
340 return;
341 goto out;
342 }
343
344 subreq = &rctx->subreq;
345 subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
346
347 err = do_decrypt(req, err ?: post_crypt(req));
348 if (rctx->left)
349 return;
350 165
351out: 166 init_crypt(req);
352 skcipher_request_complete(req, err); 167 return xor_tweak_pre(req) ?:
168 crypto_skcipher_encrypt(subreq) ?:
169 xor_tweak_post(req);
353} 170}
354 171
355static int decrypt(struct skcipher_request *req) 172static int decrypt(struct skcipher_request *req)
356{ 173{
357 return do_decrypt(req, init_crypt(req, decrypt_done)); 174 struct rctx *rctx = skcipher_request_ctx(req);
175 struct skcipher_request *subreq = &rctx->subreq;
176
177 init_crypt(req);
178 return xor_tweak_pre(req) ?:
179 crypto_skcipher_decrypt(subreq) ?:
180 xor_tweak_post(req);
358} 181}
359 182
360static int init_tfm(struct crypto_skcipher *tfm) 183static int init_tfm(struct crypto_skcipher *tfm)