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,
6 * Written by David McCullough <david_mccullough@securecomputing.com>
7 * Copyright (C) 2004-2007 David McCullough
8 * Copyright (C) 2004-2005 Intel Corporation.
12 * The free distribution and use of this software in both source and binary
13 * form is allowed (with or without changes) provided that:
15 * 1. distributions of this source code include the above copyright
16 * notice, this list of conditions and the following disclaimer;
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;
22 * 3. the copyright holder's name is not used to endorse products
23 * built using this software without specific written permission.
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.
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 * ---------------------------------------------------------------------------
37 #ifndef AUTOCONF_INCLUDED
38 #include <linux/config.h>
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>
48 #include <linux/skbuff.h>
49 #include <linux/random.h>
50 #include <asm/scatterlist.h>
52 #include <cryptodev.h>
56 softc_device_decl sc_dev
;
59 #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
61 /* Software session entry */
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
73 struct crypto_tfm
*sw_tfm
;
82 struct swcr_data
*sw_next
;
85 #ifndef CRYPTO_TFM_MODE_CBC
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.
90 #define CRYPTO_TFM_MODE_CBC 0
91 #define CRYPTO_TFM_MODE_ECB 0
94 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
96 * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
100 /* Symmetric/Block Cipher */
101 struct blkcipher_desc
103 struct crypto_tfm
*tfm
;
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))
120 /* Hash/HMAC/Digest */
123 struct crypto_tfm
*tfm
;
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)
134 /* Asymmetric Cipher */
135 #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0)
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)
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) */
148 struct crypto_details
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.
159 * IMPORTANT: The index to the array IS CRYPTO_xxx.
161 static struct crypto_details crypto_details
[CRYPTO_ALGORITHM_MAX
+ 1] = {
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
},
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");
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");
200 static struct swcr_data
**swcr_sessions
= NULL
;
201 static u_int32_t swcr_sesnum
= 0;
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
);
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
),
214 #define debug swcr_debug
216 module_param(swcr_debug
, int, 0644);
217 MODULE_PARM_DESC(swcr_debug
, "Enable debug");
220 * Generate a new software session.
223 swcr_newsession(device_t dev
, u_int32_t
*sid
, struct cryptoini
*cri
)
225 struct swcr_data
**swd
;
231 dprintk("%s()\n", __FUNCTION__
);
232 if (sid
== NULL
|| cri
== NULL
) {
233 dprintk("%s,%d - EINVAL\n", __FILE__
, __LINE__
);
238 for (i
= 1; i
< swcr_sesnum
; i
++)
239 if (swcr_sessions
[i
] == NULL
)
242 i
= 1; /* NB: to silence compiler warning */
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
;
251 swd
= kmalloc(swcr_sesnum
* sizeof(struct swcr_data
*), SLAB_ATOMIC
);
253 /* Reset session number */
254 if (swcr_sesnum
== CRYPTO_SW_SESSIONS
)
258 dprintk("%s,%d: ENOBUFS\n", __FILE__
, __LINE__
);
261 memset(swd
, 0, swcr_sesnum
* sizeof(struct swcr_data
*));
263 /* Copy existing sessions */
265 memcpy(swd
, swcr_sessions
,
266 (swcr_sesnum
/ 2) * sizeof(struct swcr_data
*));
267 kfree(swcr_sessions
);
273 swd
= &swcr_sessions
[i
];
277 *swd
= (struct swcr_data
*) kmalloc(sizeof(struct swcr_data
),
280 swcr_freesession(NULL
, i
);
281 dprintk("%s,%d: ENOBUFS\n", __FILE__
, __LINE__
);
284 memset(*swd
, 0, sizeof(struct swcr_data
));
286 if (cri
->cri_alg
> CRYPTO_ALGORITHM_MAX
) {
287 printk("cryptosoft: Unknown algorithm 0x%x\n", cri
->cri_alg
);
288 swcr_freesession(NULL
, i
);
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
);
299 mode
= crypto_details
[cri
->cri_alg
].mode
;
300 sw_type
= crypto_details
[cri
->cri_alg
].sw_type
;
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 */
311 if (sw_type
== SW_TYPE_BLKCIPHER
) {
312 dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__
,
315 (*swd
)->sw_tfm
= crypto_blkcipher_tfm(
316 crypto_alloc_blkcipher(algo
, 0,
318 if (!(*swd
)->sw_tfm
) {
319 dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n",
321 swcr_freesession(NULL
, i
);
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
++)
330 dprintk("%s0x%x", (i
% 8) ? " " : "\n ",cri
->cri_key
[i
]);
334 error
= crypto_blkcipher_setkey(
335 crypto_blkcipher_cast((*swd
)->sw_tfm
), cri
->cri_key
,
336 (cri
->cri_klen
+ 7) / 8);
338 printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error
,
339 (*swd
)->sw_tfm
->crt_flags
);
340 swcr_freesession(NULL
, i
);
343 } else if (sw_type
== SW_TYPE_HMAC
|| sw_type
== SW_TYPE_HASH
) {
344 dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__
,
347 (*swd
)->sw_tfm
= crypto_hash_tfm(
348 crypto_alloc_hash(algo
, 0, CRYPTO_ALG_ASYNC
));
350 if (!(*swd
)->sw_tfm
) {
351 dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
353 swcr_freesession(NULL
, i
);
357 (*swd
)->u
.hmac
.sw_klen
= (cri
->cri_klen
+ 7) / 8;
358 (*swd
)->u
.hmac
.sw_key
= (char *)kmalloc((*swd
)->u
.hmac
.sw_klen
,
360 if ((*swd
)->u
.hmac
.sw_key
== NULL
) {
361 swcr_freesession(NULL
, i
);
362 dprintk("%s,%d: ENOBUFS\n", __FILE__
, __LINE__
);
365 memcpy((*swd
)->u
.hmac
.sw_key
, cri
->cri_key
, (*swd
)->u
.hmac
.sw_klen
);
367 (*swd
)->u
.hmac
.sw_mlen
= cri
->cri_mlen
;
369 (*swd
)->u
.hmac
.sw_mlen
=
370 crypto_hash_digestsize(
371 crypto_hash_cast((*swd
)->sw_tfm
));
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",
379 swcr_freesession(NULL
, i
);
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__
);
389 printk("cryptosoft: Unhandled sw_type %d\n", sw_type
);
390 swcr_freesession(NULL
, i
);
394 (*swd
)->sw_alg
= cri
->cri_alg
;
395 (*swd
)->sw_type
= sw_type
;
398 swd
= &((*swd
)->sw_next
);
407 swcr_freesession(device_t dev
, u_int64_t tid
)
409 struct swcr_data
*swd
;
410 u_int32_t sid
= CRYPTO_SESID2LID(tid
);
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__
);
419 /* Silently accept and return */
423 while ((swd
= swcr_sessions
[sid
]) != NULL
) {
424 swcr_sessions
[sid
] = swd
->sw_next
;
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
);
431 if (swd
->u
.hmac
.sw_key
)
432 kfree(swd
->u
.hmac
.sw_key
);
440 * Process a software request.
443 swcr_process(device_t dev
, struct cryptop
*crp
, int hint
)
445 struct cryptodesc
*crd
;
446 struct swcr_data
*sw
;
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
;
454 dprintk("%s()\n", __FUNCTION__
);
457 dprintk("%s,%d: EINVAL\n", __FILE__
, __LINE__
);
463 if (crp
->crp_desc
== NULL
|| crp
->crp_buf
== NULL
) {
464 dprintk("%s,%d: EINVAL\n", __FILE__
, __LINE__
);
465 crp
->crp_etype
= EINVAL
;
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__
);
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
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
);
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__
,
497 /* Go through crypto descriptors, processing as we go */
498 for (crd
= crp
->crp_desc
; crd
; crd
= crd
->crd_next
) {
500 * Find the crypto context.
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).
509 for (sw
= swcr_sessions
[lid
]; sw
&& sw
->sw_alg
!= crd
->crd_alg
;
513 /* No such context ? */
515 crp
->crp_etype
= EINVAL
;
516 dprintk("%s,%d: EINVAL\n", __FILE__
, __LINE__
);
520 skip
= crd
->crd_skip
;
523 * setup the SG list skip from the start of the buffer
525 memset(sg
, 0, sizeof(sg
));
526 if (crp
->crp_flags
& CRYPTO_F_SKBUF
) {
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
));
543 skip
-= skb_headlen(skb
);
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
,
555 skb_shinfo(skb
)->frags
[i
].page_offset
+ skip
);
560 skip
-= skb_shinfo(skb
)->frags
[i
].size
;
562 } else if (crp
->crp_flags
& CRYPTO_F_IOV
) {
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
),
576 offset_in_page(uiop
->uio_iov
[sg_num
].iov_base
+skip
));
580 skip
-= uiop
->uio_iov
[sg_num
].iov_len
;
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
));
592 switch (sw
->sw_type
) {
593 case SW_TYPE_BLKCIPHER
: {
594 unsigned char iv
[EALG_MAX_BLOCK_LEN
];
595 unsigned char *ivp
= iv
;
597 crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw
->sw_tfm
));
598 struct blkcipher_desc desc
;
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
)));
609 if (ivsize
> sizeof(iv
)) {
610 crp
->crp_etype
= EINVAL
;
611 dprintk("%s,%d: EINVAL\n", __FILE__
, __LINE__
);
615 if (crd
->crd_flags
& CRD_F_KEY_EXPLICIT
) {
619 dprintk("%s key:", __FUNCTION__
);
620 for (i
= 0; i
< (crd
->crd_klen
+ 7) / 8; i
++)
621 dprintk("%s0x%x", (i
% 8) ? " " : "\n ",
625 error
= crypto_blkcipher_setkey(
626 crypto_blkcipher_cast(sw
->sw_tfm
), crd
->crd_key
,
627 (crd
->crd_klen
+ 7) / 8);
629 dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
630 error
, sw
->sw_tfm
->crt_flags
);
631 crp
->crp_etype
= -error
;
635 memset(&desc
, 0, sizeof(desc
));
636 desc
.tfm
= crypto_blkcipher_cast(sw
->sw_tfm
);
638 if (crd
->crd_flags
& CRD_F_ENCRYPT
) { /* encrypt */
640 if (crd
->crd_flags
& CRD_F_IV_EXPLICIT
) {
643 get_random_bytes(ivp
, ivsize
);
646 * do we have to copy the IV back to the buffer ?
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
);
653 crypto_blkcipher_encrypt_iv(&desc
, sg
, sg
, sg_len
);
655 } else { /*decrypt */
657 if (crd
->crd_flags
& CRD_F_IV_EXPLICIT
) {
660 crypto_copydata(crp
->crp_flags
, crp
->crp_buf
,
661 crd
->crd_inject
, ivsize
, (caddr_t
)ivp
);
664 crypto_blkcipher_decrypt_iv(&desc
, sg
, sg
, sg_len
);
670 char result
[HASH_MAX_LEN
];
671 struct hash_desc desc
;
673 /* check we have room for the result */
674 if (crp
->crp_ilen
- crd
->crd_inject
< sw
->u
.hmac
.sw_mlen
) {
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
,
679 crp
->crp_etype
= EINVAL
;
683 memset(&desc
, 0, sizeof(desc
));
684 desc
.tfm
= crypto_hash_cast(sw
->sw_tfm
);
686 memset(result
, 0, sizeof(result
));
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
,
693 crypto_hash_setkey(desc
.tfm
, sw
->u
.hmac
.sw_key
,
695 crypto_hash_digest(&desc
, sg
, sg_len
, result
);
696 #endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
698 } else { /* SW_TYPE_HASH */
699 crypto_hash_digest(&desc
, sg
, sg_len
, result
);
702 crypto_copyback(crp
->crp_flags
, crp
->crp_buf
,
703 crd
->crd_inject
, sw
->u
.hmac
.sw_mlen
, result
);
709 void *obuf
= sw
->u
.sw_comp_buf
;
710 int ilen
= sg_len
, olen
= CRYPTO_MAX_DATA_LEN
;
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 ?
725 for (blk
= 0; blk
< sg_num
; blk
++) {
726 memcpy(obuf
, sg_virt(&sg
[blk
]),
728 obuf
+= sg
[blk
].length
;
732 ibuf
= sg_virt(&sg
[0]);
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",
740 if (swcr_fail_if_compression_grows
)
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
);
754 dprintk("%s,%d: ret = %d\n", __FILE__
, __LINE__
, ret
);
757 * on success copy result back,
758 * linux crpyto API returns -errno, we need to fix that
760 crp
->crp_etype
= ret
< 0 ? -ret
: ret
;
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
;
772 /* Unknown/unsupported algorithm */
773 dprintk("%s,%d: EINVAL\n", __FILE__
, __LINE__
);
774 crp
->crp_etype
= EINVAL
;
785 cryptosoft_init(void)
787 int i
, sw_type
, mode
;
790 dprintk("%s(%p)\n", __FUNCTION__
, cryptosoft_init
);
792 softc_device_init(&swcr_softc
, "cryptosoft", 0, swcr_methods
);
794 swcr_id
= crypto_get_driverid(softc_get_device(&swcr_softc
),
795 CRYPTOCAP_F_SOFTWARE
| CRYPTOCAP_F_SYNC
);
797 printk("Software crypto device cannot initialize!");
801 #define REGISTER(alg) \
802 crypto_register(swcr_id, alg, 0,0);
804 for (i
= CRYPTO_ALGORITHM_MIN
; i
<= CRYPTO_ALGORITHM_MAX
; ++i
)
807 algo
= crypto_details
[i
].alg_name
;
810 dprintk("%s:Algorithm %d not supported\n", __FUNCTION__
, i
);
814 mode
= crypto_details
[i
].mode
;
815 sw_type
= crypto_details
[i
].sw_type
;
820 if (crypto_has_cipher(algo
, 0, CRYPTO_ALG_ASYNC
))
826 dprintk("%s:CIPHER algorithm %d:'%s' not supported\n",
827 __FUNCTION__
, i
, algo
);
831 if (crypto_has_hash(algo
, 0, CRYPTO_ALG_ASYNC
))
837 dprintk("%s:HMAC algorithm %d:'%s' not supported\n",
838 __FUNCTION__
, i
, algo
);
842 if (crypto_has_hash(algo
, 0, CRYPTO_ALG_ASYNC
))
848 dprintk("%s:HASH algorithm %d:'%s' not supported\n",
849 __FUNCTION__
, i
, algo
);
853 if (crypto_has_comp(algo
, 0, CRYPTO_ALG_ASYNC
))
859 dprintk("%s:COMP algorithm %d:'%s' not supported\n",
860 __FUNCTION__
, i
, algo
);
863 case SW_TYPE_BLKCIPHER
:
864 if (crypto_has_blkcipher(algo
, 0, CRYPTO_ALG_ASYNC
))
870 dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n",
871 __FUNCTION__
, i
, algo
);
876 "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
877 __FUNCTION__
, sw_type
, i
, algo
);
886 cryptosoft_exit(void)
888 dprintk("%s()\n", __FUNCTION__
);
889 crypto_unregister_all(swcr_id
);
893 module_init(cryptosoft_init
);
894 module_exit(cryptosoft_exit
);
896 MODULE_LICENSE("Dual BSD/GPL");
897 MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
898 MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");