diff options
-rw-r--r-- | crypto/lrw.c | 106 | ||||
-rw-r--r-- | include/crypto/lrw.h | 43 |
2 files changed, 129 insertions, 20 deletions
diff --git a/crypto/lrw.c b/crypto/lrw.c index 91c17fa18374..ba42acc4deba 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2006 Rik Snel <rsnel@cube.dyndns.org> | 4 | * Copyright (c) 2006 Rik Snel <rsnel@cube.dyndns.org> |
5 | * | 5 | * |
6 | * Based om ecb.c | 6 | * Based on ecb.c |
7 | * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> | 7 | * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
@@ -16,6 +16,7 @@ | |||
16 | * http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html | 16 | * http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html |
17 | * | 17 | * |
18 | * The test vectors are included in the testing module tcrypt.[ch] */ | 18 | * The test vectors are included in the testing module tcrypt.[ch] */ |
19 | |||
19 | #include <crypto/algapi.h> | 20 | #include <crypto/algapi.h> |
20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
@@ -26,23 +27,7 @@ | |||
26 | 27 | ||
27 | #include <crypto/b128ops.h> | 28 | #include <crypto/b128ops.h> |
28 | #include <crypto/gf128mul.h> | 29 | #include <crypto/gf128mul.h> |
29 | 30 | #include <crypto/lrw.h> | |
30 | #define LRW_BLOCK_SIZE 16 | ||
31 | |||
32 | struct lrw_table_ctx { | ||
33 | /* optimizes multiplying a random (non incrementing, as at the | ||
34 | * start of a new sector) value with key2, we could also have | ||
35 | * used 4k optimization tables or no optimization at all. In the | ||
36 | * latter case we would have to store key2 here */ | ||
37 | struct gf128mul_64k *table; | ||
38 | /* stores: | ||
39 | * key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 }, | ||
40 | * key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 } | ||
41 | * key2*{ 0,0,...1,1,1,1,1 }, etc | ||
42 | * needed for optimized multiplication of incrementing values | ||
43 | * with key2 */ | ||
44 | be128 mulinc[128]; | ||
45 | }; | ||
46 | 31 | ||
47 | struct priv { | 32 | struct priv { |
48 | struct crypto_cipher *child; | 33 | struct crypto_cipher *child; |
@@ -60,7 +45,7 @@ static inline void setbit128_bbe(void *b, int bit) | |||
60 | ), b); | 45 | ), b); |
61 | } | 46 | } |
62 | 47 | ||
63 | static int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak) | 48 | int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak) |
64 | { | 49 | { |
65 | be128 tmp = { 0 }; | 50 | be128 tmp = { 0 }; |
66 | int i; | 51 | int i; |
@@ -82,12 +67,14 @@ static int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak) | |||
82 | 67 | ||
83 | return 0; | 68 | return 0; |
84 | } | 69 | } |
70 | EXPORT_SYMBOL_GPL(lrw_init_table); | ||
85 | 71 | ||
86 | static void lrw_free_table(struct lrw_table_ctx *ctx) | 72 | void lrw_free_table(struct lrw_table_ctx *ctx) |
87 | { | 73 | { |
88 | if (ctx->table) | 74 | if (ctx->table) |
89 | gf128mul_free_64k(ctx->table); | 75 | gf128mul_free_64k(ctx->table); |
90 | } | 76 | } |
77 | EXPORT_SYMBOL_GPL(lrw_free_table); | ||
91 | 78 | ||
92 | static int setkey(struct crypto_tfm *parent, const u8 *key, | 79 | static int setkey(struct crypto_tfm *parent, const u8 *key, |
93 | unsigned int keylen) | 80 | unsigned int keylen) |
@@ -227,6 +214,85 @@ static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, | |||
227 | crypto_cipher_alg(ctx->child)->cia_decrypt); | 214 | crypto_cipher_alg(ctx->child)->cia_decrypt); |
228 | } | 215 | } |
229 | 216 | ||
217 | int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst, | ||
218 | struct scatterlist *ssrc, unsigned int nbytes, | ||
219 | struct lrw_crypt_req *req) | ||
220 | { | ||
221 | const unsigned int bsize = LRW_BLOCK_SIZE; | ||
222 | const unsigned int max_blks = req->tbuflen / bsize; | ||
223 | struct lrw_table_ctx *ctx = req->table_ctx; | ||
224 | struct blkcipher_walk walk; | ||
225 | unsigned int nblocks; | ||
226 | be128 *iv, *src, *dst, *t; | ||
227 | be128 *t_buf = req->tbuf; | ||
228 | int err, i; | ||
229 | |||
230 | BUG_ON(max_blks < 1); | ||
231 | |||
232 | blkcipher_walk_init(&walk, sdst, ssrc, nbytes); | ||
233 | |||
234 | err = blkcipher_walk_virt(desc, &walk); | ||
235 | nbytes = walk.nbytes; | ||
236 | if (!nbytes) | ||
237 | return err; | ||
238 | |||
239 | nblocks = min(walk.nbytes / bsize, max_blks); | ||
240 | src = (be128 *)walk.src.virt.addr; | ||
241 | dst = (be128 *)walk.dst.virt.addr; | ||
242 | |||
243 | /* calculate first value of T */ | ||
244 | iv = (be128 *)walk.iv; | ||
245 | t_buf[0] = *iv; | ||
246 | |||
247 | /* T <- I*Key2 */ | ||
248 | gf128mul_64k_bbe(&t_buf[0], ctx->table); | ||
249 | |||
250 | i = 0; | ||
251 | goto first; | ||
252 | |||
253 | for (;;) { | ||
254 | do { | ||
255 | for (i = 0; i < nblocks; i++) { | ||
256 | /* T <- I*Key2, using the optimization | ||
257 | * discussed in the specification */ | ||
258 | be128_xor(&t_buf[i], t, | ||
259 | &ctx->mulinc[get_index128(iv)]); | ||
260 | inc(iv); | ||
261 | first: | ||
262 | t = &t_buf[i]; | ||
263 | |||
264 | /* PP <- T xor P */ | ||
265 | be128_xor(dst + i, t, src + i); | ||
266 | } | ||
267 | |||
268 | /* CC <- E(Key2,PP) */ | ||
269 | req->crypt_fn(req->crypt_ctx, (u8 *)dst, | ||
270 | nblocks * bsize); | ||
271 | |||
272 | /* C <- T xor CC */ | ||
273 | for (i = 0; i < nblocks; i++) | ||
274 | be128_xor(dst + i, dst + i, &t_buf[i]); | ||
275 | |||
276 | src += nblocks; | ||
277 | dst += nblocks; | ||
278 | nbytes -= nblocks * bsize; | ||
279 | nblocks = min(nbytes / bsize, max_blks); | ||
280 | } while (nblocks > 0); | ||
281 | |||
282 | err = blkcipher_walk_done(desc, &walk, nbytes); | ||
283 | nbytes = walk.nbytes; | ||
284 | if (!nbytes) | ||
285 | break; | ||
286 | |||
287 | nblocks = min(nbytes / bsize, max_blks); | ||
288 | src = (be128 *)walk.src.virt.addr; | ||
289 | dst = (be128 *)walk.dst.virt.addr; | ||
290 | } | ||
291 | |||
292 | return err; | ||
293 | } | ||
294 | EXPORT_SYMBOL_GPL(lrw_crypt); | ||
295 | |||
230 | static int init_tfm(struct crypto_tfm *tfm) | 296 | static int init_tfm(struct crypto_tfm *tfm) |
231 | { | 297 | { |
232 | struct crypto_cipher *cipher; | 298 | struct crypto_cipher *cipher; |
diff --git a/include/crypto/lrw.h b/include/crypto/lrw.h new file mode 100644 index 000000000000..25a2c8716375 --- /dev/null +++ b/include/crypto/lrw.h | |||
@@ -0,0 +1,43 @@ | |||
1 | #ifndef _CRYPTO_LRW_H | ||
2 | #define _CRYPTO_LRW_H | ||
3 | |||
4 | #include <crypto/b128ops.h> | ||
5 | |||
6 | struct scatterlist; | ||
7 | struct gf128mul_64k; | ||
8 | struct blkcipher_desc; | ||
9 | |||
10 | #define LRW_BLOCK_SIZE 16 | ||
11 | |||
12 | struct lrw_table_ctx { | ||
13 | /* optimizes multiplying a random (non incrementing, as at the | ||
14 | * start of a new sector) value with key2, we could also have | ||
15 | * used 4k optimization tables or no optimization at all. In the | ||
16 | * latter case we would have to store key2 here */ | ||
17 | struct gf128mul_64k *table; | ||
18 | /* stores: | ||
19 | * key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 }, | ||
20 | * key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 } | ||
21 | * key2*{ 0,0,...1,1,1,1,1 }, etc | ||
22 | * needed for optimized multiplication of incrementing values | ||
23 | * with key2 */ | ||
24 | be128 mulinc[128]; | ||
25 | }; | ||
26 | |||
27 | int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak); | ||
28 | void lrw_free_table(struct lrw_table_ctx *ctx); | ||
29 | |||
30 | struct lrw_crypt_req { | ||
31 | be128 *tbuf; | ||
32 | unsigned int tbuflen; | ||
33 | |||
34 | struct lrw_table_ctx *table_ctx; | ||
35 | void *crypt_ctx; | ||
36 | void (*crypt_fn)(void *ctx, u8 *blks, unsigned int nbytes); | ||
37 | }; | ||
38 | |||
39 | int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, | ||
40 | struct scatterlist *src, unsigned int nbytes, | ||
41 | struct lrw_crypt_req *req); | ||
42 | |||
43 | #endif /* _CRYPTO_LRW_H */ | ||