aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/xts.c
diff options
context:
space:
mode:
authorRik Snel <rsnel@cube.dyndns.org>2007-09-19 08:23:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:55:45 -0400
commitf19f5111c94053ba4931892f5c01c806de33942e (patch)
treeb40dfae8fa170ebdc92fdcfeb3000c84d6203645 /crypto/xts.c
parent5aaff0c8f7dd3515c9f1ca57f86463f30779acc7 (diff)
[CRYPTO] xts: XTS blockcipher mode implementation without partial blocks
XTS currently considered to be the successor of the LRW mode by the IEEE1619 workgroup. LRW was discarded, because it was not secure if the encyption key itself is encrypted with LRW. XTS does not have this problem. The implementation is pretty straightforward, a new function was added to gf128mul to handle GF(128) elements in ble format. Four testvectors from the specification http://grouper.ieee.org/groups/1619/email/pdf00086.pdf were added, and they verify on my system. Signed-off-by: Rik Snel <rsnel@cube.dyndns.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/xts.c')
-rw-r--r--crypto/xts.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/crypto/xts.c b/crypto/xts.c
new file mode 100644
index 000000000000..8eb08bfaf7c0
--- /dev/null
+++ b/crypto/xts.c
@@ -0,0 +1,292 @@
1/* XTS: as defined in IEEE1619/D16
2 * http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
3 * (sector sizes which are not a multiple of 16 bytes are,
4 * however currently unsupported)
5 *
6 * Copyright (c) 2007 Rik Snel <rsnel@cube.dyndns.org>
7 *
8 * Based om ecb.c
9 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 */
16#include <crypto/algapi.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/scatterlist.h>
22#include <linux/slab.h>
23
24#include <crypto/b128ops.h>
25#include <crypto/gf128mul.h>
26
27struct priv {
28 struct crypto_cipher *child;
29 struct crypto_cipher *tweak;
30};
31
32static int setkey(struct crypto_tfm *parent, const u8 *key,
33 unsigned int keylen)
34{
35 struct priv *ctx = crypto_tfm_ctx(parent);
36 struct crypto_cipher *child = ctx->tweak;
37 u32 *flags = &parent->crt_flags;
38 int err;
39
40 /* key consists of keys of equal size concatenated, therefore
41 * the length must be even */
42 if (keylen % 2) {
43 /* tell the user why there was an error */
44 *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
45 return -EINVAL;
46 }
47
48 /* we need two cipher instances: one to compute the inital 'tweak'
49 * by encrypting the IV (usually the 'plain' iv) and the other
50 * one to encrypt and decrypt the data */
51
52 /* tweak cipher, uses Key2 i.e. the second half of *key */
53 crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
54 crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
55 CRYPTO_TFM_REQ_MASK);
56 err = crypto_cipher_setkey(child, key + keylen/2, keylen/2);
57 if (err)
58 return err;
59
60 crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
61 CRYPTO_TFM_RES_MASK);
62
63 child = ctx->child;
64
65 /* data cipher, uses Key1 i.e. the first half of *key */
66 crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
67 crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
68 CRYPTO_TFM_REQ_MASK);
69 err = crypto_cipher_setkey(child, key, keylen/2);
70 if (err)
71 return err;
72
73 crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
74 CRYPTO_TFM_RES_MASK);
75
76 return 0;
77}
78
79struct sinfo {
80 be128 t;
81 struct crypto_tfm *tfm;
82 void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
83};
84
85static inline void xts_round(struct sinfo *s, void *dst, const void *src)
86{
87 be128_xor(dst, &s->t, src); /* PP <- T xor P */
88 s->fn(s->tfm, dst, dst); /* CC <- E(Key1,PP) */
89 be128_xor(dst, dst, &s->t); /* C <- T xor CC */
90}
91
92static int crypt(struct blkcipher_desc *d,
93 struct blkcipher_walk *w, struct priv *ctx,
94 void (*tw)(struct crypto_tfm *, u8 *, const u8 *),
95 void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
96{
97 int err;
98 unsigned int avail;
99 const int bs = crypto_cipher_blocksize(ctx->child);
100 struct sinfo s = {
101 .tfm = crypto_cipher_tfm(ctx->child),
102 .fn = fn
103 };
104 be128 *iv;
105 u8 *wsrc;
106 u8 *wdst;
107
108 err = blkcipher_walk_virt(d, w);
109 if (!w->nbytes)
110 return err;
111
112 avail = w->nbytes;
113
114 wsrc = w->src.virt.addr;
115 wdst = w->dst.virt.addr;
116
117 /* calculate first value of T */
118 iv = (be128 *)w->iv;
119 tw(crypto_cipher_tfm(ctx->tweak), (void *)&s.t, w->iv);
120
121 goto first;
122
123 for (;;) {
124 do {
125 gf128mul_x_ble(&s.t, &s.t);
126
127first:
128 xts_round(&s, wdst, wsrc);
129
130 wsrc += bs;
131 wdst += bs;
132 } while ((avail -= bs) >= bs);
133
134 err = blkcipher_walk_done(d, w, avail);
135 if (!w->nbytes)
136 break;
137
138 avail = w->nbytes;
139
140 wsrc = w->src.virt.addr;
141 wdst = w->dst.virt.addr;
142 }
143
144 return err;
145}
146
147static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
148 struct scatterlist *src, unsigned int nbytes)
149{
150 struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
151 struct blkcipher_walk w;
152
153 blkcipher_walk_init(&w, dst, src, nbytes);
154 return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
155 crypto_cipher_alg(ctx->child)->cia_encrypt);
156}
157
158static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
159 struct scatterlist *src, unsigned int nbytes)
160{
161 struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
162 struct blkcipher_walk w;
163
164 blkcipher_walk_init(&w, dst, src, nbytes);
165 return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
166 crypto_cipher_alg(ctx->child)->cia_decrypt);
167}
168
169static int init_tfm(struct crypto_tfm *tfm)
170{
171 struct crypto_cipher *cipher;
172 struct crypto_instance *inst = (void *)tfm->__crt_alg;
173 struct crypto_spawn *spawn = crypto_instance_ctx(inst);
174 struct priv *ctx = crypto_tfm_ctx(tfm);
175 u32 *flags = &tfm->crt_flags;
176
177 cipher = crypto_spawn_cipher(spawn);
178 if (IS_ERR(cipher))
179 return PTR_ERR(cipher);
180
181 if (crypto_cipher_blocksize(cipher) != 16) {
182 *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
183 crypto_free_cipher(cipher);
184 return -EINVAL;
185 }
186
187 ctx->child = cipher;
188
189 cipher = crypto_spawn_cipher(spawn);
190 if (IS_ERR(cipher)) {
191 crypto_free_cipher(ctx->child);
192 return PTR_ERR(cipher);
193 }
194
195 /* this check isn't really needed, leave it here just in case */
196 if (crypto_cipher_blocksize(cipher) != 16) {
197 crypto_free_cipher(cipher);
198 crypto_free_cipher(ctx->child);
199 *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
200 return -EINVAL;
201 }
202
203 ctx->tweak = cipher;
204
205 return 0;
206}
207
208static void exit_tfm(struct crypto_tfm *tfm)
209{
210 struct priv *ctx = crypto_tfm_ctx(tfm);
211 crypto_free_cipher(ctx->child);
212 crypto_free_cipher(ctx->tweak);
213}
214
215static struct crypto_instance *alloc(struct rtattr **tb)
216{
217 struct crypto_instance *inst;
218 struct crypto_alg *alg;
219 int err;
220
221 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
222 if (err)
223 return ERR_PTR(err);
224
225 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
226 CRYPTO_ALG_TYPE_MASK);
227 if (IS_ERR(alg))
228 return ERR_PTR(PTR_ERR(alg));
229
230 inst = crypto_alloc_instance("xts", alg);
231 if (IS_ERR(inst))
232 goto out_put_alg;
233
234 inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
235 inst->alg.cra_priority = alg->cra_priority;
236 inst->alg.cra_blocksize = alg->cra_blocksize;
237
238 if (alg->cra_alignmask < 7)
239 inst->alg.cra_alignmask = 7;
240 else
241 inst->alg.cra_alignmask = alg->cra_alignmask;
242
243 inst->alg.cra_type = &crypto_blkcipher_type;
244
245 inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
246 inst->alg.cra_blkcipher.min_keysize =
247 2 * alg->cra_cipher.cia_min_keysize;
248 inst->alg.cra_blkcipher.max_keysize =
249 2 * alg->cra_cipher.cia_max_keysize;
250
251 inst->alg.cra_ctxsize = sizeof(struct priv);
252
253 inst->alg.cra_init = init_tfm;
254 inst->alg.cra_exit = exit_tfm;
255
256 inst->alg.cra_blkcipher.setkey = setkey;
257 inst->alg.cra_blkcipher.encrypt = encrypt;
258 inst->alg.cra_blkcipher.decrypt = decrypt;
259
260out_put_alg:
261 crypto_mod_put(alg);
262 return inst;
263}
264
265static void free(struct crypto_instance *inst)
266{
267 crypto_drop_spawn(crypto_instance_ctx(inst));
268 kfree(inst);
269}
270
271static struct crypto_template crypto_tmpl = {
272 .name = "xts",
273 .alloc = alloc,
274 .free = free,
275 .module = THIS_MODULE,
276};
277
278static int __init crypto_module_init(void)
279{
280 return crypto_register_template(&crypto_tmpl);
281}
282
283static void __exit crypto_module_exit(void)
284{
285 crypto_unregister_template(&crypto_tmpl);
286}
287
288module_init(crypto_module_init);
289module_exit(crypto_module_exit);
290
291MODULE_LICENSE("GPL");
292MODULE_DESCRIPTION("XTS block cipher mode");