diff options
author | Kevin Coffman <kwc@citi.umich.edu> | 2008-03-24 09:26:16 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-04-20 22:19:23 -0400 |
commit | 76cb9521795a167ae3d206343c072f602d84f815 (patch) | |
tree | 36aa2e201867c76ac244de69e1bb16befa0504ee /crypto/cts.c | |
parent | fd4609a8e00a867303783ade62d67953fb72adc8 (diff) |
[CRYPTO] cts: Add CTS mode required for Kerberos AES support
Implement CTS wrapper for CBC mode required for support of AES
encryption support for Kerberos (rfc3962).
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/cts.c')
-rw-r--r-- | crypto/cts.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/crypto/cts.c b/crypto/cts.c new file mode 100644 index 000000000000..c4e70bfb4970 --- /dev/null +++ b/crypto/cts.c | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * CTS: Cipher Text Stealing mode | ||
3 | * | ||
4 | * COPYRIGHT (c) 2008 | ||
5 | * The Regents of the University of Michigan | ||
6 | * ALL RIGHTS RESERVED | ||
7 | * | ||
8 | * Permission is granted to use, copy, create derivative works | ||
9 | * and redistribute this software and such derivative works | ||
10 | * for any purpose, so long as the name of The University of | ||
11 | * Michigan is not used in any advertising or publicity | ||
12 | * pertaining to the use of distribution of this software | ||
13 | * without specific, written prior authorization. If the | ||
14 | * above copyright notice or any other identification of the | ||
15 | * University of Michigan is included in any copy of any | ||
16 | * portion of this software, then the disclaimer below must | ||
17 | * also be included. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION | ||
20 | * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY | ||
21 | * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF | ||
22 | * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING | ||
23 | * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | ||
25 | * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE | ||
26 | * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR | ||
27 | * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING | ||
28 | * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN | ||
29 | * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF | ||
30 | * SUCH DAMAGES. | ||
31 | */ | ||
32 | |||
33 | /* Derived from various: | ||
34 | * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
35 | */ | ||
36 | |||
37 | /* | ||
38 | * This is the Cipher Text Stealing mode as described by | ||
39 | * Section 8 of rfc2040 and referenced by rfc3962. | ||
40 | * rfc3962 includes errata information in its Appendix A. | ||
41 | */ | ||
42 | |||
43 | #include <crypto/algapi.h> | ||
44 | #include <linux/err.h> | ||
45 | #include <linux/init.h> | ||
46 | #include <linux/kernel.h> | ||
47 | #include <linux/log2.h> | ||
48 | #include <linux/module.h> | ||
49 | #include <linux/scatterlist.h> | ||
50 | #include <crypto/scatterwalk.h> | ||
51 | #include <linux/slab.h> | ||
52 | |||
53 | struct crypto_cts_ctx { | ||
54 | struct crypto_blkcipher *child; | ||
55 | }; | ||
56 | |||
57 | static int crypto_cts_setkey(struct crypto_tfm *parent, const u8 *key, | ||
58 | unsigned int keylen) | ||
59 | { | ||
60 | struct crypto_cts_ctx *ctx = crypto_tfm_ctx(parent); | ||
61 | struct crypto_blkcipher *child = ctx->child; | ||
62 | int err; | ||
63 | |||
64 | crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); | ||
65 | crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) & | ||
66 | CRYPTO_TFM_REQ_MASK); | ||
67 | err = crypto_blkcipher_setkey(child, key, keylen); | ||
68 | crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) & | ||
69 | CRYPTO_TFM_RES_MASK); | ||
70 | return err; | ||
71 | } | ||
72 | |||
73 | static int cts_cbc_encrypt(struct crypto_cts_ctx *ctx, | ||
74 | struct blkcipher_desc *desc, | ||
75 | struct scatterlist *dst, | ||
76 | struct scatterlist *src, | ||
77 | unsigned int offset, | ||
78 | unsigned int nbytes) | ||
79 | { | ||
80 | int bsize = crypto_blkcipher_blocksize(desc->tfm); | ||
81 | u8 tmp[bsize], tmp2[bsize]; | ||
82 | struct blkcipher_desc lcldesc; | ||
83 | struct scatterlist sgsrc[1], sgdst[1]; | ||
84 | int lastn = nbytes - bsize; | ||
85 | u8 iv[bsize]; | ||
86 | u8 s[bsize * 2], d[bsize * 2]; | ||
87 | int err; | ||
88 | |||
89 | if (lastn < 0) | ||
90 | return -EINVAL; | ||
91 | |||
92 | memset(s, 0, sizeof(s)); | ||
93 | scatterwalk_map_and_copy(s, src, offset, nbytes, 0); | ||
94 | |||
95 | memcpy(iv, desc->info, bsize); | ||
96 | |||
97 | lcldesc.tfm = ctx->child; | ||
98 | lcldesc.info = iv; | ||
99 | lcldesc.flags = desc->flags; | ||
100 | |||
101 | sg_set_buf(&sgsrc[0], s, bsize); | ||
102 | sg_set_buf(&sgdst[0], tmp, bsize); | ||
103 | err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize); | ||
104 | |||
105 | memcpy(d + bsize, tmp, lastn); | ||
106 | |||
107 | lcldesc.info = tmp; | ||
108 | |||
109 | sg_set_buf(&sgsrc[0], s + bsize, bsize); | ||
110 | sg_set_buf(&sgdst[0], tmp2, bsize); | ||
111 | err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize); | ||
112 | |||
113 | memcpy(d, tmp2, bsize); | ||
114 | |||
115 | scatterwalk_map_and_copy(d, dst, offset, nbytes, 1); | ||
116 | |||
117 | memcpy(desc->info, tmp2, bsize); | ||
118 | |||
119 | return err; | ||
120 | } | ||
121 | |||
122 | static int crypto_cts_encrypt(struct blkcipher_desc *desc, | ||
123 | struct scatterlist *dst, struct scatterlist *src, | ||
124 | unsigned int nbytes) | ||
125 | { | ||
126 | struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
127 | int bsize = crypto_blkcipher_blocksize(desc->tfm); | ||
128 | int tot_blocks = (nbytes + bsize - 1) / bsize; | ||
129 | int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0; | ||
130 | struct blkcipher_desc lcldesc; | ||
131 | int err; | ||
132 | |||
133 | lcldesc.tfm = ctx->child; | ||
134 | lcldesc.info = desc->info; | ||
135 | lcldesc.flags = desc->flags; | ||
136 | |||
137 | if (tot_blocks == 1) { | ||
138 | err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, bsize); | ||
139 | } else if (nbytes <= bsize * 2) { | ||
140 | err = cts_cbc_encrypt(ctx, desc, dst, src, 0, nbytes); | ||
141 | } else { | ||
142 | /* do normal function for tot_blocks - 2 */ | ||
143 | err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, | ||
144 | cbc_blocks * bsize); | ||
145 | if (err == 0) { | ||
146 | /* do cts for final two blocks */ | ||
147 | err = cts_cbc_encrypt(ctx, desc, dst, src, | ||
148 | cbc_blocks * bsize, | ||
149 | nbytes - (cbc_blocks * bsize)); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | return err; | ||
154 | } | ||
155 | |||
156 | static int cts_cbc_decrypt(struct crypto_cts_ctx *ctx, | ||
157 | struct blkcipher_desc *desc, | ||
158 | struct scatterlist *dst, | ||
159 | struct scatterlist *src, | ||
160 | unsigned int offset, | ||
161 | unsigned int nbytes) | ||
162 | { | ||
163 | int bsize = crypto_blkcipher_blocksize(desc->tfm); | ||
164 | u8 tmp[bsize]; | ||
165 | struct blkcipher_desc lcldesc; | ||
166 | struct scatterlist sgsrc[1], sgdst[1]; | ||
167 | int lastn = nbytes - bsize; | ||
168 | u8 iv[bsize]; | ||
169 | u8 s[bsize * 2], d[bsize * 2]; | ||
170 | int err; | ||
171 | |||
172 | if (lastn < 0) | ||
173 | return -EINVAL; | ||
174 | |||
175 | scatterwalk_map_and_copy(s, src, offset, nbytes, 0); | ||
176 | |||
177 | lcldesc.tfm = ctx->child; | ||
178 | lcldesc.info = iv; | ||
179 | lcldesc.flags = desc->flags; | ||
180 | |||
181 | /* 1. Decrypt Cn-1 (s) to create Dn (tmp)*/ | ||
182 | memset(iv, 0, sizeof(iv)); | ||
183 | sg_set_buf(&sgsrc[0], s, bsize); | ||
184 | sg_set_buf(&sgdst[0], tmp, bsize); | ||
185 | err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize); | ||
186 | if (err) | ||
187 | return err; | ||
188 | /* 2. Pad Cn with zeros at the end to create C of length BB */ | ||
189 | memset(iv, 0, sizeof(iv)); | ||
190 | memcpy(iv, s + bsize, lastn); | ||
191 | /* 3. Exclusive-or Dn (tmp) with C (iv) to create Xn (tmp) */ | ||
192 | crypto_xor(tmp, iv, bsize); | ||
193 | /* 4. Select the first Ln bytes of Xn (tmp) to create Pn */ | ||
194 | memcpy(d + bsize, tmp, lastn); | ||
195 | |||
196 | /* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */ | ||
197 | memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn); | ||
198 | /* 6. Decrypt En to create Pn-1 */ | ||
199 | memset(iv, 0, sizeof(iv)); | ||
200 | sg_set_buf(&sgsrc[0], s + bsize, bsize); | ||
201 | sg_set_buf(&sgdst[0], d, bsize); | ||
202 | err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize); | ||
203 | |||
204 | /* XOR with previous block */ | ||
205 | crypto_xor(d, desc->info, bsize); | ||
206 | |||
207 | scatterwalk_map_and_copy(d, dst, offset, nbytes, 1); | ||
208 | |||
209 | memcpy(desc->info, s, bsize); | ||
210 | return err; | ||
211 | } | ||
212 | |||
213 | static int crypto_cts_decrypt(struct blkcipher_desc *desc, | ||
214 | struct scatterlist *dst, struct scatterlist *src, | ||
215 | unsigned int nbytes) | ||
216 | { | ||
217 | struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
218 | int bsize = crypto_blkcipher_blocksize(desc->tfm); | ||
219 | int tot_blocks = (nbytes + bsize - 1) / bsize; | ||
220 | int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0; | ||
221 | struct blkcipher_desc lcldesc; | ||
222 | int err; | ||
223 | |||
224 | lcldesc.tfm = ctx->child; | ||
225 | lcldesc.info = desc->info; | ||
226 | lcldesc.flags = desc->flags; | ||
227 | |||
228 | if (tot_blocks == 1) { | ||
229 | err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize); | ||
230 | } else if (nbytes <= bsize * 2) { | ||
231 | err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes); | ||
232 | } else { | ||
233 | /* do normal function for tot_blocks - 2 */ | ||
234 | err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, | ||
235 | cbc_blocks * bsize); | ||
236 | if (err == 0) { | ||
237 | /* do cts for final two blocks */ | ||
238 | err = cts_cbc_decrypt(ctx, desc, dst, src, | ||
239 | cbc_blocks * bsize, | ||
240 | nbytes - (cbc_blocks * bsize)); | ||
241 | } | ||
242 | } | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | static int crypto_cts_init_tfm(struct crypto_tfm *tfm) | ||
247 | { | ||
248 | struct crypto_instance *inst = (void *)tfm->__crt_alg; | ||
249 | struct crypto_spawn *spawn = crypto_instance_ctx(inst); | ||
250 | struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm); | ||
251 | struct crypto_blkcipher *cipher; | ||
252 | |||
253 | cipher = crypto_spawn_blkcipher(spawn); | ||
254 | if (IS_ERR(cipher)) | ||
255 | return PTR_ERR(cipher); | ||
256 | |||
257 | ctx->child = cipher; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static void crypto_cts_exit_tfm(struct crypto_tfm *tfm) | ||
262 | { | ||
263 | struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm); | ||
264 | crypto_free_blkcipher(ctx->child); | ||
265 | } | ||
266 | |||
267 | static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb) | ||
268 | { | ||
269 | struct crypto_instance *inst; | ||
270 | struct crypto_alg *alg; | ||
271 | int err; | ||
272 | |||
273 | err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); | ||
274 | if (err) | ||
275 | return ERR_PTR(err); | ||
276 | |||
277 | alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER, | ||
278 | CRYPTO_ALG_TYPE_MASK); | ||
279 | err = PTR_ERR(alg); | ||
280 | if (IS_ERR(alg)) | ||
281 | return ERR_PTR(err); | ||
282 | |||
283 | inst = ERR_PTR(-EINVAL); | ||
284 | if (!is_power_of_2(alg->cra_blocksize)) | ||
285 | goto out_put_alg; | ||
286 | |||
287 | inst = crypto_alloc_instance("cts", alg); | ||
288 | if (IS_ERR(inst)) | ||
289 | goto out_put_alg; | ||
290 | |||
291 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; | ||
292 | inst->alg.cra_priority = alg->cra_priority; | ||
293 | inst->alg.cra_blocksize = alg->cra_blocksize; | ||
294 | inst->alg.cra_alignmask = alg->cra_alignmask; | ||
295 | inst->alg.cra_type = &crypto_blkcipher_type; | ||
296 | |||
297 | /* We access the data as u32s when xoring. */ | ||
298 | inst->alg.cra_alignmask |= __alignof__(u32) - 1; | ||
299 | |||
300 | inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; | ||
301 | inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize; | ||
302 | inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize; | ||
303 | |||
304 | inst->alg.cra_blkcipher.geniv = "seqiv"; | ||
305 | |||
306 | inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx); | ||
307 | |||
308 | inst->alg.cra_init = crypto_cts_init_tfm; | ||
309 | inst->alg.cra_exit = crypto_cts_exit_tfm; | ||
310 | |||
311 | inst->alg.cra_blkcipher.setkey = crypto_cts_setkey; | ||
312 | inst->alg.cra_blkcipher.encrypt = crypto_cts_encrypt; | ||
313 | inst->alg.cra_blkcipher.decrypt = crypto_cts_decrypt; | ||
314 | |||
315 | out_put_alg: | ||
316 | crypto_mod_put(alg); | ||
317 | return inst; | ||
318 | } | ||
319 | |||
320 | static void crypto_cts_free(struct crypto_instance *inst) | ||
321 | { | ||
322 | crypto_drop_spawn(crypto_instance_ctx(inst)); | ||
323 | kfree(inst); | ||
324 | } | ||
325 | |||
326 | static struct crypto_template crypto_cts_tmpl = { | ||
327 | .name = "cts", | ||
328 | .alloc = crypto_cts_alloc, | ||
329 | .free = crypto_cts_free, | ||
330 | .module = THIS_MODULE, | ||
331 | }; | ||
332 | |||
333 | static int __init crypto_cts_module_init(void) | ||
334 | { | ||
335 | return crypto_register_template(&crypto_cts_tmpl); | ||
336 | } | ||
337 | |||
338 | static void __exit crypto_cts_module_exit(void) | ||
339 | { | ||
340 | crypto_unregister_template(&crypto_cts_tmpl); | ||
341 | } | ||
342 | |||
343 | module_init(crypto_cts_module_init); | ||
344 | module_exit(crypto_cts_module_exit); | ||
345 | |||
346 | MODULE_LICENSE("Dual BSD/GPL"); | ||
347 | MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC"); | ||