Blame view

crypto/lrw.c 7.62 KB
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  /* 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>
   *
   * Based om ecb.c
   * 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] */
  #include <crypto/algapi.h>
  #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>
  
  struct priv {
  	struct crypto_cipher *child;
  	/* 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];
  };
  
  static inline void setbit128_bbe(void *b, int bit)
  {
8eb2dfac4   Herbert Xu   crypto: lrw - Fix...
48
49
50
51
52
53
54
  	__set_bit(bit ^ (0x80 -
  #ifdef __BIG_ENDIAN
  			 BITS_PER_LONG
  #else
  			 BITS_PER_BYTE
  #endif
  			), b);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  }
  
  static int setkey(struct crypto_tfm *parent, const u8 *key,
  		  unsigned int keylen)
  {
  	struct priv *ctx = crypto_tfm_ctx(parent);
  	struct crypto_cipher *child = ctx->child;
  	int err, i;
  	be128 tmp = { 0 };
  	int bsize = crypto_cipher_blocksize(child);
  
  	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
  				       CRYPTO_TFM_REQ_MASK);
  	if ((err = crypto_cipher_setkey(child, key, keylen - bsize)))
  		return err;
  	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
  				     CRYPTO_TFM_RES_MASK);
  
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
  
  	/* initialize multiplication table for Key2 */
  	ctx->table = gf128mul_init_64k_bbe((be128 *)(key + keylen - bsize));
  	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;
  }
  
  struct sinfo {
  	be128 t;
  	struct crypto_tfm *tfm;
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  };
  
  static inline void inc(be128 *iv)
  {
fd4609a8e   Marcin Slusarz   [CRYPTO] lrw: Rep...
100
101
102
  	be64_add_cpu(&iv->b, 1);
  	if (!iv->b)
  		be64_add_cpu(&iv->a, 1);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
103
  }
9ebed9d18   David S. Miller   [CRYPTO] lrw: rou...
104
  static inline void lrw_round(struct sinfo *s, void *dst, const void *src)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  {
  	be128_xor(dst, &s->t, src);		/* PP <- T xor P */
  	s->fn(s->tfm, dst, dst);		/* CC <- E(Key2,PP) */
  	be128_xor(dst, dst, &s->t);		/* C <- T xor CC */
  }
  
  /* 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;
  }
  
  static int crypt(struct blkcipher_desc *d,
  		 struct blkcipher_walk *w, struct priv *ctx,
  		 void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
  {
  	int err;
  	unsigned int avail;
  	const int bs = crypto_cipher_blocksize(ctx->child);
  	struct sinfo s = {
  		.tfm = crypto_cipher_tfm(ctx->child),
  		.fn = fn
  	};
  	be128 *iv;
  	u8 *wsrc;
  	u8 *wdst;
  
  	err = blkcipher_walk_virt(d, w);
  	if (!(avail = w->nbytes))
  		return err;
  
  	wsrc = w->src.virt.addr;
  	wdst = w->dst.virt.addr;
  
  	/* calculate first value of T */
  	iv = (be128 *)w->iv;
  	s.t = *iv;
  
  	/* T <- I*Key2 */
  	gf128mul_64k_bbe(&s.t, ctx->table);
  
  	goto first;
  
  	for (;;) {
  		do {
  			/* T <- I*Key2, using the optimization
  			 * discussed in the specification */
  			be128_xor(&s.t, &s.t, &ctx->mulinc[get_index128(iv)]);
  			inc(iv);
  
  first:
9ebed9d18   David S. Miller   [CRYPTO] lrw: rou...
169
  			lrw_round(&s, wdst, wsrc);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  
  			wsrc += bs;
  			wdst += bs;
  		} while ((avail -= bs) >= bs);
  
  		err = blkcipher_walk_done(d, w, avail);
  		if (!(avail = w->nbytes))
  			break;
  
  		wsrc = w->src.virt.addr;
  		wdst = w->dst.virt.addr;
  	}
  
  	return err;
  }
  
  static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
  		   struct scatterlist *src, unsigned int nbytes)
  {
  	struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
  	struct blkcipher_walk w;
  
  	blkcipher_walk_init(&w, dst, src, nbytes);
  	return crypt(desc, &w, ctx,
  		     crypto_cipher_alg(ctx->child)->cia_encrypt);
  }
  
  static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
  		   struct scatterlist *src, unsigned int nbytes)
  {
  	struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
  	struct blkcipher_walk w;
  
  	blkcipher_walk_init(&w, dst, src, nbytes);
  	return crypt(desc, &w, ctx,
  		     crypto_cipher_alg(ctx->child)->cia_decrypt);
  }
  
  static int init_tfm(struct crypto_tfm *tfm)
  {
2e306ee01   Herbert Xu   [CRYPTO] api: Add...
210
  	struct crypto_cipher *cipher;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
211
212
213
214
  	struct crypto_instance *inst = (void *)tfm->__crt_alg;
  	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
  	struct priv *ctx = crypto_tfm_ctx(tfm);
  	u32 *flags = &tfm->crt_flags;
2e306ee01   Herbert Xu   [CRYPTO] api: Add...
215
216
217
  	cipher = crypto_spawn_cipher(spawn);
  	if (IS_ERR(cipher))
  		return PTR_ERR(cipher);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
218

2e306ee01   Herbert Xu   [CRYPTO] api: Add...
219
  	if (crypto_cipher_blocksize(cipher) != 16) {
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
220
221
222
  		*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
  		return -EINVAL;
  	}
2e306ee01   Herbert Xu   [CRYPTO] api: Add...
223
  	ctx->child = cipher;
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
224
225
226
227
228
229
230
231
232
233
  	return 0;
  }
  
  static void exit_tfm(struct crypto_tfm *tfm)
  {
  	struct priv *ctx = crypto_tfm_ctx(tfm);
  	if (ctx->table)
  		gf128mul_free_64k(ctx->table);
  	crypto_free_cipher(ctx->child);
  }
