Blame view

crypto/lrw.c 14.8 KB
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
1
2
3
4
5
  /* LRW: as defined by Cyril Guyot in
   *	http://grouper.ieee.org/groups/1619/email/pdf00017.pdf
   *
   * Copyright (c) 2006 Rik Snel <rsnel@cube.dyndns.org>
   *
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
6
   * Based on ecb.c
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
7
8
9
10
11
12
13
14
15
16
17
18
   * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the Free
   * Software Foundation; either version 2 of the License, or (at your option)
   * any later version.
   */
  /* This implementation is checked against the test vectors in the above
   * document and by a test vector provided by Ken Buchanan at
   * http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html
   *
   * The test vectors are included in the testing module tcrypt.[ch] */
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
19

700cb3f5f   Herbert Xu   crypto: lrw - Con...
20
21
  #include <crypto/internal/skcipher.h>
  #include <crypto/scatterwalk.h>
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
22
23
24
25
26
27
28
29
30
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/scatterlist.h>
  #include <linux/slab.h>
  
  #include <crypto/b128ops.h>
  #include <crypto/gf128mul.h>
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
31
  #include <crypto/lrw.h>
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
32

700cb3f5f   Herbert Xu   crypto: lrw - Con...
33
  #define LRW_BUFFER_SIZE 128u
171c02048   Jussi Kivilinna   crypto: lrw - spl...
34
  struct priv {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
35
  	struct crypto_skcipher *child;
171c02048   Jussi Kivilinna   crypto: lrw - spl...
36
37
  	struct lrw_table_ctx table;
  };
700cb3f5f   Herbert Xu   crypto: lrw - Con...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  struct rctx {
  	be128 buf[LRW_BUFFER_SIZE / sizeof(be128)];
  
  	be128 t;
  
  	be128 *ext;
  
  	struct scatterlist srcbuf[2];
  	struct scatterlist dstbuf[2];
  	struct scatterlist *src;
  	struct scatterlist *dst;
  
  	unsigned int left;
  
  	struct skcipher_request subreq;
  };
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
54
55
  static inline void setbit128_bbe(void *b, int bit)
  {
8eb2dfac4   Herbert Xu   crypto: lrw - Fix...
56
57
58
59
60
61
62
  	__set_bit(bit ^ (0x80 -
  #ifdef __BIG_ENDIAN
  			 BITS_PER_LONG
  #else
  			 BITS_PER_BYTE
  #endif
  			), b);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
63
  }
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
64
  int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
65
  {
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
66
  	be128 tmp = { 0 };
171c02048   Jussi Kivilinna   crypto: lrw - spl...
67
  	int i;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
68
69
70
71
72
  
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
  
  	/* initialize multiplication table for Key2 */
171c02048   Jussi Kivilinna   crypto: lrw - spl...
73
  	ctx->table = gf128mul_init_64k_bbe((be128 *)tweak);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
74
75
76
77
78
79
80
81
82
83
84
85
  	if (!ctx->table)
  		return -ENOMEM;
  
  	/* initialize optimization table */
  	for (i = 0; i < 128; i++) {
  		setbit128_bbe(&tmp, i);
  		ctx->mulinc[i] = tmp;
  		gf128mul_64k_bbe(&ctx->mulinc[i], ctx->table);
  	}
  
  	return 0;
  }
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
86
  EXPORT_SYMBOL_GPL(lrw_init_table);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
87

6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
88
  void lrw_free_table(struct lrw_table_ctx *ctx)
171c02048   Jussi Kivilinna   crypto: lrw - spl...
89
90
91
92
  {
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
  }
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
93
  EXPORT_SYMBOL_GPL(lrw_free_table);
171c02048   Jussi Kivilinna   crypto: lrw - spl...
94

700cb3f5f   Herbert Xu   crypto: lrw - Con...
95
  static int setkey(struct crypto_skcipher *parent, const u8 *key,
171c02048   Jussi Kivilinna   crypto: lrw - spl...
96
97
  		  unsigned int keylen)
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
98
99
  	struct priv *ctx = crypto_skcipher_ctx(parent);
  	struct crypto_skcipher *child = ctx->child;
171c02048   Jussi Kivilinna   crypto: lrw - spl...
100
101
  	int err, bsize = LRW_BLOCK_SIZE;
  	const u8 *tweak = key + keylen - bsize;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
