aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/xcbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/xcbc.c')
-rw-r--r--crypto/xcbc.c370
1 files changed, 142 insertions, 228 deletions
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index b63b633e549c..bb7b67fba349 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -19,211 +19,142 @@
19 * Kazunori Miyazawa <miyazawa@linux-ipv6.org> 19 * Kazunori Miyazawa <miyazawa@linux-ipv6.org>
20 */ 20 */
21 21
22#include <crypto/scatterwalk.h> 22#include <crypto/internal/hash.h>
23#include <linux/crypto.h>
24#include <linux/err.h> 23#include <linux/err.h>
25#include <linux/hardirq.h>
26#include <linux/kernel.h> 24#include <linux/kernel.h>
27#include <linux/mm.h>
28#include <linux/rtnetlink.h>
29#include <linux/slab.h>
30#include <linux/scatterlist.h>
31 25
32static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 26static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
33 0x02020202, 0x02020202, 0x02020202, 0x02020202, 27 0x02020202, 0x02020202, 0x02020202, 0x02020202,
34 0x03030303, 0x03030303, 0x03030303, 0x03030303}; 28 0x03030303, 0x03030303, 0x03030303, 0x03030303};
29
35/* 30/*
36 * +------------------------ 31 * +------------------------
37 * | <parent tfm> 32 * | <parent tfm>
38 * +------------------------ 33 * +------------------------
39 * | crypto_xcbc_ctx 34 * | xcbc_tfm_ctx
40 * +------------------------ 35 * +------------------------
41 * | odds (block size) 36 * | consts (block size * 2)
42 * +------------------------ 37 * +------------------------
43 * | prev (block size) 38 */
39struct xcbc_tfm_ctx {
40 struct crypto_cipher *child;
41 u8 ctx[];
42};
43
44/*
44 * +------------------------ 45 * +------------------------
45 * | key (block size) 46 * | <shash desc>
46 * +------------------------ 47 * +------------------------
47 * | consts (block size * 3) 48 * | xcbc_desc_ctx
49 * +------------------------
50 * | odds (block size)
51 * +------------------------
52 * | prev (block size)
48 * +------------------------ 53 * +------------------------
49 */ 54 */
50struct crypto_xcbc_ctx { 55struct xcbc_desc_ctx {
51 struct crypto_cipher *child;
52 u8 *odds;
53 u8 *prev;
54 u8 *key;
55 u8 *consts;
56 void (*xor)(u8 *a, const u8 *b, unsigned int bs);
57 unsigned int keylen;
58 unsigned int len; 56 unsigned int len;
57 u8 ctx[];
59}; 58};
60 59
61static void xor_128(u8 *a, const u8 *b, unsigned int bs) 60static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
62{ 61 const u8 *inkey, unsigned int keylen)
63 ((u32 *)a)[0] ^= ((u32 *)b)[0];
64 ((u32 *)a)[1] ^= ((u32 *)b)[1];
65 ((u32 *)a)[2] ^= ((u32 *)b)[2];
66 ((u32 *)a)[3] ^= ((u32 *)b)[3];
67}
68
69static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent,
70 struct crypto_xcbc_ctx *ctx)
71{ 62{
72 int bs = crypto_hash_blocksize(parent); 63 unsigned long alignmask = crypto_shash_alignmask(parent);
64 struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
65 int bs = crypto_shash_blocksize(parent);
66 u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
73 int err = 0; 67 int err = 0;
74 u8 key1[bs]; 68 u8 key1[bs];
75 69
76 if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen))) 70 if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
77 return err; 71 return err;
78 72
79 crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts); 73 crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs);
74 crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2);
75 crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks);
80 76
81 return crypto_cipher_setkey(ctx->child, key1, bs); 77 return crypto_cipher_setkey(ctx->child, key1, bs);
82}
83
84static int crypto_xcbc_digest_setkey(struct crypto_hash *parent,
85 const u8 *inkey, unsigned int keylen)
86{
87 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
88
89 if (keylen != crypto_cipher_blocksize(ctx->child))
90 return -EINVAL;
91 78
92 ctx->keylen = keylen;
93 memcpy(ctx->key, inkey, keylen);
94 ctx->consts = (u8*)ks;
95
96 return _crypto_xcbc_digest_setkey(parent, ctx);
97} 79}
98 80
99static int crypto_xcbc_digest_init(struct hash_desc *pdesc) 81static int crypto_xcbc_digest_init(struct shash_desc *pdesc)
100{ 82{
101 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(pdesc->tfm); 83 unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm);
102 int bs = crypto_hash_blocksize(pdesc->tfm); 84 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
85 int bs = crypto_shash_blocksize(pdesc->tfm);
86 u8 *prev = PTR_ALIGN(&ctx->ctx[0], alignmask + 1) + bs;
103 87
104 ctx->len = 0; 88 ctx->len = 0;
105 memset(ctx->odds, 0, bs); 89 memset(prev, 0, bs);
106 memset(ctx->prev, 0, bs);
107 90
108 return 0; 91 return 0;
109} 92}
110 93
111static int crypto_xcbc_digest_update2(struct hash_desc *pdesc, 94static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
112 struct scatterlist *sg, 95 unsigned int len)
113 unsigned int nbytes)
114{ 96{
115 struct crypto_hash *parent = pdesc->tfm; 97 struct crypto_shash *parent = pdesc->tfm;
116 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); 98 unsigned long alignmask = crypto_shash_alignmask(parent);
117 struct crypto_cipher *tfm = ctx->child; 99 struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
118 int bs = crypto_hash_blocksize(parent); 100 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
119 101 struct crypto_cipher *tfm = tctx->child;
120 for (;;) { 102 int bs = crypto_shash_blocksize(parent);
121 struct page *pg = sg_page(sg); 103 u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
122 unsigned int offset = sg->offset; 104 u8 *prev = odds + bs;
123 unsigned int slen = sg->length; 105
124 106 /* checking the data can fill the block */
125 if (unlikely(slen > nbytes)) 107 if ((ctx->len + len) <= bs) {
126 slen = nbytes; 108 memcpy(odds + ctx->len, p, len);
127 109 ctx->len += len;
128 nbytes -= slen; 110 return 0;
129
130 while (slen > 0) {
131 unsigned int len = min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
132 char *p = crypto_kmap(pg, 0) + offset;
133
134 /* checking the data can fill the block */
135 if ((ctx->len + len) <= bs) {
136 memcpy(ctx->odds + ctx->len, p, len);
137 ctx->len += len;
138 slen -= len;
139
140 /* checking the rest of the page */
141 if (len + offset >= PAGE_SIZE) {
142 offset = 0;
143 pg++;
144 } else
145 offset += len;
146
147 crypto_kunmap(p, 0);
148 crypto_yield(pdesc->flags);
149 continue;
150 }
151
152 /* filling odds with new data and encrypting it */
153 memcpy(ctx->odds + ctx->len, p, bs - ctx->len);
154 len -= bs - ctx->len;
155 p += bs - ctx->len;
156
157 ctx->xor(ctx->prev, ctx->odds, bs);
158 crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev);
159
160 /* clearing the length */
161 ctx->len = 0;
162
163 /* encrypting the rest of data */
164 while (len > bs) {
165 ctx->xor(ctx->prev, p, bs);
166 crypto_cipher_encrypt_one(tfm, ctx->prev,
167 ctx->prev);
168 p += bs;
169 len -= bs;
170 }
171
172 /* keeping the surplus of blocksize */
173 if (len) {
174 memcpy(ctx->odds, p, len);
175 ctx->len = len;
176 }
177 crypto_kunmap(p, 0);
178 crypto_yield(pdesc->flags);
179 slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
180 offset = 0;
181 pg++;
182 }
183
184 if (!nbytes)
185 break;
186 sg = scatterwalk_sg_next(sg);
187 } 111 }
188 112
189 return 0; 113 /* filling odds with new data and encrypting it */
190} 114 memcpy(odds + ctx->len, p, bs - ctx->len);
115 len -= bs - ctx->len;
116 p += bs - ctx->len;
191 117
192static int crypto_xcbc_digest_update(struct hash_desc *pdesc, 118 crypto_xor(prev, odds, bs);
193 struct scatterlist *sg, 119 crypto_cipher_encrypt_one(tfm, prev, prev);
194 unsigned int nbytes)
195{
196 if (WARN_ON_ONCE(in_irq()))
197 return -EDEADLK;
198 return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
199}
200 120
201static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) 121 /* clearing the length */
202{ 122 ctx->len = 0;
203 struct crypto_hash *parent = pdesc->tfm;
204 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
205 struct crypto_cipher *tfm = ctx->child;
206 int bs = crypto_hash_blocksize(parent);
207 int err = 0;
208
209 if (ctx->len == bs) {
210 u8 key2[bs];
211 123
212 if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) 124 /* encrypting the rest of data */
213 return err; 125 while (len > bs) {
126 crypto_xor(prev, p, bs);
127 crypto_cipher_encrypt_one(tfm, prev, prev);
128 p += bs;
129 len -= bs;
130 }
214 131
215 crypto_cipher_encrypt_one(tfm, key2, 132 /* keeping the surplus of blocksize */
216 (u8 *)(ctx->consts + bs)); 133 if (len) {
134 memcpy(odds, p, len);
135 ctx->len = len;
136 }
217 137
218 ctx->xor(ctx->prev, ctx->odds, bs); 138 return 0;
219 ctx->xor(ctx->prev, key2, bs); 139}
220 _crypto_xcbc_digest_setkey(parent, ctx);
221 140
222 crypto_cipher_encrypt_one(tfm, out, ctx->prev); 141static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out)
223 } else { 142{
224 u8 key3[bs]; 143 struct crypto_shash *parent = pdesc->tfm;
144 unsigned long alignmask = crypto_shash_alignmask(parent);
145 struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
146 struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
147 struct crypto_cipher *tfm = tctx->child;
148 int bs = crypto_shash_blocksize(parent);
149 u8 *consts = PTR_ALIGN(&tctx->ctx[0], alignmask + 1);
150 u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
151 u8 *prev = odds + bs;
152 unsigned int offset = 0;
153
154 if (ctx->len != bs) {
225 unsigned int rlen; 155 unsigned int rlen;
226 u8 *p = ctx->odds + ctx->len; 156 u8 *p = odds + ctx->len;
157
227 *p = 0x80; 158 *p = 0x80;
228 p++; 159 p++;
229 160
@@ -231,32 +162,15 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
231 if (rlen) 162 if (rlen)
232 memset(p, 0, rlen); 163 memset(p, 0, rlen);
233 164
234 if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) 165 offset += bs;
235 return err;
236
237 crypto_cipher_encrypt_one(tfm, key3,
238 (u8 *)(ctx->consts + bs * 2));
239
240 ctx->xor(ctx->prev, ctx->odds, bs);
241 ctx->xor(ctx->prev, key3, bs);
242
243 _crypto_xcbc_digest_setkey(parent, ctx);
244
245 crypto_cipher_encrypt_one(tfm, out, ctx->prev);
246 } 166 }
247 167
248 return 0; 168 crypto_xor(prev, odds, bs);
249} 169 crypto_xor(prev, consts + offset, bs);
250 170
251static int crypto_xcbc_digest(struct hash_desc *pdesc, 171 crypto_cipher_encrypt_one(tfm, out, prev);
252 struct scatterlist *sg, unsigned int nbytes, u8 *out)
253{
254 if (WARN_ON_ONCE(in_irq()))
255 return -EDEADLK;
256 172
257 crypto_xcbc_digest_init(pdesc); 173 return 0;
258 crypto_xcbc_digest_update2(pdesc, sg, nbytes);
259 return crypto_xcbc_digest_final(pdesc, out);
260} 174}
261 175
262static int xcbc_init_tfm(struct crypto_tfm *tfm) 176static int xcbc_init_tfm(struct crypto_tfm *tfm)
@@ -264,95 +178,95 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm)
264 struct crypto_cipher *cipher; 178 struct crypto_cipher *cipher;
265 struct crypto_instance *inst = (void *)tfm->__crt_alg; 179 struct crypto_instance *inst = (void *)tfm->__crt_alg;
266 struct crypto_spawn *spawn = crypto_instance_ctx(inst); 180 struct crypto_spawn *spawn = crypto_instance_ctx(inst);
267 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); 181 struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
268 int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm));
269 182
270 cipher = crypto_spawn_cipher(spawn); 183 cipher = crypto_spawn_cipher(spawn);
271 if (IS_ERR(cipher)) 184 if (IS_ERR(cipher))
272 return PTR_ERR(cipher); 185 return PTR_ERR(cipher);
273 186
274 switch(bs) {
275 case 16:
276 ctx->xor = xor_128;
277 break;
278 default:
279 return -EINVAL;
280 }
281
282 ctx->child = cipher; 187 ctx->child = cipher;
283 ctx->odds = (u8*)(ctx+1);
284 ctx->prev = ctx->odds + bs;
285 ctx->key = ctx->prev + bs;
286 188
287 return 0; 189 return 0;
288}; 190};
289 191
290static void xcbc_exit_tfm(struct crypto_tfm *tfm) 192static void xcbc_exit_tfm(struct crypto_tfm *tfm)
291{ 193{
292 struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); 194 struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
293 crypto_free_cipher(ctx->child); 195 crypto_free_cipher(ctx->child);
294} 196}
295 197
296static struct crypto_instance *xcbc_alloc(struct rtattr **tb) 198static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
297{ 199{
298 struct crypto_instance *inst; 200 struct shash_instance *inst;
299 struct crypto_alg *alg; 201 struct crypto_alg *alg;
202 unsigned long alignmask;
300 int err; 203 int err;
301 204
302 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); 205 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
303 if (err) 206 if (err)
304 return ERR_PTR(err); 207 return err;
305 208
306 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, 209 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
307 CRYPTO_ALG_TYPE_MASK); 210 CRYPTO_ALG_TYPE_MASK);
308 if (IS_ERR(alg)) 211 if (IS_ERR(alg))
309 return ERR_CAST(alg); 212 return PTR_ERR(alg);
310 213
311 switch(alg->cra_blocksize) { 214 switch(alg->cra_blocksize) {
312 case 16: 215 case 16:
313 break; 216 break;
314 default: 217 default:
315 inst = ERR_PTR(-EINVAL);
316 goto out_put_alg; 218 goto out_put_alg;
317 } 219 }
318 220
319 inst = crypto_alloc_instance("xcbc", alg); 221 inst = shash_alloc_instance("xcbc", alg);
222 err = PTR_ERR(inst);
320 if (IS_ERR(inst)) 223 if (IS_ERR(inst))
321 goto out_put_alg; 224 goto out_put_alg;
322 225
323 inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH; 226 err = crypto_init_spawn(shash_instance_ctx(inst), alg,
324 inst->alg.cra_priority = alg->cra_priority; 227 shash_crypto_instance(inst),
325 inst->alg.cra_blocksize = alg->cra_blocksize; 228 CRYPTO_ALG_TYPE_MASK);
326 inst->alg.cra_alignmask = alg->cra_alignmask; 229 if (err)
327 inst->alg.cra_type = &crypto_hash_type; 230 goto out_free_inst;
328 231
329 inst->alg.cra_hash.digestsize = alg->cra_blocksize; 232 alignmask = alg->cra_alignmask | 3;
330 inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + 233 inst->alg.base.cra_alignmask = alignmask;
331 ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *)); 234 inst->alg.base.cra_priority = alg->cra_priority;
332 inst->alg.cra_init = xcbc_init_tfm; 235 inst->alg.base.cra_blocksize = alg->cra_blocksize;
333 inst->alg.cra_exit = xcbc_exit_tfm; 236
334 237 inst->alg.digestsize = alg->cra_blocksize;
335 inst->alg.cra_hash.init = crypto_xcbc_digest_init; 238 inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx),
336 inst->alg.cra_hash.update = crypto_xcbc_digest_update; 239 crypto_tfm_ctx_alignment()) +
337 inst->alg.cra_hash.final = crypto_xcbc_digest_final; 240 (alignmask &
338 inst->alg.cra_hash.digest = crypto_xcbc_digest; 241 ~(crypto_tfm_ctx_alignment() - 1)) +
339 inst->alg.cra_hash.setkey = crypto_xcbc_digest_setkey; 242 alg->cra_blocksize * 2;
243
244 inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx),
245 alignmask + 1) +
246 alg->cra_blocksize * 2;
247 inst->alg.base.cra_init = xcbc_init_tfm;
248 inst->alg.base.cra_exit = xcbc_exit_tfm;
249
250 inst->alg.init = crypto_xcbc_digest_init;
251 inst->alg.update = crypto_xcbc_digest_update;
252 inst->alg.final = crypto_xcbc_digest_final;
253 inst->alg.setkey = crypto_xcbc_digest_setkey;
254
255 err = shash_register_instance(tmpl, inst);
256 if (err) {
257out_free_inst:
258 shash_free_instance(shash_crypto_instance(inst));
259 }
340 260
341out_put_alg: 261out_put_alg:
342 crypto_mod_put(alg); 262 crypto_mod_put(alg);
343 return inst; 263 return err;
344}
345
346static void xcbc_free(struct crypto_instance *inst)
347{
348 crypto_drop_spawn(crypto_instance_ctx(inst));
349 kfree(inst);
350} 264}
351 265
352static struct crypto_template crypto_xcbc_tmpl = { 266static struct crypto_template crypto_xcbc_tmpl = {
353 .name = "xcbc", 267 .name = "xcbc",
354 .alloc = xcbc_alloc, 268 .create = xcbc_create,
355 .free = xcbc_free, 269 .free = shash_free_instance,
356 .module = THIS_MODULE, 270 .module = THIS_MODULE,
357}; 271};
358 272