Blame view

crypto/lrw.c 13.4 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>
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
31

700cb3f5f   Herbert Xu   crypto: lrw - Con...
32
  #define LRW_BUFFER_SIZE 128u
217afccf6   Eric Biggers   crypto: lrw - rem...
33
  #define LRW_BLOCK_SIZE 16
171c02048   Jussi Kivilinna   crypto: lrw - spl...
34
  struct priv {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
35
  	struct crypto_skcipher *child;
217afccf6   Eric Biggers   crypto: lrw - rem...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  	/*
  	 * optimizes multiplying a random (non incrementing, as at the
  	 * start of a new sector) value with key2, we could also have
  	 * used 4k optimization tables or no optimization at all. In the
  	 * latter case we would have to store key2 here
  	 */
  	struct gf128mul_64k *table;
  
  	/*
  	 * stores:
  	 *  key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
  	 *  key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
  	 *  key2*{ 0,0,...1,1,1,1,1 }, etc
  	 * needed for optimized multiplication of incrementing values
  	 * with key2
  	 */
  	be128 mulinc[128];
171c02048   Jussi Kivilinna   crypto: lrw - spl...
54
  };
700cb3f5f   Herbert Xu   crypto: lrw - Con...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  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...
71
72
  static inline void setbit128_bbe(void *b, int bit)
  {
8eb2dfac4   Herbert Xu   crypto: lrw - Fix...
73
74
75
76
77
78
79
  	__set_bit(bit ^ (0x80 -
  #ifdef __BIG_ENDIAN
  			 BITS_PER_LONG
  #else
  			 BITS_PER_BYTE
  #endif
  			), b);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
80
  }
217afccf6   Eric Biggers   crypto: lrw - rem...
81
82
  static int setkey(struct crypto_skcipher *parent, const u8 *key,
  		  unsigned int keylen)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
83
  {
217afccf6   Eric Biggers   crypto: lrw - rem...
84
85
86
87
  	struct priv *ctx = crypto_skcipher_ctx(parent);
  	struct crypto_skcipher *child = ctx->child;
  	int err, bsize = LRW_BLOCK_SIZE;
  	const u8 *tweak = key + keylen - bsize;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
88
  	be128 tmp = { 0 };
171c02048   Jussi Kivilinna   crypto: lrw - spl...
89
  	int i;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
90

217afccf6   Eric Biggers   crypto: lrw - rem...
91
92
93
94
95
96
97
98
  	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);
  	if (err)
  		return err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
99
100
101
102
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
  
  	/* initialize multiplication table for Key2 */
171c02048   Jussi Kivilinna   crypto: lrw - spl...
103
  	ctx->table = gf128mul_init_64k_bbe((be128 *)tweak);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
104
105
106
107
108
109
110
111
112
113
114
115
  	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;
  }
171c02048   Jussi Kivilinna   crypto: lrw - spl...
116

64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
117
118
  static inline void inc(be128 *iv)
  {
fd4609a8e   Marcin Slusarz   [CRYPTO] lrw: Rep...
119
120
121
  	be64_add_cpu(&iv->b, 1);
  	if (!iv->b)
  		be64_add_cpu(&iv->a, 1);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
122
  }
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  /* 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);
  	}
c2ff39496   Ondrej Mosnacek   crypto: lrw - Fix...
138
139
140
141
142
143
  	/*
  	 * If we get here, then x == 128 and we are incrementing the counter
  	 * from all ones to all zeros. This means we must return index 127, i.e.
  	 * the one corresponding to key2*{ 1,...,1 }.
  	 */
  	return 127;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
144
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
145
  static int post_crypt(struct skcipher_request *req)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
146
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
147
148
149
150
151
152
153
  	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...
154
  	int err;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
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
  
  	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);
8c30fbe63   Eric Biggers   crypto: scatterwa...
187
  		scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 2);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	}
  	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...
203
  	const int bs = LRW_BLOCK_SIZE;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
204
205
206
207
  	struct skcipher_walk w;
  	struct scatterlist *sg;
  	unsigned cryptlen;
  	unsigned offset;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
208
  	be128 *iv;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
209
210
  	bool more;
  	int err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
211

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
215
216
217
218
  	cryptlen = subreq->cryptlen;
  	more = rctx->left > cryptlen;
  	if (!more)
  		cryptlen = rctx->left;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
219

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

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
226
227
228
229
230
231
232
  	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...
233

64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
234
  		do {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
235
236
  			*buf++ = rctx->t;
  			be128_xor(wdst++, &rctx->t, wsrc++);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
237
238
  			/* T <- I*Key2, using the optimization
  			 * discussed in the specification */
700cb3f5f   Herbert Xu   crypto: lrw - Con...
239
  			be128_xor(&rctx->t, &rctx->t,
217afccf6   Eric Biggers   crypto: lrw - rem...
240
  				  &ctx->mulinc[get_index128(iv)]);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
241
  			inc(iv);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
242
  		} while ((avail -= bs) >= bs);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
243

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

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
251
252
253
254
255
256
257
258
259
260
261
262
  	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);
