Commit | Line | Data |
---|---|---|
91652be5 DH |
1 | /* |
2 | * PCBC: Propagating Cipher Block Chaining mode | |
3 | * | |
4 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
6 | * | |
7 | * Derived from cbc.c | |
8 | * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify it | |
11 | * under the terms of the GNU General Public License as published by the Free | |
12 | * Software Foundation; either version 2 of the License, or (at your option) | |
13 | * any later version. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <crypto/algapi.h> | |
18 | #include <linux/err.h> | |
19 | #include <linux/init.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/scatterlist.h> | |
23 | #include <linux/slab.h> | |
24 | ||
25 | struct crypto_pcbc_ctx { | |
26 | struct crypto_cipher *child; | |
27 | void (*xor)(u8 *dst, const u8 *src, unsigned int bs); | |
28 | }; | |
29 | ||
30 | static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key, | |
31 | unsigned int keylen) | |
32 | { | |
33 | struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent); | |
34 | struct crypto_cipher *child = ctx->child; | |
35 | int err; | |
36 | ||
37 | crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); | |
38 | crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & | |
39 | CRYPTO_TFM_REQ_MASK); | |
40 | err = crypto_cipher_setkey(child, key, keylen); | |
41 | crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & | |
42 | CRYPTO_TFM_RES_MASK); | |
43 | return err; | |
44 | } | |
45 | ||
46 | static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, | |
47 | struct blkcipher_walk *walk, | |
48 | struct crypto_cipher *tfm, | |
49 | void (*xor)(u8 *, const u8 *, | |
50 | unsigned int)) | |
51 | { | |
52 | void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = | |
53 | crypto_cipher_alg(tfm)->cia_encrypt; | |
54 | int bsize = crypto_cipher_blocksize(tfm); | |
55 | unsigned int nbytes = walk->nbytes; | |
56 | u8 *src = walk->src.virt.addr; | |
57 | u8 *dst = walk->dst.virt.addr; | |
58 | u8 *iv = walk->iv; | |
59 | ||
60 | do { | |
61 | xor(iv, src, bsize); | |
62 | fn(crypto_cipher_tfm(tfm), dst, iv); | |
63 | memcpy(iv, dst, bsize); | |
64 | xor(iv, src, bsize); | |
65 | ||
66 | src += bsize; | |
67 | dst += bsize; | |
68 | } while ((nbytes -= bsize) >= bsize); | |
69 | ||
70 | return nbytes; | |
71 | } | |
72 | ||
73 | static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc, | |
74 | struct blkcipher_walk *walk, | |
75 | struct crypto_cipher *tfm, | |
76 | void (*xor)(u8 *, const u8 *, | |
77 | unsigned int)) | |
78 | { | |
79 | void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = | |
80 | crypto_cipher_alg(tfm)->cia_encrypt; | |
81 | int bsize = crypto_cipher_blocksize(tfm); | |
82 | unsigned int nbytes = walk->nbytes; | |
83 | u8 *src = walk->src.virt.addr; | |
84 | u8 *iv = walk->iv; | |
85 | u8 tmpbuf[bsize]; | |
86 | ||
87 | do { | |
88 | memcpy(tmpbuf, src, bsize); | |
89 | xor(iv, tmpbuf, bsize); | |
90 | fn(crypto_cipher_tfm(tfm), src, iv); | |
91 | memcpy(iv, src, bsize); | |
92 | xor(iv, tmpbuf, bsize); | |
93 | ||
94 | src += bsize; | |
95 | } while ((nbytes -= bsize) >= bsize); | |
96 | ||
97 | memcpy(walk->iv, iv, bsize); | |
98 | ||
99 | return nbytes; | |
100 | } | |
101 | ||
102 | static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, | |
103 | struct scatterlist *dst, struct scatterlist *src, | |
104 | unsigned int nbytes) | |
105 | { | |
106 | struct blkcipher_walk walk; | |
107 | struct crypto_blkcipher *tfm = desc->tfm; | |
108 | struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); | |
109 | struct crypto_cipher *child = ctx->child; | |
110 | void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; | |
111 | int err; | |
112 | ||
113 | blkcipher_walk_init(&walk, dst, src, nbytes); | |
114 | err = blkcipher_walk_virt(desc, &walk); | |
115 | ||
116 | while ((nbytes = walk.nbytes)) { | |
117 | if (walk.src.virt.addr == walk.dst.virt.addr) | |
118 | nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child, | |
119 | xor); | |
120 | else | |
121 | nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child, | |
122 | xor); | |
123 | err = blkcipher_walk_done(desc, &walk, nbytes); | |
124 | } | |
125 | ||
126 | return err; | |
127 | } | |
128 | ||
129 | static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, | |
130 | struct blkcipher_walk *walk, | |
131 | struct crypto_cipher *tfm, | |
132 | void (*xor)(u8 *, const u8 *, | |
133 | unsigned int)) | |
134 | { | |
135 | void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = | |
136 | crypto_cipher_alg(tfm)->cia_decrypt; | |
137 | int bsize = crypto_cipher_blocksize(tfm); | |
138 | unsigned int nbytes = walk->nbytes; | |
139 | u8 *src = walk->src.virt.addr; | |
140 | u8 *dst = walk->dst.virt.addr; | |
141 | u8 *iv = walk->iv; | |
142 | ||
143 | do { | |
144 | fn(crypto_cipher_tfm(tfm), dst, src); | |
145 | xor(dst, iv, bsize); | |
146 | memcpy(iv, src, bsize); | |
147 | xor(iv, dst, bsize); | |
148 | ||
149 | src += bsize; | |
150 | dst += bsize; | |
151 | } while ((nbytes -= bsize) >= bsize); | |
152 | ||
153 | memcpy(walk->iv, iv, bsize); | |
154 | ||
155 | return nbytes; | |
156 | } | |
157 | ||
158 | static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc, | |
159 | struct blkcipher_walk *walk, | |
160 | struct crypto_cipher *tfm, | |
161 | void (*xor)(u8 *, const u8 *, | |
162 | unsigned int)) | |
163 | { | |
164 | void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = | |
165 | crypto_cipher_alg(tfm)->cia_decrypt; | |
166 | int bsize = crypto_cipher_blocksize(tfm); | |
167 | unsigned int nbytes = walk->nbytes; | |
168 | u8 *src = walk->src.virt.addr; | |
169 | u8 *iv = walk->iv; | |
170 | u8 tmpbuf[bsize]; | |
171 | ||
172 | do { | |
173 | memcpy(tmpbuf, src, bsize); | |
174 | fn(crypto_cipher_tfm(tfm), src, src); | |
175 | xor(src, iv, bsize); | |
176 | memcpy(iv, tmpbuf, bsize); | |
177 | xor(iv, src, bsize); | |
178 | ||
179 | src += bsize; | |
180 | } while ((nbytes -= bsize) >= bsize); | |
181 | ||
182 | memcpy(walk->iv, iv, bsize); | |
183 | ||
184 | return nbytes; | |
185 | } | |
186 | ||
187 | static int crypto_pcbc_decrypt(struct blkcipher_desc *desc, | |
188 | struct scatterlist *dst, struct scatterlist *src, | |
189 | unsigned int nbytes) | |
190 | { | |
191 | struct blkcipher_walk walk; | |
192 | struct crypto_blkcipher *tfm = desc->tfm; | |
193 | struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); | |
194 | struct crypto_cipher *child = ctx->child; | |
195 | void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; | |
196 | int err; | |
197 | ||
198 | blkcipher_walk_init(&walk, dst, src, nbytes); | |
199 | err = blkcipher_walk_virt(desc, &walk); | |
200 | ||
201 | while ((nbytes = walk.nbytes)) { | |
202 | if (walk.src.virt.addr == walk.dst.virt.addr) | |
203 | nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child, | |
204 | xor); | |
205 | else | |
206 | nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child, | |
207 | xor); | |
208 | err = blkcipher_walk_done(desc, &walk, nbytes); | |
209 | } | |
210 | ||
211 | return err; | |
212 | } | |
213 | ||
214 | static void xor_byte(u8 *a, const u8 *b, unsigned int bs) | |
215 | { | |
216 | do { | |
217 | *a++ ^= *b++; | |
218 | } while (--bs); | |
219 | } | |
220 | ||
221 | static void xor_quad(u8 *dst, const u8 *src, unsigned int bs) | |
222 | { | |
223 | u32 *a = (u32 *)dst; | |
224 | u32 *b = (u32 *)src; | |
225 | ||
226 | do { | |
227 | *a++ ^= *b++; | |
228 | } while ((bs -= 4)); | |
229 | } | |
230 | ||
231 | static void xor_64(u8 *a, const u8 *b, unsigned int bs) | |
232 | { | |
233 | ((u32 *)a)[0] ^= ((u32 *)b)[0]; | |
234 | ((u32 *)a)[1] ^= ((u32 *)b)[1]; | |
235 | } | |
236 | ||
237 | static void xor_128(u8 *a, const u8 *b, unsigned int bs) | |
238 | { | |
239 | ((u32 *)a)[0] ^= ((u32 *)b)[0]; | |
240 | ((u32 *)a)[1] ^= ((u32 *)b)[1]; | |
241 | ((u32 *)a)[2] ^= ((u32 *)b)[2]; | |
242 | ((u32 *)a)[3] ^= ((u32 *)b)[3]; | |
243 | } | |
244 | ||
245 | static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm) | |
246 | { | |
247 | struct crypto_instance *inst = (void *)tfm->__crt_alg; | |
248 | struct crypto_spawn *spawn = crypto_instance_ctx(inst); | |
249 | struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); | |
2e306ee0 | 250 | struct crypto_cipher *cipher; |
91652be5 DH |
251 | |
252 | switch (crypto_tfm_alg_blocksize(tfm)) { | |
253 | case 8: | |
254 | ctx->xor = xor_64; | |
255 | break; | |
256 | ||
257 | case 16: | |
258 | ctx->xor = xor_128; | |
259 | break; | |
260 | ||
261 | default: | |
262 | if (crypto_tfm_alg_blocksize(tfm) % 4) | |
263 | ctx->xor = xor_byte; | |
264 | else | |
265 | ctx->xor = xor_quad; | |
266 | } | |
267 | ||
2e306ee0 HX |
268 | cipher = crypto_spawn_cipher(spawn); |
269 | if (IS_ERR(cipher)) | |
270 | return PTR_ERR(cipher); | |
91652be5 | 271 | |
2e306ee0 | 272 | ctx->child = cipher; |
91652be5 DH |
273 | return 0; |
274 | } | |
275 | ||
276 | static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm) | |
277 | { | |
278 | struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); | |
279 | crypto_free_cipher(ctx->child); | |
280 | } | |
281 | ||
282 | static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len) | |
283 | { | |
284 | struct crypto_instance *inst; | |
285 | struct crypto_alg *alg; | |
286 | ||
287 | alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, | |
288 | CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); | |
289 | if (IS_ERR(alg)) | |
290 | return ERR_PTR(PTR_ERR(alg)); | |
291 | ||
292 | inst = crypto_alloc_instance("pcbc", alg); | |
293 | if (IS_ERR(inst)) | |
294 | goto out_put_alg; | |
295 | ||
296 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; | |
297 | inst->alg.cra_priority = alg->cra_priority; | |
298 | inst->alg.cra_blocksize = alg->cra_blocksize; | |
299 | inst->alg.cra_alignmask = alg->cra_alignmask; | |
300 | inst->alg.cra_type = &crypto_blkcipher_type; | |
301 | ||
302 | if (!(alg->cra_blocksize % 4)) | |
303 | inst->alg.cra_alignmask |= 3; | |
304 | inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; | |
305 | inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; | |
306 | inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; | |
307 | ||
308 | inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx); | |
309 | ||
310 | inst->alg.cra_init = crypto_pcbc_init_tfm; | |
311 | inst->alg.cra_exit = crypto_pcbc_exit_tfm; | |
312 | ||
313 | inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey; | |
314 | inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt; | |
315 | inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt; | |
316 | ||
317 | out_put_alg: | |
318 | crypto_mod_put(alg); | |
319 | return inst; | |
320 | } | |
321 | ||
322 | static void crypto_pcbc_free(struct crypto_instance *inst) | |
323 | { | |
324 | crypto_drop_spawn(crypto_instance_ctx(inst)); | |
325 | kfree(inst); | |
326 | } | |
327 | ||
328 | static struct crypto_template crypto_pcbc_tmpl = { | |
329 | .name = "pcbc", | |
330 | .alloc = crypto_pcbc_alloc, | |
331 | .free = crypto_pcbc_free, | |
332 | .module = THIS_MODULE, | |
333 | }; | |
334 | ||
335 | static int __init crypto_pcbc_module_init(void) | |
336 | { | |
337 | return crypto_register_template(&crypto_pcbc_tmpl); | |
338 | } | |
339 | ||
340 | static void __exit crypto_pcbc_module_exit(void) | |
341 | { | |
342 | crypto_unregister_template(&crypto_pcbc_tmpl); | |
343 | } | |
344 | ||
345 | module_init(crypto_pcbc_module_init); | |
346 | module_exit(crypto_pcbc_module_exit); | |
347 | ||
348 | MODULE_LICENSE("GPL"); | |
349 | MODULE_DESCRIPTION("PCBC block cipher algorithm"); |