Blame view

crypto/xts.c 8.66 KB
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /* XTS: as defined in IEEE1619/D16
   *	http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
   *	(sector sizes which are not a multiple of 16 bytes are,
   *	however currently unsupported)
   *
   * Copyright (c) 2007 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.
   */
  #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>
ce0045561   Jussi Kivilinna   crypto: xts: add ...
23
  #include <crypto/xts.h>
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  #include <crypto/b128ops.h>
  #include <crypto/gf128mul.h>
  
  struct priv {
  	struct crypto_cipher *child;
  	struct crypto_cipher *tweak;
  };
  
  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->tweak;
  	u32 *flags = &parent->crt_flags;
  	int err;
  
  	/* key consists of keys of equal size concatenated, therefore
  	 * the length must be even */
  	if (keylen % 2) {
  		/* tell the user why there was an error */
  		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
  		return -EINVAL;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
47
  	/* we need two cipher instances: one to compute the initial 'tweak'
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  	 * by encrypting the IV (usually the 'plain' iv) and the other
  	 * one to encrypt and decrypt the data */
  
  	/* tweak cipher, uses Key2 i.e. the second half of *key */
  	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
  				       CRYPTO_TFM_REQ_MASK);
  	err = crypto_cipher_setkey(child, key + keylen/2, keylen/2);
  	if (err)
  		return err;
  
  	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
  				     CRYPTO_TFM_RES_MASK);
  
  	child = ctx->child;
  
  	/* data cipher, uses Key1 i.e. the first half of *key */
  	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
  				       CRYPTO_TFM_REQ_MASK);
  	err = crypto_cipher_setkey(child, key, keylen/2);
  	if (err)
  		return err;
  
  	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
  				     CRYPTO_TFM_RES_MASK);
  
  	return 0;
  }
  
  struct sinfo {
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
79
  	be128 *t;
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
80
81
82
83
84
85
  	struct crypto_tfm *tfm;
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  };
  
  static inline void xts_round(struct sinfo *s, void *dst, const void *src)
  {
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
86
  	be128_xor(dst, s->t, src);		/* PP <- T xor P */
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
87
  	s->fn(s->tfm, dst, dst);		/* CC <- E(Key1,PP) */
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
88
  	be128_xor(dst, dst, s->t);		/* C <- T xor CC */
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
89
90
91
92
93
94
95
96
97
  }
  
  static int crypt(struct blkcipher_desc *d,
  		 struct blkcipher_walk *w, struct priv *ctx,
  		 void (*tw)(struct crypto_tfm *, u8 *, const u8 *),
  		 void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
  {
  	int err;
  	unsigned int avail;
f9d2691fc   Jussi Kivilinna   crypto: xts - use...
98
  	const int bs = XTS_BLOCK_SIZE;
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
99
100
101
102
  	struct sinfo s = {
  		.tfm = crypto_cipher_tfm(ctx->child),
  		.fn = fn
  	};
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
103
104
105
106
107
108
  	u8 *wsrc;
  	u8 *wdst;
  
  	err = blkcipher_walk_virt(d, w);
  	if (!w->nbytes)
  		return err;
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
109
  	s.t = (be128 *)w->iv;
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
110
111
112
113
114
115
  	avail = w->nbytes;
  
  	wsrc = w->src.virt.addr;
  	wdst = w->dst.virt.addr;
  
  	/* calculate first value of T */
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
116
  	tw(crypto_cipher_tfm(ctx->tweak), w->iv, w->iv);
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
117
118
119
120
121
  
  	goto first;
  
  	for (;;) {
  		do {
6212f2c7f   Sebastian Siewior   [CRYPTO] xts: Use...
122
  			gf128mul_x_ble(s.t, s.t);
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
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
  
  first:
  			xts_round(&s, wdst, wsrc);
  
  			wsrc += bs;
  			wdst += bs;
  		} while ((avail -= bs) >= bs);
  
  		err = blkcipher_walk_done(d, w, avail);
  		if (!w->nbytes)
  			break;
  
  		avail = w->nbytes;
  
  		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->tweak)->cia_encrypt,
  		     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->tweak)->cia_encrypt,
  		     crypto_cipher_alg(ctx->child)->cia_decrypt);
  }
ce0045561   Jussi Kivilinna   crypto: xts: add ...
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
  	      struct scatterlist *ssrc, unsigned int nbytes,
  	      struct xts_crypt_req *req)
  {
  	const unsigned int bsize = XTS_BLOCK_SIZE;
  	const unsigned int max_blks = req->tbuflen / bsize;
  	struct blkcipher_walk walk;
  	unsigned int nblocks;
  	be128 *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(nbytes / bsize, max_blks);
  	src = (be128 *)walk.src.virt.addr;
  	dst = (be128 *)walk.dst.virt.addr;
  
  	/* calculate first value of T */
  	req->tweak_fn(req->tweak_ctx, (u8 *)&t_buf[0], walk.iv);
  
  	i = 0;
  	goto first;
  
  	for (;;) {
  		do {
  			for (i = 0; i < nblocks; i++) {
  				gf128mul_x_ble(&t_buf[i], t);
  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);
  
  		*(be128 *)walk.iv = *t;
  
  		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(xts_crypt);
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
236
237
238
239
240
241
242
243
244
245
246
  static int init_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_cipher *cipher;
  	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;
  
  	cipher = crypto_spawn_cipher(spawn);
  	if (IS_ERR(cipher))
  		return PTR_ERR(cipher);
f9d2691fc   Jussi Kivilinna   crypto: xts - use...
247
  	if (crypto_cipher_blocksize(cipher) != XTS_BLOCK_SIZE) {
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  		*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
  		crypto_free_cipher(cipher);
  		return -EINVAL;
  	}
  
  	ctx->child = cipher;
  
  	cipher = crypto_spawn_cipher(spawn);
  	if (IS_ERR(cipher)) {
  		crypto_free_cipher(ctx->child);
  		return PTR_ERR(cipher);
  	}
  
  	/* this check isn't really needed, leave it here just in case */
f9d2691fc   Jussi Kivilinna   crypto: xts - use...
262
  	if (crypto_cipher_blocksize(cipher) != XTS_BLOCK_SIZE) {
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
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
  		crypto_free_cipher(cipher);
  		crypto_free_cipher(ctx->child);
  		*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
  		return -EINVAL;
  	}
  
  	ctx->tweak = cipher;
  
  	return 0;
  }
  
  static void exit_tfm(struct crypto_tfm *tfm)
  {
  	struct priv *ctx = crypto_tfm_ctx(tfm);
  	crypto_free_cipher(ctx->child);
  	crypto_free_cipher(ctx->tweak);
  }
  
  static struct crypto_instance *alloc(struct rtattr **tb)
  {
  	struct crypto_instance *inst;
  	struct crypto_alg *alg;
  	int err;
  
  	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
  	if (err)
  		return ERR_PTR(err);
  
  	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
  				  CRYPTO_ALG_TYPE_MASK);
  	if (IS_ERR(alg))
8db050786   Julia Lawall   crypto: Use ERR_CAST
294
  		return ERR_CAST(alg);
f19f5111c   Rik Snel   [CRYPTO] xts: XTS...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  
  	inst = crypto_alloc_instance("xts", 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;
  
  	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
  	inst->alg.cra_blkcipher.min_keysize =
  		2 * alg->cra_cipher.cia_min_keysize;
  	inst->alg.cra_blkcipher.max_keysize =
  		2 * alg->cra_cipher.cia_max_keysize;
  
  	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 = "xts",
  	.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("XTS block cipher mode");