aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorOndrej Mosnacek <omosnace@redhat.com>2018-09-13 04:51:34 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2018-09-21 01:24:52 -0400
commitac3c8f36c31d2f0add4eeaa42c7d0540d7c60583 (patch)
tree813284644b85344440be5d86985e263f1a51099d /crypto
parentc778f96bf3471b870caa2b9282f08f176a416f88 (diff)
crypto: lrw - Do not use auxiliary buffer
This patch simplifies the LRW template to recompute the LRW 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 MEASUREMENTS (x86_64) Performed using: https://gitlab.com/omos/linux-crypto-bench Crypto driver used: lrw(ecb-aes-aesni) The results show that the new code has about the same performance as the old code. For 512-byte message it seems to be even slightly faster, but that might be just noise. Before: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 200 203 lrw(aes) 320 64 202 204 lrw(aes) 384 64 204 205 lrw(aes) 256 512 415 415 lrw(aes) 320 512 432 440 lrw(aes) 384 512 449 451 lrw(aes) 256 4096 1838 1995 lrw(aes) 320 4096 2123 1980 lrw(aes) 384 4096 2100 2119 lrw(aes) 256 16384 7183 6954 lrw(aes) 320 16384 7844 7631 lrw(aes) 384 16384 8256 8126 lrw(aes) 256 32768 14772 14484 lrw(aes) 320 32768 15281 15431 lrw(aes) 384 32768 16469 16293 After: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 197 196 lrw(aes) 320 64 200 197 lrw(aes) 384 64 203 199 lrw(aes) 256 512 385 380 lrw(aes) 320 512 401 395 lrw(aes) 384 512 415 415 lrw(aes) 256 4096 1869 1846 lrw(aes) 320 4096 2080 1981 lrw(aes) 384 4096 2160 2109 lrw(aes) 256 16384 7077 7127 lrw(aes) 320 16384 7807 7766 lrw(aes) 384 16384 8108 8357 lrw(aes) 256 32768 14111 14454 lrw(aes) 320 32768 15268 15082 lrw(aes) 384 32768 16581 16250 [1] https://lkml.org/lkml/2018/8/23/1315 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/lrw.c280
1 files changed, 51 insertions, 229 deletions
diff --git a/crypto/lrw.c b/crypto/lrw.c
index 7377b5b486fd..6fcf0d431185 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -29,8 +29,6 @@
29#include <crypto/b128ops.h> 29#include <crypto/b128ops.h>
30#include <crypto/gf128mul.h> 30#include <crypto/gf128mul.h>
31 31
32#define LRW_BUFFER_SIZE 128u
33
34#define LRW_BLOCK_SIZE 16 32#define LRW_BLOCK_SIZE 16
35 33
36struct priv { 34struct priv {
@@ -56,19 +54,7 @@ struct priv {
56}; 54};
57 55
58struct rctx { 56struct rctx {
59 be128 buf[LRW_BUFFER_SIZE / sizeof(be128)];
60
61 be128 t; 57 be128 t;
62
63 be128 *ext;
64
65 struct scatterlist srcbuf[2];
66 struct scatterlist dstbuf[2];
67 struct scatterlist *src;
68 struct scatterlist *dst;
69
70 unsigned int left;
71
72 struct skcipher_request subreq; 58 struct skcipher_request subreq;
73}; 59};
74 60
@@ -152,86 +138,31 @@ static int next_index(u32 *counter)
152 return 127; 138 return 127;
153} 139}
154 140
155static int post_crypt(struct skcipher_request *req) 141/*
142 * We compute the tweak masks twice (both before and after the ECB encryption or
143 * decryption) to avoid having to allocate a temporary buffer and/or make
144 * mutliple calls to the 'ecb(..)' instance, which usually would be slower than
145 * just doing the next_index() calls again.
146 */
147static int xor_tweak(struct skcipher_request *req, bool second_pass)
156{ 148{
157 struct rctx *rctx = skcipher_request_ctx(req);
158 be128 *buf = rctx->ext ?: rctx->buf;
159 struct skcipher_request *subreq;
160 const int bs = LRW_BLOCK_SIZE; 149 const int bs = LRW_BLOCK_SIZE;
161 struct skcipher_walk w;
162 struct scatterlist *sg;
163 unsigned offset;
164 int err;
165
166 subreq = &rctx->subreq;
167 err = skcipher_walk_virt(&w, subreq, false);
168
169 while (w.nbytes) {
170 unsigned int avail = w.nbytes;
171 be128 *wdst;
172
173 wdst = w.dst.virt.addr;
174
175 do {
176 be128_xor(wdst, buf++, wdst);
177 wdst++;
178 } while ((avail -= bs) >= bs);
179
180 err = skcipher_walk_done(&w, avail);
181 }
182
183 rctx->left -= subreq->cryptlen;
184
185 if (err || !rctx->left)
186 goto out;
187
188 rctx->dst = rctx->dstbuf;
189
190 scatterwalk_done(&w.out, 0, 1);
191 sg = w.out.sg;
192 offset = w.out.offset;
193
194 if (rctx->dst != sg) {
195 rctx->dst[0] = *sg;
196 sg_unmark_end(rctx->dst);
197 scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 2);
198 }
199 rctx->dst[0].length -= offset - sg->offset;
200 rctx->dst[0].offset = offset;
201
202out:
203 return err;
204}
205
206static int pre_crypt(struct skcipher_request *req)
207{
208 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 150 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
209 struct rctx *rctx = skcipher_request_ctx(req);
210 struct priv *ctx = crypto_skcipher_ctx(tfm); 151 struct priv *ctx = crypto_skcipher_ctx(tfm);
211 be128 *buf = rctx->ext ?: rctx->buf; 152 struct rctx *rctx = skcipher_request_ctx(req);
212 struct skcipher_request *subreq; 153 be128 t = rctx->t;
213 const int bs = LRW_BLOCK_SIZE;
214 struct skcipher_walk w; 154 struct skcipher_walk w;
215 struct scatterlist *sg;
216 unsigned cryptlen;
217 unsigned offset;
218 bool more;
219 __be32 *iv; 155 __be32 *iv;
220 u32 counter[4]; 156 u32 counter[4];
221 int err; 157 int err;
222 158
223 subreq = &rctx->subreq; 159 if (second_pass) {
224 skcipher_request_set_tfm(subreq, tfm); 160 req = &rctx->subreq;
225 161 /* set to our TFM to enforce correct alignment: */
226 cryptlen = subreq->cryptlen; 162 skcipher_request_set_tfm(req, tfm);
227 more = rctx->left > cryptlen; 163 }
228 if (!more)
229 cryptlen = rctx->left;
230
231 skcipher_request_set_crypt(subreq, rctx->src, rctx->dst,
232 cryptlen, req->iv);
233 164
234 err = skcipher_walk_virt(&w, subreq, false); 165 err = skcipher_walk_virt(&w, req, false);
235 iv = (__be32 *)w.iv; 166 iv = (__be32 *)w.iv;
236 167
237 counter[0] = be32_to_cpu(iv[3]); 168 counter[0] = be32_to_cpu(iv[3]);
@@ -248,16 +179,14 @@ static int pre_crypt(struct skcipher_request *req)
248 wdst = w.dst.virt.addr; 179 wdst = w.dst.virt.addr;
249 180
250 do { 181 do {
251 *buf++ = rctx->t; 182 be128_xor(wdst++, &t, wsrc++);
252 be128_xor(wdst++, &rctx->t, wsrc++);
253 183
254 /* T <- I*Key2, using the optimization 184 /* T <- I*Key2, using the optimization
255 * discussed in the specification */ 185 * discussed in the specification */
256 be128_xor(&rctx->t, &rctx->t, 186 be128_xor(&t, &t, &ctx->mulinc[next_index(counter)]);
257 &ctx->mulinc[next_index(counter)]);
258 } while ((avail -= bs) >= bs); 187 } while ((avail -= bs) >= bs);
259 188
260 if (w.nbytes == w.total) { 189 if (second_pass && w.nbytes == w.total) {
261 iv[0] = cpu_to_be32(counter[3]); 190 iv[0] = cpu_to_be32(counter[3]);
262 iv[1] = cpu_to_be32(counter[2]); 191 iv[1] = cpu_to_be32(counter[2]);
263 iv[2] = cpu_to_be32(counter[1]); 192 iv[2] = cpu_to_be32(counter[1]);
@@ -267,175 +196,68 @@ static int pre_crypt(struct skcipher_request *req)
267 err = skcipher_walk_done(&w, avail); 196 err = skcipher_walk_done(&w, avail);
268 } 197 }
269 198
270 skcipher_request_set_tfm(subreq, ctx->child);
271 skcipher_request_set_crypt(subreq, rctx->dst, rctx->dst,
272 cryptlen, NULL);
273
274 if (err || !more)
275 goto out;
276
277 rctx->src = rctx->srcbuf;
278
279 scatterwalk_done(&w.in, 0, 1);
280 sg = w.in.sg;
281 offset = w.in.offset;
282
283 if (rctx->src != sg) {
284 rctx->src[0] = *sg;
285 sg_unmark_end(rctx->src);
286 scatterwalk_crypto_chain(rctx->src, sg_next(sg), 2);
287 }
288 rctx->src[0].length -= offset - sg->offset;
289 rctx->src[0].offset = offset;
290
291out:
292 return err; 199 return err;
293} 200}
294 201
295static int init_crypt(struct skcipher_request *req, crypto_completion_t done) 202static int xor_tweak_pre(struct skcipher_request *req)
296{ 203{
297 struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 204 return xor_tweak(req, false);
298 struct rctx *rctx = skcipher_request_ctx(req);
299 struct skcipher_request *subreq;
300 gfp_t gfp;
301
302 subreq = &rctx->subreq;
303 skcipher_request_set_callback(subreq, req->base.flags, done, req);
304
305 gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
306 GFP_ATOMIC;
307 rctx->ext = NULL;
308
309 subreq->cryptlen = LRW_BUFFER_SIZE;
310 if (req->cryptlen > LRW_BUFFER_SIZE) {
311 unsigned int n = min(req->cryptlen, (unsigned int)PAGE_SIZE);
312
313 rctx->ext = kmalloc(n, gfp);
314 if (rctx->ext)
315 subreq->cryptlen = n;
316 }
317
318 rctx->src = req->src;
319 rctx->dst = req->dst;
320 rctx->left = req->cryptlen;
321
322 /* calculate first value of T */
323 memcpy(&rctx->t, req->iv, sizeof(rctx->t));
324
325 /* T <- I*Key2 */
326 gf128mul_64k_bbe(&rctx->t, ctx->table);
327
328 return 0;
329} 205}
330 206
331static void exit_crypt(struct skcipher_request *req) 207static int xor_tweak_post(struct skcipher_request *req)
332{ 208{
333 struct rctx *rctx = skcipher_request_ctx(req); 209 return xor_tweak(req, true);
334
335 rctx->left = 0;
336
337 if (rctx->ext)
338 kzfree(rctx->ext);
339} 210}
340 211
341static int do_encrypt(struct skcipher_request *req, int err) 212static void crypt_done(struct crypto_async_request *areq, int err)
342{
343 struct rctx *rctx = skcipher_request_ctx(req);
344 struct skcipher_request *subreq;
345
346 subreq = &rctx->subreq;
347
348 while (!err && rctx->left) {
349 err = pre_crypt(req) ?:
350 crypto_skcipher_encrypt(subreq) ?:
351 post_crypt(req);
352
353 if (err == -EINPROGRESS || err == -EBUSY)
354 return err;
355 }
356
357 exit_crypt(req);
358 return err;
359}
360
361static void encrypt_done(struct crypto_async_request *areq, int err)
362{ 213{
363 struct skcipher_request *req = areq->data; 214 struct skcipher_request *req = areq->data;
364 struct skcipher_request *subreq;
365 struct rctx *rctx;
366
367 rctx = skcipher_request_ctx(req);
368
369 if (err == -EINPROGRESS) {
370 if (rctx->left != req->cryptlen)
371 return;
372 goto out;
373 }
374 215
375 subreq = &rctx->subreq; 216 if (!err)
376 subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; 217 err = xor_tweak_post(req);
377 218
378 err = do_encrypt(req, err ?: post_crypt(req));
379 if (rctx->left)
380 return;
381
382out:
383 skcipher_request_complete(req, err); 219 skcipher_request_complete(req, err);
384} 220}
385 221
386static int encrypt(struct skcipher_request *req) 222static void init_crypt(struct skcipher_request *req)
387{
388 return do_encrypt(req, init_crypt(req, encrypt_done));
389}
390
391static int do_decrypt(struct skcipher_request *req, int err)
392{ 223{
224 struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
393 struct rctx *rctx = skcipher_request_ctx(req); 225 struct rctx *rctx = skcipher_request_ctx(req);
394 struct skcipher_request *subreq; 226 struct skcipher_request *subreq = &rctx->subreq;
395 227
396 subreq = &rctx->subreq; 228 skcipher_request_set_tfm(subreq, ctx->child);
397 229 skcipher_request_set_callback(subreq, req->base.flags, crypt_done, req);
398 while (!err && rctx->left) { 230 /* pass req->iv as IV (will be used by xor_tweak, ECB will ignore it) */
399 err = pre_crypt(req) ?: 231 skcipher_request_set_crypt(subreq, req->dst, req->dst,
400 crypto_skcipher_decrypt(subreq) ?: 232 req->cryptlen, req->iv);
401 post_crypt(req);
402 233
403 if (err == -EINPROGRESS || err == -EBUSY) 234 /* calculate first value of T */
404 return err; 235 memcpy(&rctx->t, req->iv, sizeof(rctx->t));
405 }
406 236
407 exit_crypt(req); 237 /* T <- I*Key2 */
408 return err; 238 gf128mul_64k_bbe(&rctx->t, ctx->table);
409} 239}
410 240
411static void decrypt_done(struct crypto_async_request *areq, int err) 241static int encrypt(struct skcipher_request *req)
412{ 242{
413 struct skcipher_request *req = areq->data; 243 struct rctx *rctx = skcipher_request_ctx(req);
414 struct skcipher_request *subreq; 244 struct skcipher_request *subreq = &rctx->subreq;
415 struct rctx *rctx;
416
417 rctx = skcipher_request_ctx(req);
418
419 if (err == -EINPROGRESS) {
420 if (rctx->left != req->cryptlen)
421 return;
422 goto out;
423 }
424
425 subreq = &rctx->subreq;
426 subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
427
428 err = do_decrypt(req, err ?: post_crypt(req));
429 if (rctx->left)
430 return;
431 245
432out: 246 init_crypt(req);
433 skcipher_request_complete(req, err); 247 return xor_tweak_pre(req) ?:
248 crypto_skcipher_encrypt(subreq) ?:
249 xor_tweak_post(req);
434} 250}
435 251
436static int decrypt(struct skcipher_request *req) 252static int decrypt(struct skcipher_request *req)
437{ 253{
438 return do_decrypt(req, init_crypt(req, decrypt_done)); 254 struct rctx *rctx = skcipher_request_ctx(req);
255 struct skcipher_request *subreq = &rctx->subreq;
256
257 init_crypt(req);
258 return xor_tweak_pre(req) ?:
259 crypto_skcipher_decrypt(subreq) ?:
260 xor_tweak_post(req);
439} 261}
440 262
441static int init_tfm(struct crypto_skcipher *tfm) 263static int init_tfm(struct crypto_skcipher *tfm)