ebc610e5b   Herbert Xu   [CRYPTO] template...
234
  static struct crypto_instance *alloc(struct rtattr **tb)
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
235
236
237
  {
  	struct crypto_instance *inst;
  	struct crypto_alg *alg;
ebc610e5b   Herbert Xu   [CRYPTO] template...
238
239
240
241
242
  	int err;
  
  	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
  	if (err)
  		return ERR_PTR(err);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
243

ebc610e5b   Herbert Xu   [CRYPTO] template...
244
245
  	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
  				  CRYPTO_ALG_TYPE_MASK);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
246
  	if (IS_ERR(alg))
e231c2ee6   David Howells   Convert ERR_PTR(P...
247
  		return ERR_CAST(alg);
64470f1b8   Rik Snel   [CRYPTO] lrw: Lis...
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  
  	inst = crypto_alloc_instance("lrw", alg);
  	if (IS_ERR(inst))
  		goto out_put_alg;
  
  	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
  	inst->alg.cra_priority = alg->cra_priority;
  	inst->alg.cra_blocksize = alg->cra_blocksize;
  
  	if (alg->cra_alignmask < 7) inst->alg.cra_alignmask = 7;
  	else inst->alg.cra_alignmask = alg->cra_alignmask;
  	inst->alg.cra_type = &crypto_blkcipher_type;
  
  	if (!(alg->cra_blocksize % 4))
  		inst->alg.cra_alignmask |= 3;
  	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
  	inst->alg.cra_blkcipher.min_keysize =
  		alg->cra_cipher.cia_min_keysize + alg->cra_blocksize;
  	inst->alg.cra_blkcipher.max_keysize =
  		alg->cra_cipher.cia_max_keysize + alg->cra_blocksize;
  
  	inst->alg.cra_ctxsize = sizeof(struct priv);
  
  	inst->alg.cra_init = init_tfm;
  	inst->alg.cra_exit = exit_tfm;
  
  	inst->alg.cra_blkcipher.setkey = setkey;
  	inst->alg.cra_blkcipher.encrypt = encrypt;
  	inst->alg.cra_blkcipher.decrypt = decrypt;
  
  out_put_alg:
  	crypto_mod_put(alg);
  	return inst;
  }
  
  static void free(struct crypto_instance *inst)
  {
  	crypto_drop_spawn(crypto_instance_ctx(inst));
  	kfree(inst);
  }
  
  static struct crypto_template crypto_tmpl = {
  	.name = "lrw",
  	.alloc = alloc,
  	.free = free,
  	.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");