102
103
104
105
106
107
  	crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
  					 CRYPTO_TFM_REQ_MASK);
  	err = crypto_skcipher_setkey(child, key, keylen - bsize);
  	crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
  					  CRYPTO_TFM_RES_MASK);
171c02048   Jussi Kivilinna   crypto: lrw - spl...
108
109
  	if (err)
  		return err;
171c02048   Jussi Kivilinna   crypto: lrw - spl...
110
111
112
  
  	return lrw_init_table(&ctx->table, tweak);
  }
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
113
114
  static inline void inc(be128 *iv)
  {
fd4609a8e   Marcin Slusarz   [CRYPTO] lrw: Rep...
115
116
117
  	be64_add_cpu(&iv->b, 1);
  	if (!iv->b)
  		be64_add_cpu(&iv->a, 1);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
118
  }
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  /* this returns the number of consequative 1 bits starting
   * from the right, get_index128(00 00 00 00 00 00 ... 00 00 10 FB) = 2 */
  static inline int get_index128(be128 *block)
  {
  	int x;
  	__be32 *p = (__be32 *) block;
  
  	for (p += 3, x = 0; x < 128; p--, x += 32) {
  		u32 val = be32_to_cpup(p);
  
  		if (!~val)
  			continue;
  
  		return x + ffz(val);
  	}
  
  	return x;
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
137
  static int post_crypt(struct skcipher_request *req)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
138
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
139
140
141
142
143
144
145
  	struct rctx *rctx = skcipher_request_ctx(req);
  	be128 *buf = rctx->ext ?: rctx->buf;
  	struct skcipher_request *subreq;
  	const int bs = LRW_BLOCK_SIZE;
  	struct skcipher_walk w;
  	struct scatterlist *sg;
  	unsigned offset;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
146
  	int err;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  
  	subreq = &rctx->subreq;
  	err = skcipher_walk_virt(&w, subreq, false);
  
  	while (w.nbytes) {
  		unsigned int avail = w.nbytes;
  		be128 *wdst;
  
  		wdst = w.dst.virt.addr;
  
  		do {
  			be128_xor(wdst, buf++, wdst);
  			wdst++;
  		} while ((avail -= bs) >= bs);
  
  		err = skcipher_walk_done(&w, avail);
  	}
  
  	rctx->left -= subreq->cryptlen;
  
  	if (err || !rctx->left)
  		goto out;
  
  	rctx->dst = rctx->dstbuf;
  
  	scatterwalk_done(&w.out, 0, 1);
  	sg = w.out.sg;
  	offset = w.out.offset;
  
  	if (rctx->dst != sg) {
  		rctx->dst[0] = *sg;
  		sg_unmark_end(rctx->dst);
  		scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 0, 2);
  	}
  	rctx->dst[0].length -= offset - sg->offset;
  	rctx->dst[0].offset = offset;
  
  out:
  	return err;
  }
  
  static int pre_crypt(struct skcipher_request *req)
  {
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct rctx *rctx = skcipher_request_ctx(req);
  	struct priv *ctx = crypto_skcipher_ctx(tfm);
  	be128 *buf = rctx->ext ?: rctx->buf;
  	struct skcipher_request *subreq;
4660720df   Jussi Kivilinna   crypto: lrw - use...
195
  	const int bs = LRW_BLOCK_SIZE;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
196
197
198
199
  	struct skcipher_walk w;
  	struct scatterlist *sg;
  	unsigned cryptlen;
  	unsigned offset;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
200
  	be128 *iv;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
201
202
  	bool more;
  	int err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
203

700cb3f5f   Herbert Xu   crypto: lrw - Con...
204
205
  	subreq = &rctx->subreq;
  	skcipher_request_set_tfm(subreq, tfm);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
206

700cb3f5f   Herbert Xu   crypto: lrw - Con...
207
208
209
210
  	cryptlen = subreq->cryptlen;
  	more = rctx->left > cryptlen;
  	if (!more)
  		cryptlen = rctx->left;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
211

700cb3f5f   Herbert Xu   crypto: lrw - Con...
212
213
  	skcipher_request_set_crypt(subreq, rctx->src, rctx->dst,
  				   cryptlen, req->iv);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
214

700cb3f5f   Herbert Xu   crypto: lrw - Con...
215
216
  	err = skcipher_walk_virt(&w, subreq, false);
  	iv = w.iv;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
217

700cb3f5f   Herbert Xu   crypto: lrw - Con...
218
219
220
221
222
223
224
  	while (w.nbytes) {
  		unsigned int avail = w.nbytes;
  		be128 *wsrc;
  		be128 *wdst;
  
  		wsrc = w.src.virt.addr;
  		wdst = w.dst.virt.addr;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
225

64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
226
  		do {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
227
228
  			*buf++ = rctx->t;
  			be128_xor(wdst++, &rctx->t, wsrc++);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
229
230
  			/* T <- I*Key2, using the optimization
  			 * discussed in the specification */
700cb3f5f   Herbert Xu   crypto: lrw - Con...
231
  			be128_xor(&rctx->t, &rctx->t,
171c02048   Jussi Kivilinna   crypto: lrw - spl...
232
  				  &ctx->table.mulinc[get_index128(iv)]);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
233
  			inc(iv);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
234
  		} while ((avail -= bs) >= bs);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
235

700cb3f5f   Herbert Xu   crypto: lrw - Con...
236
237
  		err = skcipher_walk_done(&w, avail);
  	}
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
238

700cb3f5f   Herbert Xu   crypto: lrw - Con...
239
240
241
  	skcipher_request_set_tfm(subreq, ctx->child);
  	skcipher_request_set_crypt(subreq, rctx->dst, rctx->dst,
  				   cryptlen, NULL);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
242

700cb3f5f   Herbert Xu   crypto: lrw - Con...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  	if (err || !more)
  		goto out;
  
  	rctx->src = rctx->srcbuf;
  
  	scatterwalk_done(&w.in, 0, 1);
  	sg = w.in.sg;
  	offset = w.in.offset;
  
  	if (rctx->src != sg) {
  		rctx->src[0] = *sg;
  		sg_unmark_end(rctx->src);
  		scatterwalk_crypto_chain(rctx->src, sg_next(sg), 0, 2);
  	}
  	rctx->src[0].length -= offset - sg->offset;
  	rctx->src[0].offset = offset;
  
  out:
  	return err;
  }
  
  static int init_crypt(struct skcipher_request *req, crypto_completion_t done)
  {
  	struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
  	struct rctx *rctx = skcipher_request_ctx(req);
  	struct skcipher_request *subreq;
  	gfp_t gfp;
  
  	subreq = &rctx->subreq;
  	skcipher_request_set_callback(subreq, req->base.flags, done, req);
  
  	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
  							   GFP_ATOMIC;
  	rctx->ext = NULL;
  
  	subreq->cryptlen = LRW_BUFFER_SIZE;
  	if (req->cryptlen > LRW_BUFFER_SIZE) {
9df0eb180   Eric Biggers   crypto: xts,lrw -...
280
281
282
283
284
  		unsigned int n = min(req->cryptlen, (unsigned int)PAGE_SIZE);
  
  		rctx->ext = kmalloc(n, gfp);
  		if (rctx->ext)
  			subreq->cryptlen = n;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
285
286
287
288
289
290
291
292
293
294
295
  	}
  
  	rctx->src = req->src;
  	rctx->dst = req->dst;
  	rctx->left = req->cryptlen;
  
  	/* calculate first value of T */
  	memcpy(&rctx->t, req->iv, sizeof(rctx->t));
  
  	/* T <- I*Key2 */
  	gf128mul_64k_bbe(&rctx->t, ctx->table.table);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
296

700cb3f5f   Herbert Xu   crypto: lrw - Con...
297
298
299
300
301
302
303
304
305
306
  	return 0;
  }
  
  static void exit_crypt(struct skcipher_request *req)
  {
  	struct rctx *rctx = skcipher_request_ctx(req);
  
  	rctx->left = 0;
  
  	if (rctx->ext)
77827f3d6   Herbert Xu   crypto: lrw - Fre...
307
  		kzfree(rctx->ext);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  }
  
  static int do_encrypt(struct skcipher_request *req, int err)
  {
  	struct rctx *rctx = skcipher_request_ctx(req);
  	struct skcipher_request *subreq;
  
  	subreq = &rctx->subreq;
  
  	while (!err && rctx->left) {
  		err = pre_crypt(req) ?:
  		      crypto_skcipher_encrypt(subreq) ?:
  		      post_crypt(req);
  
  		if (err == -EINPROGRESS ||
  		    (err == -EBUSY &&
  		     req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
  			return err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
326
  	}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
327
  	exit_crypt(req);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
328
329
  	return err;
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
330
331
332
333
334
335
336
  static void encrypt_done(struct crypto_async_request *areq, int err)
  {
  	struct skcipher_request *req = areq->data;
  	struct skcipher_request *subreq;
  	struct rctx *rctx;
  
  	rctx = skcipher_request_ctx(req);
4702bbeef   Herbert Xu   crypto: lrw - Fix...
337
338
339
340
341
342
  
  	if (err == -EINPROGRESS) {
  		if (rctx->left != req->cryptlen)
  			return;
  		goto out;
  	}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
343
344
345
346
347
348
  	subreq = &rctx->subreq;
  	subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
  
  	err = do_encrypt(req, err ?: post_crypt(req));
  	if (rctx->left)
  		return;
4702bbeef   Herbert Xu   crypto: lrw - Fix...
349
  out:
700cb3f5f   Herbert Xu   crypto: lrw - Con...
350
351
352
353
354
355
356
357
358
  	skcipher_request_complete(req, err);
  }
  
  static int encrypt(struct skcipher_request *req)
  {
  	return do_encrypt(req, init_crypt(req, encrypt_done));
  }
  
  static int do_decrypt(struct skcipher_request *req, int err)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
359
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
  	struct rctx *rctx = skcipher_request_ctx(req);
  	struct skcipher_request *subreq;
  
  	subreq = &rctx->subreq;
  
  	while (!err && rctx->left) {
  		err = pre_crypt(req) ?:
  		      crypto_skcipher_decrypt(subreq) ?:
  		      post_crypt(req);
  
  		if (err == -EINPROGRESS ||
  		    (err == -EBUSY &&
  		     req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
  			return err;
  	}
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
375

700cb3f5f   Herbert Xu   crypto: lrw - Con...
376
377
  	exit_crypt(req);
  	return err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
378
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
379
  static void decrypt_done(struct crypto_async_request *areq, int err)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
380
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
381
382
383
384
385
  	struct skcipher_request *req = areq->data;
  	struct skcipher_request *subreq;
  	struct rctx *rctx;
  
  	rctx = skcipher_request_ctx(req);
4702bbeef   Herbert Xu   crypto: lrw - Fix...
386
387
388
389
390
391
  
  	if (err == -EINPROGRESS) {
  		if (rctx->left != req->cryptlen)
  			return;
  		goto out;
  	}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
392
393
394
395
396
397
  	subreq = &rctx->subreq;
  	subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
  
  	err = do_decrypt(req, err ?: post_crypt(req));
  	if (rctx->left)
  		return;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
398

4702bbeef   Herbert Xu   crypto: lrw - Fix...
399
  out:
700cb3f5f   Herbert Xu   crypto: lrw - Con...
400
401
402
403
404
405
  	skcipher_request_complete(req, err);
  }
  
  static int decrypt(struct skcipher_request *req)
  {
  	return do_decrypt(req, init_crypt(req, decrypt_done));
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
406
  }
6c2205b8f   Jussi Kivilinna   crypto: lrw - add...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
  	      struct scatterlist *ssrc, unsigned int nbytes,
  	      struct lrw_crypt_req *req)
  {
  	const unsigned int bsize = LRW_BLOCK_SIZE;
  	const unsigned int max_blks = req->tbuflen / bsize;
  	struct lrw_table_ctx *ctx = req->table_ctx;
  	struct blkcipher_walk walk;
  	unsigned int nblocks;
  	be128 *iv, *src, *dst, *t;
  	be128 *t_buf = req->tbuf;
  	int err, i;
  
  	BUG_ON(max_blks < 1);
  
  	blkcipher_walk_init(&walk, sdst, ssrc, nbytes);
  
  	err = blkcipher_walk_virt(desc, &walk);
  	nbytes = walk.nbytes;
  	if (!nbytes)
  		return err;
  
  	nblocks = min(walk.nbytes / bsize, max_blks);
  	src = (be128 *)walk.src.virt.addr;
  	dst = (be128 *)walk.dst.virt.addr;
  
  	/* calculate first value of T */
  	iv = (be128 *)walk.iv;
  	t_buf[0] = *iv;
  
  	/* T <- I*Key2 */
  	gf128mul_64k_bbe(&t_buf[0], ctx->table);
  
  	i = 0;
  	goto first;
  
  	for (;;) {
  		do {
  			for (i = 0; i < nblocks; i++) {
  				/* T <- I*Key2, using the optimization
  				 * discussed in the specification */
  				be128_xor(&t_buf[i], t,
  						&ctx->mulinc[get_index128(iv)]);
  				inc(iv);
  first:
  				t = &t_buf[i];
  
  				/* PP <- T xor P */
  				be128_xor(dst + i, t, src + i);
  			}
  
  			/* CC <- E(Key2,PP) */
  			req->crypt_fn(req->crypt_ctx, (u8 *)dst,
  				      nblocks * bsize);
  
  			/* C <- T xor CC */
  			for (i = 0; i < nblocks; i++)
  				be128_xor(dst + i, dst + i, &t_buf[i]);
  
  			src += nblocks;
  			dst += nblocks;
  			nbytes -= nblocks * bsize;
  			nblocks = min(nbytes / bsize, max_blks);
  		} while (nblocks > 0);
  
  		err = blkcipher_walk_done(desc, &walk, nbytes);
  		nbytes = walk.nbytes;
  		if (!nbytes)
  			break;
  
  		nblocks = min(nbytes / bsize, max_blks);
  		src = (be128 *)walk.src.virt.addr;
  		dst = (be128 *)walk.dst.virt.addr;
  	}
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(lrw_crypt);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
485
  static int init_tfm(struct crypto_skcipher *tfm)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
486
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
487
488
489
490
  	struct skcipher_instance *inst = skcipher_alg_instance(tfm);
  	struct crypto_skcipher_spawn *spawn = skcipher_instance_ctx(inst);
  	struct priv *ctx = crypto_skcipher_ctx(tfm);
  	struct crypto_skcipher *cipher;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
491

700cb3f5f   Herbert Xu   crypto: lrw - Con...
492
  	cipher = crypto_spawn_skcipher(spawn);
2e306ee01   Herbert Xu   [CRYPTO] api: Add...
493
494
  	if (IS_ERR(cipher))
  		return PTR_ERR(cipher);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
495

2e306ee01   Herbert Xu   [CRYPTO] api: Add...
496
  	ctx->child = cipher;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
497
498
499
  
  	crypto_skcipher_set_reqsize(tfm, crypto_skcipher_reqsize(cipher) +
  					 sizeof(struct rctx));
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
500
501
  	return 0;
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
502
  static void exit_tfm(struct crypto_skcipher *tfm)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
503
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
504
  	struct priv *ctx = crypto_skcipher_ctx(tfm);
171c02048   Jussi Kivilinna   crypto: lrw - spl...
505
506
  
  	lrw_free_table(&ctx->table);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
507
508
509
510
511
512
513
  	crypto_free_skcipher(ctx->child);
  }
  
  static void free(struct skcipher_instance *inst)
  {
  	crypto_drop_skcipher(skcipher_instance_ctx(inst));
  	kfree(inst);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
514
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
515
  static int create(struct crypto_template *tmpl, struct rtattr **tb)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
516
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
517
518
519
520
521
522
  	struct crypto_skcipher_spawn *spawn;
  	struct skcipher_instance *inst;
  	struct crypto_attr_type *algt;
  	struct skcipher_alg *alg;
  	const char *cipher_name;
  	char ecb_name[CRYPTO_MAX_ALG_NAME];
ebc610e5b   Herbert Xu   [CRYPTO] template...
523
  	int err;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
  	algt = crypto_get_attr_type(tb);
  	if (IS_ERR(algt))
  		return PTR_ERR(algt);
  
  	if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask)
  		return -EINVAL;
  
  	cipher_name = crypto_attr_alg_name(tb[1]);
  	if (IS_ERR(cipher_name))
  		return PTR_ERR(cipher_name);
  
  	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
  	if (!inst)
  		return -ENOMEM;
  
  	spawn = skcipher_instance_ctx(inst);
  
  	crypto_set_skcipher_spawn(spawn, skcipher_crypto_instance(inst));
  	err = crypto_grab_skcipher(spawn, cipher_name, 0,
  				   crypto_requires_sync(algt->type,
  							algt->mask));
  	if (err == -ENOENT) {
  		err = -ENAMETOOLONG;
  		if (snprintf(ecb_name, CRYPTO_MAX_ALG_NAME, "ecb(%s)",
  			     cipher_name) >= CRYPTO_MAX_ALG_NAME)
  			goto err_free_inst;
  
  		err = crypto_grab_skcipher(spawn, ecb_name, 0,
  					   crypto_requires_sync(algt->type,
  								algt->mask));
  	}
ebc610e5b   Herbert Xu   [CRYPTO] template...
555
  	if (err)
700cb3f5f   Herbert Xu   crypto: lrw - Con...
556
  		goto err_free_inst;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
557

700cb3f5f   Herbert Xu   crypto: lrw - Con...
558
  	alg = crypto_skcipher_spawn_alg(spawn);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
559

700cb3f5f   Herbert Xu   crypto: lrw - Con...
560
561
562
  	err = -EINVAL;
  	if (alg->base.cra_blocksize != LRW_BLOCK_SIZE)
  		goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
563

700cb3f5f   Herbert Xu   crypto: lrw - Con...
564
565
  	if (crypto_skcipher_alg_ivsize(alg))
  		goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
566

700cb3f5f   Herbert Xu   crypto: lrw - Con...
567
568
569
570
  	err = crypto_inst_setname(skcipher_crypto_instance(inst), "lrw",
  				  &alg->base);
  	if (err)
  		goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
571

700cb3f5f   Herbert Xu   crypto: lrw - Con...
572
573
  	err = -EINVAL;
  	cipher_name = alg->base.cra_name;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
574

700cb3f5f   Herbert Xu   crypto: lrw - Con...
575
576
577
578
579
  	/* Alas we screwed up the naming so we have to mangle the
  	 * cipher name.
  	 */
  	if (!strncmp(cipher_name, "ecb(", 4)) {
  		unsigned len;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
580

700cb3f5f   Herbert Xu   crypto: lrw - Con...
581
582
583
  		len = strlcpy(ecb_name, cipher_name + 4, sizeof(ecb_name));
  		if (len < 2 || len >= sizeof(ecb_name))
  			goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
584

700cb3f5f   Herbert Xu   crypto: lrw - Con...
585
586
  		if (ecb_name[len - 1] != ')')
  			goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
587

700cb3f5f   Herbert Xu   crypto: lrw - Con...
588
  		ecb_name[len - 1] = 0;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
589

700cb3f5f   Herbert Xu   crypto: lrw - Con...
590
  		if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
bd5139895   Christophe Jaillet   crypto: lrw - Fix...
591
592
593
594
  			     "lrw(%s)", ecb_name) >= CRYPTO_MAX_ALG_NAME) {
  			err = -ENAMETOOLONG;
  			goto err_drop_spawn;
  		}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  	}
  
  	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
  	inst->alg.base.cra_priority = alg->base.cra_priority;
  	inst->alg.base.cra_blocksize = LRW_BLOCK_SIZE;
  	inst->alg.base.cra_alignmask = alg->base.cra_alignmask |
  				       (__alignof__(u64) - 1);
  
  	inst->alg.ivsize = LRW_BLOCK_SIZE;
  	inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg) +
  				LRW_BLOCK_SIZE;
  	inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(alg) +
  				LRW_BLOCK_SIZE;
  
  	inst->alg.base.cra_ctxsize = sizeof(struct priv);
  
  	inst->alg.init = init_tfm;
  	inst->alg.exit = exit_tfm;
  
  	inst->alg.setkey = setkey;
  	inst->alg.encrypt = encrypt;
  	inst->alg.decrypt = decrypt;
  
  	inst->free = free;
  
  	err = skcipher_register_instance(tmpl, inst);
  	if (err)
  		goto err_drop_spawn;
  
  out:
  	return err;
  
  err_drop_spawn:
  	crypto_drop_skcipher(spawn);
  err_free_inst:
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
630
  	kfree(inst);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
631
  	goto out;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
632
633
634
635
  }
  
  static struct crypto_template crypto_tmpl = {
  	.name = "lrw",
700cb3f5f   Herbert Xu   crypto: lrw - Con...
636
  	.create = create,
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
  	.module = THIS_MODULE,
  };
  
  static int __init crypto_module_init(void)
  {
  	return crypto_register_template(&crypto_tmpl);
  }
  
  static void __exit crypto_module_exit(void)
  {
  	crypto_unregister_template(&crypto_tmpl);
  }
  
  module_init(crypto_module_init);
  module_exit(crypto_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("LRW block cipher mode");
4943ba16b   Kees Cook   crypto: include c...
655
  MODULE_ALIAS_CRYPTO("lrw");