8c30fbe63   Eric Biggers   crypto: scatterwa...
263
  		scatterwalk_crypto_chain(rctx->src, sg_next(sg), 2);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	}
  	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 -...
288
289
290
291
292
  		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...
293
294
295
296
297
298
299
300
301
302
  	}
  
  	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 */
217afccf6   Eric Biggers   crypto: lrw - rem...
303
  	gf128mul_64k_bbe(&rctx->t, ctx->table);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
304

700cb3f5f   Herbert Xu   crypto: lrw - Con...
305
306
307
308
309
310
311
312
313
314
  	return 0;
  }
  
  static void exit_crypt(struct skcipher_request *req)
  {
  	struct rctx *rctx = skcipher_request_ctx(req);
  
  	rctx->left = 0;
  
  	if (rctx->ext)
8c9bdab21   Herbert Xu   crypto: lrw - Fre...
315
  		kzfree(rctx->ext);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
316
317
318
319
320
321
322
323
324
325
326
327
328
  }
  
  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);
4e5b0ad58   Gilad Ben-Yossef   crypto: remove re...
329
  		if (err == -EINPROGRESS || err == -EBUSY)
700cb3f5f   Herbert Xu   crypto: lrw - Con...
330
  			return err;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
331
  	}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
332
  	exit_crypt(req);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
333
334
  	return err;
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
335
336
337
338
339
340
341
  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...
342
343
344
345
346
347
  
  	if (err == -EINPROGRESS) {
  		if (rctx->left != req->cryptlen)
  			return;
  		goto out;
  	}
700cb3f5f   Herbert Xu   crypto: lrw - Con...
348
349
350
351
352
353
  	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...
354
  out:
700cb3f5f   Herbert Xu   crypto: lrw - Con...
355
356
357
358
359
360
361
362
363
  	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...
364
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
365
366
367
368
369
370
371
372
373
  	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);
4e5b0ad58   Gilad Ben-Yossef   crypto: remove re...
374
  		if (err == -EINPROGRESS || err == -EBUSY)
700cb3f5f   Herbert Xu   crypto: lrw - Con...
375
376
  			return err;
  	}
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
377

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

4702bbeef   Herbert Xu   crypto: lrw - Fix...
401
  out:
700cb3f5f   Herbert Xu   crypto: lrw - Con...
402
403
404
405
406
407
  	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...
408
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
409
  static int init_tfm(struct crypto_skcipher *tfm)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
410
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
411
412
413
414
  	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...
415

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

2e306ee01   Herbert Xu   [CRYPTO] api: Add...
420
  	ctx->child = cipher;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
421
422
423
  
  	crypto_skcipher_set_reqsize(tfm, crypto_skcipher_reqsize(cipher) +
  					 sizeof(struct rctx));
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
424
425
  	return 0;
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
426
  static void exit_tfm(struct crypto_skcipher *tfm)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
427
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
428
  	struct priv *ctx = crypto_skcipher_ctx(tfm);
171c02048   Jussi Kivilinna   crypto: lrw - spl...
429

217afccf6   Eric Biggers   crypto: lrw - rem...
430
431
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
432
433
434
435
436
437
438
  	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...
439
  }
700cb3f5f   Herbert Xu   crypto: lrw - Con...
440
  static int create(struct crypto_template *tmpl, struct rtattr **tb)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
441
  {
700cb3f5f   Herbert Xu   crypto: lrw - Con...
442
443
444
445
446
447
  	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...
448
  	int err;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
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
  	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...
480
  	if (err)
700cb3f5f   Herbert Xu   crypto: lrw - Con...
481
  		goto err_free_inst;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
482

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

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

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
492
493
494
495
  	err = crypto_inst_setname(skcipher_crypto_instance(inst), "lrw",
  				  &alg->base);
  	if (err)
  		goto err_drop_spawn;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
496

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
500
501
502
503
504
  	/* 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...
505

700cb3f5f   Herbert Xu   crypto: lrw - Con...
506
507
508
  		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...
509

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

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

700cb3f5f   Herbert Xu   crypto: lrw - Con...
515
  		if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
616129cc6   Christophe Jaillet   crypto: lrw - Fix...
516
517
518
519
  			     "lrw(%s)", ecb_name) >= CRYPTO_MAX_ALG_NAME) {
  			err = -ENAMETOOLONG;
  			goto err_drop_spawn;
  		}
d38efad2b   Christophe Jaillet   crypto: lrw - Che...
520
521
  	} else
  		goto err_drop_spawn;
700cb3f5f   Herbert Xu   crypto: lrw - Con...
522
523
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
555
  
  	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...
556
  	kfree(inst);
700cb3f5f   Herbert Xu   crypto: lrw - Con...
557
  	goto out;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
558
559
560
561
  }
  
  static struct crypto_template crypto_tmpl = {
  	.name = "lrw",
700cb3f5f   Herbert Xu   crypto: lrw - Con...
562
  	.create = create,
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  	.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...
581
  MODULE_ALIAS_CRYPTO("lrw");