Root/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
55struct {
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
70struct 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
148struct 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 */
161static 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
191int32_t swcr_id = -1;
192module_param(swcr_id, int, 0444);
193MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
194
195int swcr_fail_if_compression_grows = 1;
196module_param(swcr_fail_if_compression_grows, int, 0644);
197MODULE_PARM_DESC(swcr_fail_if_compression_grows,
198                "Treat compression that results in more data as a failure");
199
200static struct swcr_data **swcr_sessions = NULL;
201static u_int32_t swcr_sesnum = 0;
202
203static int swcr_process(device_t, struct cryptop *, int);
204static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
205static int swcr_freesession(device_t, u_int64_t);
206
207static 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
215int swcr_debug = 0;
216module_param(swcr_debug, int, 0644);
217MODULE_PARM_DESC(swcr_debug, "Enable debug");
218
219/*
220 * Generate a new software session.
221 */
222static int
223swcr_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 */
406static int
407swcr_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 */
442static int
443swcr_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
779done:
780    crypto_done(crp);
781    return 0;
782}
783
784static int
785cryptosoft_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
885static void
886cryptosoft_exit(void)
887{
888    dprintk("%s()\n", __FUNCTION__);
889    crypto_unregister_all(swcr_id);
890    swcr_id = -1;
891}
892
893module_init(cryptosoft_init);
894module_exit(cryptosoft_exit);
895
896MODULE_LICENSE("Dual BSD/GPL");
897MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
898MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
899

Archive Download this file



interactive