rtl8366_smi: simplify rtl8366_attr_get_port_link function
[openwrt.git] / target / linux / generic-2.6 / files / crypto / ocf / cryptosoft.c
1 /*
2 * An OCF module that uses the linux kernel cryptoapi, based on the
3 * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
4 * but is mostly unrecognisable,
5 *
6 * Written by David McCullough <david_mccullough@securecomputing.com>
7 * Copyright (C) 2004-2007 David McCullough
8 * Copyright (C) 2004-2005 Intel Corporation.
9 *
10 * LICENSE TERMS
11 *
12 * The free distribution and use of this software in both source and binary
13 * form is allowed (with or without changes) provided that:
14 *
15 * 1. distributions of this source code include the above copyright
16 * notice, this list of conditions and the following disclaimer;
17 *
18 * 2. distributions in binary form include the above copyright
19 * notice, this list of conditions and the following disclaimer
20 * in the documentation and/or other associated materials;
21 *
22 * 3. the copyright holder's name is not used to endorse products
23 * built using this software without specific written permission.
24 *
25 * ALTERNATIVELY, provided that this notice is retained in full, this product
26 * may be distributed under the terms of the GNU General Public License (GPL),
27 * in which case the provisions of the GPL apply INSTEAD OF those given above.
28 *
29 * DISCLAIMER
30 *
31 * This software is provided 'as is' with no explicit or implied warranties
32 * in respect of its properties, including, but not limited to, correctness
33 * and/or fitness for purpose.
34 * ---------------------------------------------------------------------------
35 */
36
37 #ifndef AUTOCONF_INCLUDED
38 #include <linux/config.h>
39 #endif
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/list.h>
43 #include <linux/slab.h>
44 #include <linux/sched.h>
45 #include <linux/wait.h>
46 #include <linux/crypto.h>
47 #include <linux/mm.h>
48 #include <linux/skbuff.h>
49 #include <linux/random.h>
50 #include <asm/scatterlist.h>
51
52 #include <cryptodev.h>
53 #include <uio.h>
54
55 struct {
56 softc_device_decl sc_dev;
57 } swcr_softc;
58
59 #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
60
61 /* Software session entry */
62
63 #define SW_TYPE_CIPHER 0
64 #define SW_TYPE_HMAC 1
65 #define SW_TYPE_AUTH2 2
66 #define SW_TYPE_HASH 3
67 #define SW_TYPE_COMP 4
68 #define SW_TYPE_BLKCIPHER 5
69
70 struct swcr_data {
71 int sw_type;
72 int sw_alg;
73 struct crypto_tfm *sw_tfm;
74 union {
75 struct {
76 char *sw_key;
77 int sw_klen;
78 int sw_mlen;
79 } hmac;
80 void *sw_comp_buf;
81 } u;
82 struct swcr_data *sw_next;
83 };
84
85 #ifndef CRYPTO_TFM_MODE_CBC
86 /*
87 * As of linux-2.6.21 this is no longer defined, and presumably no longer
88 * needed to be passed into the crypto core code.
89 */
90 #define CRYPTO_TFM_MODE_CBC 0
91 #define CRYPTO_TFM_MODE_ECB 0
92 #endif
93
94 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
95 /*
96 * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
97 * API into old API.
98 */
99
100 /* Symmetric/Block Cipher */
101 struct blkcipher_desc
102 {
103 struct crypto_tfm *tfm;
104 void *info;
105 };
106 #define ecb(X) #X
107 #define cbc(X) #X
108 #define crypto_has_blkcipher(X, Y, Z) crypto_alg_available(X, 0)
109 #define crypto_blkcipher_cast(X) X
110 #define crypto_blkcipher_tfm(X) X
111 #define crypto_alloc_blkcipher(X, Y, Z) crypto_alloc_tfm(X, mode)
112 #define crypto_blkcipher_ivsize(X) crypto_tfm_alg_ivsize(X)
113 #define crypto_blkcipher_blocksize(X) crypto_tfm_alg_blocksize(X)
114 #define crypto_blkcipher_setkey(X, Y, Z) crypto_cipher_setkey(X, Y, Z)
115 #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
116 crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
117 #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
118 crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
119
120 /* Hash/HMAC/Digest */
121 struct hash_desc
122 {
123 struct crypto_tfm *tfm;
124 };
125 #define hmac(X) #X
126 #define crypto_has_hash(X, Y, Z) crypto_alg_available(X, 0)
127 #define crypto_hash_cast(X) X
128 #define crypto_hash_tfm(X) X
129 #define crypto_alloc_hash(X, Y, Z) crypto_alloc_tfm(X, mode)
130 #define crypto_hash_digestsize(X) crypto_tfm_alg_digestsize(X)
131 #define crypto_hash_digest(W, X, Y, Z) \
132 crypto_digest_digest((W)->tfm, X, sg_num, Z)
133
134 /* Asymmetric Cipher */
135 #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0)
136
137 /* Compression */
138 #define crypto_has_comp(X, Y, Z) crypto_alg_available(X, 0)
139 #define crypto_comp_tfm(X) X
140 #define crypto_comp_cast(X) X
141 #define crypto_alloc_comp(X, Y, Z) crypto_alloc_tfm(X, mode)
142 #else
143 #define ecb(X) "ecb(" #X ")"
144 #define cbc(X) "cbc(" #X ")"
145 #define hmac(X) "hmac(" #X ")"
146 #endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
147
148 struct crypto_details
149 {
150 char *alg_name;
151 int mode;
152 int sw_type;
153 };
154
155 /*
156 * This needs to be kept updated with CRYPTO_xxx list (cryptodev.h).
157 * If the Algorithm is not supported, then insert a {NULL, 0, 0} entry.
158 *
159 * IMPORTANT: The index to the array IS CRYPTO_xxx.
160 */
161 static struct crypto_details crypto_details[CRYPTO_ALGORITHM_MAX + 1] = {
162 { NULL, 0, 0 },
163 /* CRYPTO_xxx index starts at 1 */
164 { cbc(des), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
165 { cbc(des3_ede), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
166 { cbc(blowfish), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
167 { cbc(cast5), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
168 { cbc(skipjack), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
169 { hmac(md5), 0, SW_TYPE_HMAC },
170 { hmac(sha1), 0, SW_TYPE_HMAC },
171 { hmac(ripemd160), 0, SW_TYPE_HMAC },
172 { "md5-kpdk??", 0, SW_TYPE_HASH },
173 { "sha1-kpdk??", 0, SW_TYPE_HASH },
174 { cbc(aes), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
175 { ecb(arc4), CRYPTO_TFM_MODE_ECB, SW_TYPE_BLKCIPHER },
176 { "md5", 0, SW_TYPE_HASH },
177 { "sha1", 0, SW_TYPE_HASH },
178 { hmac(digest_null), 0, SW_TYPE_HMAC },
179 { cbc(cipher_null), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
180 { "deflate", 0, SW_TYPE_COMP },
181 { hmac(sha256), 0, SW_TYPE_HMAC },
182 { hmac(sha384), 0, SW_TYPE_HMAC },
183 { hmac(sha512), 0, SW_TYPE_HMAC },
184 { cbc(camellia), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER },
185 { "sha256", 0, SW_TYPE_HASH },
186 { "sha384", 0, SW_TYPE_HASH },
187 { "sha512", 0, SW_TYPE_HASH },
188 { "ripemd160", 0, SW_TYPE_HASH },
189 };
190
191 int32_t swcr_id = -1;
192 module_param(swcr_id, int, 0444);
193 MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
194
195 int swcr_fail_if_compression_grows = 1;
196 module_param(swcr_fail_if_compression_grows, int, 0644);
197 MODULE_PARM_DESC(swcr_fail_if_compression_grows,
198 "Treat compression that results in more data as a failure");
199
200 static struct swcr_data **swcr_sessions = NULL;
201 static u_int32_t swcr_sesnum = 0;
202
203 static int swcr_process(device_t, struct cryptop *, int);
204 static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
205 static int swcr_freesession(device_t, u_int64_t);
206
207 static device_method_t swcr_methods = {
208 /* crypto device methods */
209 DEVMETHOD(cryptodev_newsession, swcr_newsession),
210 DEVMETHOD(cryptodev_freesession,swcr_freesession),
211 DEVMETHOD(cryptodev_process, swcr_process),
212 };
213
214 #define debug swcr_debug
215 int swcr_debug = 0;
216 module_param(swcr_debug, int, 0644);
217 MODULE_PARM_DESC(swcr_debug, "Enable debug");
218
219 /*
220 * Generate a new software session.
221 */
222 static int
223 swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
224 {
225 struct swcr_data **swd;
226 u_int32_t i;
227 int error;
228 char *algo;
229 int mode, sw_type;
230
231 dprintk("%s()\n", __FUNCTION__);
232 if (sid == NULL || cri == NULL) {
233 dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
234 return EINVAL;
235 }
236
237 if (swcr_sessions) {
238 for (i = 1; i < swcr_sesnum; i++)
239 if (swcr_sessions[i] == NULL)
240 break;
241 } else
242 i = 1; /* NB: to silence compiler warning */
243
244 if (swcr_sessions == NULL || i == swcr_sesnum) {
245 if (swcr_sessions == NULL) {
246 i = 1; /* We leave swcr_sessions[0] empty */
247 swcr_sesnum = CRYPTO_SW_SESSIONS;
248 } else
249 swcr_sesnum *= 2;
250
251 swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
252 if (swd == NULL) {
253 /* Reset session number */
254 if (swcr_sesnum == CRYPTO_SW_SESSIONS)
255 swcr_sesnum = 0;
256 else
257 swcr_sesnum /= 2;
258 dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
259 return ENOBUFS;
260 }
261 memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
262
263 /* Copy existing sessions */
264 if (swcr_sessions) {
265 memcpy(swd, swcr_sessions,
266 (swcr_sesnum / 2) * sizeof(struct swcr_data *));
267 kfree(swcr_sessions);
268 }
269
270 swcr_sessions = swd;
271 }
272
273 swd = &swcr_sessions[i];
274 *sid = i;
275
276 while (cri) {
277 *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
278 SLAB_ATOMIC);
279 if (*swd == NULL) {
280 swcr_freesession(NULL, i);
281 dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
282 return ENOBUFS;
283 }
284 memset(*swd, 0, sizeof(struct swcr_data));
285
286 if (cri->cri_alg > CRYPTO_ALGORITHM_MAX) {
287 printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
288 swcr_freesession(NULL, i);
289 return EINVAL;
290 }
291
292 algo = crypto_details[cri->cri_alg].alg_name;
293 if (!algo || !*algo) {
294 printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
295 swcr_freesession(NULL, i);
296 return EINVAL;
297 }
298
299 mode = crypto_details[cri->cri_alg].mode;
300 sw_type = crypto_details[cri->cri_alg].sw_type;
301
302 /* Algorithm specific configuration */
303 switch (cri->cri_alg) {
304 case CRYPTO_NULL_CBC:
305 cri->cri_klen = 0; /* make it work with crypto API */
306 break;
307 default:
308 break;
309 }
310
311 if (sw_type == SW_TYPE_BLKCIPHER) {
312 dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__,
313 algo, mode);
314
315 (*swd)->sw_tfm = crypto_blkcipher_tfm(
316 crypto_alloc_blkcipher(algo, 0,
317 CRYPTO_ALG_ASYNC));
318 if (!(*swd)->sw_tfm) {
319 dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n",
320 algo,mode);
321 swcr_freesession(NULL, i);
322 return EINVAL;
323 }
324
325 if (debug) {
326 dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
327 __FUNCTION__,cri->cri_klen,(cri->cri_klen + 7)/8);
328 for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
329 {
330 dprintk("%s0x%x", (i % 8) ? " " : "\n ",cri->cri_key[i]);
331 }
332 dprintk("\n");
333 }
334 error = crypto_blkcipher_setkey(
335 crypto_blkcipher_cast((*swd)->sw_tfm), cri->cri_key,
336 (cri->cri_klen + 7) / 8);
337 if (error) {
338 printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
339 (*swd)->sw_tfm->crt_flags);
340 swcr_freesession(NULL, i);
341 return error;
342 }
343 } else if (sw_type == SW_TYPE_HMAC || sw_type == SW_TYPE_HASH) {
344 dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__,
345 algo, mode);
346
347 (*swd)->sw_tfm = crypto_hash_tfm(
348 crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
349
350 if (!(*swd)->sw_tfm) {
351 dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
352 algo, mode);
353 swcr_freesession(NULL, i);
354 return EINVAL;
355 }
356
357 (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
358 (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
359 SLAB_ATOMIC);
360 if ((*swd)->u.hmac.sw_key == NULL) {
361 swcr_freesession(NULL, i);
362 dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
363 return ENOBUFS;
364 }
365 memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
366 if (cri->cri_mlen) {
367 (*swd)->u.hmac.sw_mlen = cri->cri_mlen;
368 } else {
369 (*swd)->u.hmac.sw_mlen =
370 crypto_hash_digestsize(
371 crypto_hash_cast((*swd)->sw_tfm));
372 }
373 } else if (sw_type == SW_TYPE_COMP) {
374 (*swd)->sw_tfm = crypto_comp_tfm(
375 crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
376 if (!(*swd)->sw_tfm) {
377 dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
378 algo, mode);
379 swcr_freesession(NULL, i);
380 return EINVAL;
381 }
382 (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
383 if ((*swd)->u.sw_comp_buf == NULL) {
384 swcr_freesession(NULL, i);
385 dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
386 return ENOBUFS;
387 }
388 } else {
389 printk("cryptosoft: Unhandled sw_type %d\n", sw_type);
390 swcr_freesession(NULL, i);
391 return EINVAL;
392 }
393
394 (*swd)->sw_alg = cri->cri_alg;
395 (*swd)->sw_type = sw_type;
396
397 cri = cri->cri_next;
398 swd = &((*swd)->sw_next);
399 }
400 return 0;
401 }
402
403 /*
404 * Free a session.
405 */
406 static int
407 swcr_freesession(device_t dev, u_int64_t tid)
408 {
409 struct swcr_data *swd;
410 u_int32_t sid = CRYPTO_SESID2LID(tid);
411
412 dprintk("%s()\n", __FUNCTION__);
413 if (sid > swcr_sesnum || swcr_sessions == NULL ||
414 swcr_sessions[sid] == NULL) {
415 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
416 return(EINVAL);
417 }
418
419 /* Silently accept and return */
420 if (sid == 0)
421 return(0);
422
423 while ((swd = swcr_sessions[sid]) != NULL) {
424 swcr_sessions[sid] = swd->sw_next;
425 if (swd->sw_tfm)
426 crypto_free_tfm(swd->sw_tfm);
427 if (swd->sw_type == SW_TYPE_COMP) {
428 if (swd->u.sw_comp_buf)
429 kfree(swd->u.sw_comp_buf);
430 } else {
431 if (swd->u.hmac.sw_key)
432 kfree(swd->u.hmac.sw_key);
433 }
434 kfree(swd);
435 }
436 return 0;
437 }
438
439 /*
440 * Process a software request.
441 */
442 static int
443 swcr_process(device_t dev, struct cryptop *crp, int hint)
444 {
445 struct cryptodesc *crd;
446 struct swcr_data *sw;
447 u_int32_t lid;
448 #define SCATTERLIST_MAX 16
449 struct scatterlist sg[SCATTERLIST_MAX];
450 int sg_num, sg_len, skip;
451 struct sk_buff *skb = NULL;
452 struct uio *uiop = NULL;
453
454 dprintk("%s()\n", __FUNCTION__);
455 /* Sanity check */
456 if (crp == NULL) {
457 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
458 return EINVAL;
459 }
460
461 crp->crp_etype = 0;
462
463 if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
464 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
465 crp->crp_etype = EINVAL;
466 goto done;
467 }
468
469 lid = crp->crp_sid & 0xffffffff;
470 if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||
471 swcr_sessions[lid] == NULL) {
472 crp->crp_etype = ENOENT;
473 dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
474 goto done;
475 }
476
477 /*
478 * do some error checking outside of the loop for SKB and IOV processing
479 * this leaves us with valid skb or uiop pointers for later
480 */
481 if (crp->crp_flags & CRYPTO_F_SKBUF) {
482 skb = (struct sk_buff *) crp->crp_buf;
483 if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
484 printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
485 skb_shinfo(skb)->nr_frags);
486 goto done;
487 }
488 } else if (crp->crp_flags & CRYPTO_F_IOV) {
489 uiop = (struct uio *) crp->crp_buf;
490 if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
491 printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
492 uiop->uio_iovcnt);
493 goto done;
494 }
495 }
496
497 /* Go through crypto descriptors, processing as we go */
498 for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
499 /*
500 * Find the crypto context.
501 *
502 * XXX Note that the logic here prevents us from having
503 * XXX the same algorithm multiple times in a session
504 * XXX (or rather, we can but it won't give us the right
505 * XXX results). To do that, we'd need some way of differentiating
506 * XXX between the various instances of an algorithm (so we can
507 * XXX locate the correct crypto context).
508 */
509 for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg;
510 sw = sw->sw_next)
511 ;
512
513 /* No such context ? */
514 if (sw == NULL) {
515 crp->crp_etype = EINVAL;
516 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
517 goto done;
518 }
519
520 skip = crd->crd_skip;
521
522 /*
523 * setup the SG list skip from the start of the buffer
524 */
525 memset(sg, 0, sizeof(sg));
526 if (crp->crp_flags & CRYPTO_F_SKBUF) {
527 int i, len;
528
529 sg_num = 0;
530 sg_len = 0;
531
532 if (skip < skb_headlen(skb)) {
533 len = skb_headlen(skb) - skip;
534 if (len + sg_len > crd->crd_len)
535 len = crd->crd_len - sg_len;
536 sg_set_page(&sg[sg_num],
537 virt_to_page(skb->data + skip), len,
538 offset_in_page(skb->data + skip));
539 sg_len += len;
540 sg_num++;
541 skip = 0;
542 } else
543 skip -= skb_headlen(skb);
544
545 for (i = 0; sg_len < crd->crd_len &&
546 i < skb_shinfo(skb)->nr_frags &&
547 sg_num < SCATTERLIST_MAX; i++) {
548 if (skip < skb_shinfo(skb)->frags[i].size) {
549 len = skb_shinfo(skb)->frags[i].size - skip;
550 if (len + sg_len > crd->crd_len)
551 len = crd->crd_len - sg_len;
552 sg_set_page(&sg[sg_num],
553 skb_shinfo(skb)->frags[i].page,
554 len,
555 skb_shinfo(skb)->frags[i].page_offset + skip);
556 sg_len += len;
557 sg_num++;
558 skip = 0;
559 } else
560 skip -= skb_shinfo(skb)->frags[i].size;
561 }
562 } else if (crp->crp_flags & CRYPTO_F_IOV) {
563 int len;
564
565 sg_len = 0;
566 for (sg_num = 0; sg_len <= crd->crd_len &&
567 sg_num < uiop->uio_iovcnt &&
568 sg_num < SCATTERLIST_MAX; sg_num++) {
569 if (skip <= uiop->uio_iov[sg_num].iov_len) {
570 len = uiop->uio_iov[sg_num].iov_len - skip;
571 if (len + sg_len > crd->crd_len)
572 len = crd->crd_len - sg_len;
573 sg_set_page(&sg[sg_num],
574 virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
575 len,
576 offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
577 sg_len += len;
578 skip = 0;
579 } else
580 skip -= uiop->uio_iov[sg_num].iov_len;
581 }
582 } else {
583 sg_len = (crp->crp_ilen - skip);
584 if (sg_len > crd->crd_len)
585 sg_len = crd->crd_len;
586 sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip),
587 sg_len, offset_in_page(crp->crp_buf + skip));
588 sg_num = 1;
589 }
590
591
592 switch (sw->sw_type) {
593 case SW_TYPE_BLKCIPHER: {
594 unsigned char iv[EALG_MAX_BLOCK_LEN];
595 unsigned char *ivp = iv;
596 int ivsize =
597 crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
598 struct blkcipher_desc desc;
599
600 if (sg_len < crypto_blkcipher_blocksize(
601 crypto_blkcipher_cast(sw->sw_tfm))) {
602 crp->crp_etype = EINVAL;
603 dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
604 sg_len, crypto_blkcipher_blocksize(
605 crypto_blkcipher_cast(sw->sw_tfm)));
606 goto done;
607 }
608
609 if (ivsize > sizeof(iv)) {
610 crp->crp_etype = EINVAL;
611 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
612 goto done;
613 }
614
615 if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
616 int i, error;
617
618 if (debug) {
619 dprintk("%s key:", __FUNCTION__);
620 for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
621 dprintk("%s0x%x", (i % 8) ? " " : "\n ",
622 crd->crd_key[i]);
623 dprintk("\n");
624 }
625 error = crypto_blkcipher_setkey(
626 crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
627 (crd->crd_klen + 7) / 8);
628 if (error) {
629 dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
630 error, sw->sw_tfm->crt_flags);
631 crp->crp_etype = -error;
632 }
633 }
634
635 memset(&desc, 0, sizeof(desc));
636 desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
637
638 if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
639
640 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
641 ivp = crd->crd_iv;
642 } else {
643 get_random_bytes(ivp, ivsize);
644 }
645 /*
646 * do we have to copy the IV back to the buffer ?
647 */
648 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
649 crypto_copyback(crp->crp_flags, crp->crp_buf,
650 crd->crd_inject, ivsize, (caddr_t)ivp);
651 }
652 desc.info = ivp;
653 crypto_blkcipher_encrypt_iv(&desc, sg, sg, sg_len);
654
655 } else { /*decrypt */
656
657 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
658 ivp = crd->crd_iv;
659 } else {
660 crypto_copydata(crp->crp_flags, crp->crp_buf,
661 crd->crd_inject, ivsize, (caddr_t)ivp);
662 }
663 desc.info = ivp;
664 crypto_blkcipher_decrypt_iv(&desc, sg, sg, sg_len);
665 }
666 } break;
667 case SW_TYPE_HMAC:
668 case SW_TYPE_HASH:
669 {
670 char result[HASH_MAX_LEN];
671 struct hash_desc desc;
672
673 /* check we have room for the result */
674 if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
675 dprintk(
676 "cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d digestsize=%d\n",
677 crp->crp_ilen, crd->crd_skip + sg_len, crd->crd_inject,
678 sw->u.hmac.sw_mlen);
679 crp->crp_etype = EINVAL;
680 goto done;
681 }
682
683 memset(&desc, 0, sizeof(desc));
684 desc.tfm = crypto_hash_cast(sw->sw_tfm);
685
686 memset(result, 0, sizeof(result));
687
688 if (sw->sw_type == SW_TYPE_HMAC) {
689 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
690 crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
691 sg, sg_num, result);
692 #else
693 crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
694 sw->u.hmac.sw_klen);
695 crypto_hash_digest(&desc, sg, sg_len, result);
696 #endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
697
698 } else { /* SW_TYPE_HASH */
699 crypto_hash_digest(&desc, sg, sg_len, result);
700 }
701
702 crypto_copyback(crp->crp_flags, crp->crp_buf,
703 crd->crd_inject, sw->u.hmac.sw_mlen, result);
704 }
705 break;
706
707 case SW_TYPE_COMP: {
708 void *ibuf = NULL;
709 void *obuf = sw->u.sw_comp_buf;
710 int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
711 int ret = 0;
712
713 /*
714 * we need to use an additional copy if there is more than one
715 * input chunk since the kernel comp routines do not handle
716 * SG yet. Otherwise we just use the input buffer as is.
717 * Rather than allocate another buffer we just split the tmp
718 * buffer we already have.
719 * Perhaps we should just use zlib directly ?
720 */
721 if (sg_num > 1) {
722 int blk;
723
724 ibuf = obuf;
725 for (blk = 0; blk < sg_num; blk++) {
726 memcpy(obuf, sg_virt(&sg[blk]),
727 sg[blk].length);
728 obuf += sg[blk].length;
729 }
730 olen -= sg_len;
731 } else
732 ibuf = sg_virt(&sg[0]);
733
734 if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
735 ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
736 ibuf, ilen, obuf, &olen);
737 if (!ret && olen > crd->crd_len) {
738 dprintk("cryptosoft: ERANGE compress %d into %d\n",
739 crd->crd_len, olen);
740 if (swcr_fail_if_compression_grows)
741 ret = ERANGE;
742 }
743 } else { /* decompress */
744 ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
745 ibuf, ilen, obuf, &olen);
746 if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
747 dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
748 "space for %d,at offset %d\n",
749 crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
750 ret = ETOOSMALL;
751 }
752 }
753 if (ret)
754 dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret);
755
756 /*
757 * on success copy result back,
758 * linux crpyto API returns -errno, we need to fix that
759 */
760 crp->crp_etype = ret < 0 ? -ret : ret;
761 if (ret == 0) {
762 /* copy back the result and return it's size */
763 crypto_copyback(crp->crp_flags, crp->crp_buf,
764 crd->crd_inject, olen, obuf);
765 crp->crp_olen = olen;
766 }
767
768
769 } break;
770
771 default:
772 /* Unknown/unsupported algorithm */
773 dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
774 crp->crp_etype = EINVAL;
775 goto done;
776 }
777 }
778
779 done:
780 crypto_done(crp);
781 return 0;
782 }
783
784 static int
785 cryptosoft_init(void)
786 {
787 int i, sw_type, mode;
788 char *algo;
789
790 dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);
791
792 softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods);
793
794 swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc),
795 CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
796 if (swcr_id < 0) {
797 printk("Software crypto device cannot initialize!");
798 return -ENODEV;
799 }
800
801 #define REGISTER(alg) \
802 crypto_register(swcr_id, alg, 0,0);
803
804 for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; ++i)
805 {
806
807 algo = crypto_details[i].alg_name;
808 if (!algo || !*algo)
809 {
810 dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i);
811 continue;
812 }
813
814 mode = crypto_details[i].mode;
815 sw_type = crypto_details[i].sw_type;
816
817 switch (sw_type)
818 {
819 case SW_TYPE_CIPHER:
820 if (crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC))
821 {
822 REGISTER(i);
823 }
824 else
825 {
826 dprintk("%s:CIPHER algorithm %d:'%s' not supported\n",
827 __FUNCTION__, i, algo);
828 }
829 break;
830 case SW_TYPE_HMAC:
831 if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
832 {
833 REGISTER(i);
834 }
835 else
836 {
837 dprintk("%s:HMAC algorithm %d:'%s' not supported\n",
838 __FUNCTION__, i, algo);
839 }
840 break;
841 case SW_TYPE_HASH:
842 if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC))
843 {
844 REGISTER(i);
845 }
846 else
847 {
848 dprintk("%s:HASH algorithm %d:'%s' not supported\n",
849 __FUNCTION__, i, algo);
850 }
851 break;
852 case SW_TYPE_COMP:
853 if (crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC))
854 {
855 REGISTER(i);
856 }
857 else
858 {
859 dprintk("%s:COMP algorithm %d:'%s' not supported\n",
860 __FUNCTION__, i, algo);
861 }
862 break;
863 case SW_TYPE_BLKCIPHER:
864 if (crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC))
865 {
866 REGISTER(i);
867 }
868 else
869 {
870 dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n",
871 __FUNCTION__, i, algo);
872 }
873 break;
874 default:
875 dprintk(
876 "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
877 __FUNCTION__, sw_type, i, algo);
878 break;
879 }
880 }
881
882 return(0);
883 }
884
885 static void
886 cryptosoft_exit(void)
887 {
888 dprintk("%s()\n", __FUNCTION__);
889 crypto_unregister_all(swcr_id);
890 swcr_id = -1;
891 }
892
893 module_init(cryptosoft_init);
894 module_exit(cryptosoft_exit);
895
896 MODULE_LICENSE("Dual BSD/GPL");
897 MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
898 MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
This page took 0.083823 seconds and 5 git commands to generate.