split crypto driver front-end from software crypto engine
authorderaadt <deraadt@openbsd.org>
Sun, 19 Mar 2000 06:53:40 +0000 (06:53 +0000)
committerderaadt <deraadt@openbsd.org>
Sun, 19 Mar 2000 06:53:40 +0000 (06:53 +0000)
sys/conf/files
sys/crypto/crypto.c
sys/crypto/cryptosoft.c [new file with mode: 0644]

index 7b82dff..f9da912 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.153 2000/03/17 10:25:20 angelos Exp $
+#      $OpenBSD: files,v 1.154 2000/03/19 06:53:40 deraadt Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -514,6 +514,7 @@ file crypto/ecb_enc.c                       (inet & ipsec) | crypto
 file crypto/set_key.c                  (inet & ipsec) | crypto
 file crypto/ecb3_enc.c                 (inet & ipsec) | crypto
 file crypto/crypto.c                   (inet & ipsec) | crypto
+file crypto/cryptosoft.c               (inet & ipsec) | crypto
 file crypto/xform.c                    (inet & ipsec) | crypto
 file netatalk/aarp.c                   netatalk
 file netatalk/at_control.c             netatalk
index 14fa7f8..4ef43f1 100644 (file)
 struct cryptocap *crypto_drivers = NULL;
 int crypto_drivers_num = 0;
 
-struct swcr_data **swcr_sessions = NULL;
-u_int32_t swcr_sesnum = 0;
-int32_t swcr_id = -1;
-
 struct cryptop *cryptop_queue = NULL;
 struct cryptodesc *cryptodesc_queue = NULL;
 int crypto_queue_num = 0;
 int crypto_queue_max = CRYPTO_MAX_CACHED;
 
-u_int8_t hmac_ipad_buffer[64] = {
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
-
-u_int8_t hmac_opad_buffer[64] = {
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
-    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C };
-
 /*
  * Create a new session.
  */
@@ -437,704 +413,3 @@ crypto_getreq(int num)
 
     return crp;
 }
-
-/*
- * Apply a symmetric encryption/decryption algorithm.
- */
-int
-swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
-           int outtype)
-{
-    unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
-    unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
-    struct enc_xform *exf;
-    int i, k, j, blks;
-    struct mbuf *m;
-
-    exf = sw->sw_exf;
-    blks = exf->blocksize;
-
-    /* Check for non-padded data */
-    if (crd->crd_len % blks)
-      return EINVAL;
-
-    if (outtype == CRYPTO_BUF_CONTIG)
-    {
-       if (crd->crd_flags & CRD_F_ENCRYPT)
-       {
-           /* Inject IV */
-           if (crd->crd_flags & CRD_F_HALFIV)
-           {
-               /* "Cook" half-IV */
-               for (k = 0; k < blks / 2; k++)
-                 sw->sw_iv[(blks / 2) + k] = ~sw->sw_iv[k];
-
-               bcopy(sw->sw_iv, buf + crd->crd_inject, blks / 2);
-           }
-           else
-             bcopy(sw->sw_iv, buf + crd->crd_inject, blks);
-
-           for (i = crd->crd_skip;
-                i < crd->crd_skip + crd->crd_len;
-                i += blks)
-           {
-               /* XOR with the IV/previous block, as appropriate. */
-               if (i == crd->crd_skip)
-                 for (k = 0; k < blks; k++)
-                   buf[i + k] ^= sw->sw_iv[k];
-               else
-                 for (k = 0; k < blks; k++)
-                   buf[i + k] ^= buf[i + k - blks];
-
-               exf->encrypt(sw->sw_kschedule, buf + i);
-           }
-
-           /* Keep the last block */
-           bcopy(buf + crd->crd_len - blks, sw->sw_iv, blks);
-       }
-       else /* Decrypt */
-       {
-           /* Copy the IV off the buffer */
-           bcopy(buf + crd->crd_inject, sw->sw_iv, blks);
-
-           /* "Cook" half-IV */
-           if (crd->crd_flags & CRD_F_HALFIV)
-             for (k = 0; k < blks / 2; k++)
-               sw->sw_iv[(blks / 2) + k] = ~sw->sw_iv[k];
-
-           /*
-            * Start at the end, so we don't need to keep the encrypted
-            * block as the IV for the next block.
-            */
-           for (i = crd->crd_skip + crd->crd_len - blks;
-                i >= crd->crd_skip;
-                i -= blks)
-           {
-               exf->decrypt(sw->sw_kschedule, buf + i);
-
-               /* XOR with the IV/previous block, as appropriate */
-               if (i == crd->crd_skip)
-                 for (k = 0; k < blks; k++)
-                   buf[i + k] ^= sw->sw_iv[k];
-               else
-                 for (k = 0; k < blks; k++)
-                   buf[i + k] ^= buf[i + k - blks];
-           }
-       }
-
-       return 0; /* Done with contiguous buffer encryption/decryption */
-    }
-    else /* mbuf */
-    {
-       m = (struct mbuf *) buf;
-
-       /* Initialize the IV */
-       if (crd->crd_flags & CRD_F_ENCRYPT)
-       {
-           bcopy(sw->sw_iv, iv, blks);
-
-           /* "Cook" half-IV */
-           if (crd->crd_flags & CRD_F_HALFIV)
-             for (k = 0; k < blks / 2; k++)
-               iv[(blks / 2) + k] = ~iv[k];
-
-           /* Inject IV */
-           m_copyback(m, crd->crd_inject, blks, iv);
-       }
-       else
-       {
-           m_copydata(m, crd->crd_inject, blks, iv); /* Get IV off mbuf */
-
-           /* "Cook" half-IV */
-           if (crd->crd_flags & CRD_F_HALFIV)
-             for (k = 0; k < blks / 2; k++)
-               iv[(blks / 2) + k] = ~iv[k];
-       }
-
-       ivp = iv;
-
-       /* Find beginning of data */
-       m = m_getptr(m, crd->crd_skip, &k);
-       if (m == NULL)
-         return EINVAL;
-
-       i = crd->crd_len;
-
-       while (i > 0)
-       {
-           /*
-            * If there's insufficient data at the end of an mbuf, we have
-            * to do some copying.
-            */
-           if ((m->m_len < k + blks) && (m->m_len != k))
-           {
-               m_copydata(m, k, blks, blk);
-
-               /* Actual encryption/decryption */
-               if (crd->crd_flags & CRD_F_ENCRYPT)
-               {
-                   /* XOR with previous block */
-                   for (j = 0; j < blks; j++)
-                     blk[j] ^= ivp[j];
-
-                   exf->encrypt(sw->sw_kschedule, blk);
-
-                   /* Keep encrypted block for XOR'ing with next block */
-                   bcopy(blk, iv, blks);
-                   ivp = iv;
-               }
-               else /* decrypt */
-               {
-                   /* Keep encrypted block for XOR'ing with next block */
-                   if (ivp == iv)
-                     bcopy(blk, piv, blks);
-                   else
-                     bcopy(blk, iv, blks);
-
-                   exf->decrypt(sw->sw_kschedule, blk);
-
-                   /* XOR with previous block */
-                   for (j = 0; j < blks; j++)
-                     blk[j] ^= ivp[j];
-
-                   if (ivp == iv)
-                     bcopy(piv, iv, blks);
-                   else
-                     ivp = iv;
-               }
-
-               /* Copy back decrypted block */
-               m_copyback(m, k, blks, blk);
-
-               /* Advance pointer */
-               m = m_getptr(m, k + blks, &k);
-               if (m == NULL)
-                 return EINVAL;
-
-               i -= blks;
-
-               /* Could be done... */
-               if (i == 0)
-                 break;
-           }
-
-           /* Skip possibly empty mbufs */
-           if (k == m->m_len)
-           {
-               for (m = m->m_next; m && m->m_len == 0; m = m->m_next)
-                 ;
-
-               k = 0;
-           }
-
-           /* Sanity check */
-           if (m == NULL)
-             return EINVAL;
-
-           /*
-            * Warning: idat may point to garbage here, but we only use it
-            * in the while() loop, only if there are indeed enough data.
-            */
-           idat = mtod(m, unsigned char *) + k;
-
-           while ((m->m_len >= k + blks) && (i > 0))
-           {
-               if (crd->crd_flags & CRD_F_ENCRYPT)
-               {
-                   /* XOR with previous block/IV */
-                   for (j = 0; j < blks; j++)
-                     idat[j] ^= ivp[j];
-
-                   exf->encrypt(sw->sw_kschedule, idat);
-                   ivp = idat;
-               }
-               else /* decrypt */
-               {
-                   /*
-                    * Keep encrypted block to be used in next block's
-                    * processing.
-                    */
-                   if (ivp == iv)
-                     bcopy(idat, piv, blks);
-                   else
-                     bcopy(idat, iv, blks);
-
-                   exf->decrypt(sw->sw_kschedule, idat);
-
-                   /* XOR with previous block/IV */
-                   for (j = 0; j < blks; j++)
-                     idat[j] ^= ivp[j];
-
-                   if (ivp == iv)
-                     bcopy(piv, iv, blks);
-                   else
-                     ivp = iv;
-               }
-
-               idat += blks;
-               k += blks;
-               i -= blks;
-           }
-       }
-
-       /* Keep the last block */
-       if (crd->crd_flags & CRD_F_ENCRYPT)
-         bcopy(ivp, sw->sw_iv, blks);
-
-       return 0; /* Done with mbuf encryption/decryption */
-    }
-
-    /* Unreachable */
-    return EINVAL;
-}
-
-/*
- * Compute keyed-hash authenticator.
- */
-int
-swcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw,
-                caddr_t buf, int outtype)
-{
-    unsigned char aalg[AALG_MAX_RESULT_LEN];
-    struct auth_hash *axf;
-    union authctx ctx;
-    int err;
-
-    if (sw->sw_ictx == 0)
-      return EINVAL;
-
-    axf = sw->sw_axf;
-
-    bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
-
-    if (outtype == CRYPTO_BUF_CONTIG)
-    {
-       axf->Update(&ctx, buf + crd->crd_skip, crd->crd_len);
-       axf->Final(aalg, &ctx);
-    }
-    else
-    {
-       err = m_apply((struct mbuf *) buf, crd->crd_skip,
-                     crd->crd_len,
-                     (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
-                     (caddr_t) &ctx);
-       if (err)
-         return err;
-
-       axf->Final(aalg, &ctx);
-    }
-
-    /* HMAC processing */
-    switch (sw->sw_alg)
-    {
-       case CRYPTO_MD5_HMAC96:
-       case CRYPTO_SHA1_HMAC96:
-       case CRYPTO_RIPEMD160_HMAC96:
-           if (sw->sw_octx == NULL)
-             return EINVAL;
-
-           bcopy(sw->sw_octx, &ctx, axf->ctxsize);
-           axf->Update(&ctx, aalg, axf->hashsize);
-           axf->Final(aalg, &ctx);
-           break;
-    }
-
-    /* Inject the authentication data */
-    if (outtype == CRYPTO_BUF_CONTIG)
-      bcopy(aalg, buf + crd->crd_inject, axf->authsize);
-    else
-      m_copyback((struct mbuf *) buf, crd->crd_inject, axf->authsize, aalg);
-
-    return 0;
-}
-
-/*
- * Generate a new software session.
- */
-int
-swcr_newsession(u_int32_t *sid, struct cryptoini *cri)
-{
-    struct swcr_data **swd;
-    struct auth_hash *axf;
-    struct enc_xform *txf;
-    u_int32_t i;
-    int k;
-
-    if ((sid == NULL) || (cri == NULL))
-      return EINVAL;
-
-    if (swcr_sessions)
-      for (i = 1; i < swcr_sesnum; i++)
-       if (swcr_sessions[i] == NULL)
-         break;
-
-    if ((swcr_sessions == NULL) || (i == swcr_sesnum))
-    {
-       if (swcr_sessions == NULL)
-       {
-           i = 1; /* We leave swcr_sessions[0] empty */
-           swcr_sesnum = CRYPTO_SW_SESSIONS;
-       }
-       else
-         swcr_sesnum *= 2;
-
-       MALLOC(swd, struct swcr_data **,
-              swcr_sesnum * sizeof(struct swcr_data *), M_XDATA, M_DONTWAIT);
-       if (swd == NULL)
-       {
-           /* Reset session number */
-           if (swcr_sesnum == CRYPTO_SW_SESSIONS)
-             swcr_sesnum = 0;
-           else
-             swcr_sesnum /= 2;
-
-           return ENOBUFS;
-       }
-
-       bzero(swd, swcr_sesnum * sizeof(struct swcr_data *));
-
-       /* Copy existing sessions */
-       if (swcr_sessions)
-       {
-           bcopy(swcr_sessions, swd,
-                 (swcr_sesnum / 2) * sizeof(struct swcr_data *));
-           FREE(swcr_sessions, M_XDATA);
-       }
-
-       swcr_sessions = swd;
-    }
-
-    swd = &swcr_sessions[i];
-    *sid = i;
-
-    while (cri)
-    {
-       MALLOC(*swd, struct swcr_data *, sizeof(struct swcr_data), M_XDATA,
-              M_DONTWAIT);
-       if (*swd == NULL)
-       {
-           swcr_freesession(i);
-           return ENOBUFS;
-       }
-
-       bzero(*swd, sizeof(struct swcr_data));
-
-       switch (cri->cri_alg)
-       {
-           case CRYPTO_DES_CBC:
-               txf = &enc_xform_des;
-               goto enccommon;
-
-           case CRYPTO_3DES_CBC:
-               txf = &enc_xform_3des;
-               goto enccommon;
-
-           case CRYPTO_BLF_CBC:
-               txf = &enc_xform_blf;
-               goto enccommon;
-
-           case CRYPTO_CAST_CBC:
-               txf = &enc_xform_cast5;
-               goto enccommon;
-
-           case CRYPTO_SKIPJACK_CBC:
-               txf = &enc_xform_skipjack;
-
-       enccommon:
-               txf->setkey(&((*swd)->sw_kschedule), cri->cri_key,
-                           cri->cri_klen / 8);
-               MALLOC((*swd)->sw_iv, u_int8_t *, txf->blocksize, M_XDATA,
-                      M_DONTWAIT);
-               if ((*swd)->sw_iv == NULL)
-               {
-                   swcr_freesession(i);
-                   return ENOBUFS;
-               }
-
-               (*swd)->sw_exf = txf;
-
-               get_random_bytes((*swd)->sw_iv, txf->blocksize);
-               break;
-
-           case CRYPTO_MD5_HMAC96:
-               axf = &auth_hash_hmac_md5_96;
-               goto authcommon;
-
-           case CRYPTO_SHA1_HMAC96:
-               axf = &auth_hash_hmac_sha1_96;
-               goto authcommon;
-               
-           case CRYPTO_RIPEMD160_HMAC96:
-               axf = &auth_hash_hmac_ripemd_160_96;
-
-       authcommon:
-               MALLOC((*swd)->sw_ictx, u_int8_t *, axf->ctxsize, M_XDATA,
-                      M_DONTWAIT);
-               if ((*swd)->sw_ictx == NULL)
-               {
-                   swcr_freesession(i);
-                   return ENOBUFS;
-               }
-
-               MALLOC((*swd)->sw_octx, u_int8_t *, axf->ctxsize, M_XDATA,
-                      M_DONTWAIT);
-               if ((*swd)->sw_octx == NULL)
-               {
-                   swcr_freesession(i);
-                   return ENOBUFS;
-               }
-
-               for (k = 0; k < cri->cri_klen / 8; k++)
-                 cri->cri_key[k] ^= HMAC_IPAD_VAL;
-
-               axf->Init((*swd)->sw_ictx);
-               axf->Update((*swd)->sw_ictx, cri->cri_key,
-                           cri->cri_klen / 8);
-               axf->Update((*swd)->sw_ictx, hmac_ipad_buffer,
-                           HMAC_BLOCK_LEN - (cri->cri_klen / 8));
-
-               for (k = 0; k < cri->cri_klen / 8; k++)
-                 cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
-
-               axf->Init((*swd)->sw_octx);
-               axf->Update((*swd)->sw_octx, cri->cri_key,
-                           cri->cri_klen / 8);
-               axf->Update((*swd)->sw_octx, hmac_opad_buffer,
-                           HMAC_BLOCK_LEN - (cri->cri_klen / 8));
-
-               for (k = 0; k < cri->cri_klen / 8; k++)
-                 cri->cri_key[k] ^= HMAC_OPAD_VAL;
-
-               (*swd)->sw_axf = axf;
-               break;
-
-           case CRYPTO_MD5_KPDK:
-               axf = &auth_hash_key_md5;
-               goto auth2common;
-
-           case CRYPTO_SHA1_KPDK:
-               axf = &auth_hash_key_sha1;
-
-       auth2common:
-               MALLOC((*swd)->sw_ictx, u_int8_t *, axf->ctxsize, M_XDATA,
-                      M_DONTWAIT);
-               if ((*swd)->sw_ictx == NULL)
-               {
-                   swcr_freesession(i);
-                   return ENOBUFS;
-               }
-
-               axf->Init((*swd)->sw_ictx);
-               axf->Update((*swd)->sw_ictx, cri->cri_key,
-                           cri->cri_klen / 8);
-               axf->Final(NULL, (*swd)->sw_ictx);
-
-               (*swd)->sw_axf = axf;
-               break;
-
-           default:
-               swcr_freesession(i);
-               return EINVAL;
-       }
-
-       (*swd)->sw_alg = cri->cri_alg;
-       cri = cri->cri_next;
-       swd = &((*swd)->sw_next);
-    }
-
-    return 0;
-}
-
-/*
- * Free a session.
- */
-int
-swcr_freesession(u_int32_t sid)
-{
-    struct swcr_data *swd;
-    struct enc_xform *txf;
-    struct auth_hash *axf;
-
-    if ((sid > swcr_sesnum) || (swcr_sessions == NULL) ||
-       (swcr_sessions[sid] == NULL))
-      return EINVAL;
-
-    /* Silently accept and return */
-    if (sid == 0)
-      return 0;
-
-    while ((swd = swcr_sessions[sid]) != NULL)
-    {
-        swcr_sessions[sid] = swd->sw_next;
-
-       switch (swd->sw_alg)
-       {
-           case CRYPTO_DES_CBC:
-           case CRYPTO_3DES_CBC:
-           case CRYPTO_BLF_CBC:
-           case CRYPTO_CAST_CBC:
-           case CRYPTO_SKIPJACK_CBC:
-               txf = swd->sw_exf;
-
-               if (swd->sw_kschedule)
-                 txf->zerokey(&(swd->sw_kschedule));
-
-               if (swd->sw_iv)
-                 FREE(swd->sw_iv, M_XDATA);
-               break;
-
-           case CRYPTO_MD5_HMAC96:
-           case CRYPTO_SHA1_HMAC96:
-           case CRYPTO_RIPEMD160_HMAC96:
-           case CRYPTO_MD5_KPDK:
-           case CRYPTO_SHA1_KPDK:
-               axf = swd->sw_axf;
-
-               if (swd->sw_ictx)
-               {
-                   bzero(swd->sw_ictx, axf->ctxsize);
-                   FREE(swd->sw_ictx, M_XDATA);
-               }
-
-               if (swd->sw_octx)
-               {
-                   bzero(swd->sw_octx, axf->ctxsize);
-                   FREE(swd->sw_octx, M_XDATA);
-               }
-               break;
-       }
-
-       FREE(swd, M_XDATA);
-    }
-
-    return 0;
-}
-
-/*
- * Process a software request.
- */
-int
-swcr_process(struct cryptop *crp)
-{
-    struct cryptodesc *crd;
-    struct swcr_data *sw;
-    u_int32_t lid;
-    u_int64_t nid;
-    int type;
-
-    /* Some simple sanity checks */
-    if ((crp == NULL) || (crp->crp_callback == NULL))
-      return EINVAL;
-
-    if ((crp->crp_desc == NULL) || (crp->crp_buf == NULL))
-    {
-       crp->crp_etype = EINVAL;
-       goto done;
-    }
-
-    lid = crp->crp_sid & 0xffffffff;
-    if ((lid >= swcr_sesnum) || (lid == 0) || (swcr_sessions[lid] == NULL))
-    {
-       crp->crp_etype = ENOENT;
-       goto done;
-    }
-
-    if (crp->crp_flags & CRYPTO_F_IMBUF)
-      type = CRYPTO_BUF_MBUF;
-    else
-      type = CRYPTO_BUF_CONTIG;
-
-    /* Go through crypto descriptors, processing as we go */
-    for (crd = crp->crp_desc; crd; crd = crd->crd_next)
-    {
-       /*
-        * Find the crypto context.
-        *
-        * XXX Note that the logic here prevents us from having
-        * XXX the same algorithm multiple times in a session
-        * XXX (or rather, we can but it won't give us the right
-        * XXX results). To do that, we'd need some way of differentiating
-        * XXX between the various instances of an algorithm (so we can
-        * XXX locate the correct crypto context).
-        */
-       for (sw = swcr_sessions[lid];
-            sw && sw->sw_alg != crd->crd_alg;
-            sw = sw->sw_next)
-         ;
-
-       /* No such context ? */
-       if (sw == NULL)
-       {
-           crp->crp_etype = EINVAL;
-           goto done;
-       }
-
-       switch (sw->sw_alg)
-       {
-           case CRYPTO_DES_CBC:
-           case CRYPTO_3DES_CBC:
-           case CRYPTO_BLF_CBC:
-           case CRYPTO_CAST_CBC:
-           case CRYPTO_SKIPJACK_CBC:
-               if ((crp->crp_etype = swcr_encdec(crd, sw, crp->crp_buf,
-                                                 type)) != 0)
-                 goto done;
-               break;
-
-           case CRYPTO_MD5_HMAC96:
-           case CRYPTO_SHA1_HMAC96:
-           case CRYPTO_RIPEMD160_HMAC96:
-           case CRYPTO_MD5_KPDK:
-           case CRYPTO_SHA1_KPDK:
-               if ((crp->crp_etype = swcr_authcompute(crd, sw, crp->crp_buf,
-                                                      type)) != 0)
-                 goto done;
-               break;
-
-           default:  /* Unknown/unsupported algorithm */
-               crp->crp_etype = EINVAL;
-               goto done;
-       }
-    }
-
- done:
-    if (crp->crp_etype == ENOENT)
-    {
-       crypto_freesession(crp->crp_sid); /* Just in case */
-
-       /* Migrate session */
-       for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
-         crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
-       if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI)) == 0)
-         crp->crp_sid = nid;
-    }
-
-    return crp->crp_callback(crp);
-}
-
-/*
- * Initialize the driver, called from the kernel main().
- */
-void
-swcr_init(void)
-{
-    swcr_id = crypto_get_driverid();
-    if (swcr_id >= 0)
-    {
-       crypto_register(swcr_id, CRYPTO_DES_CBC, swcr_newsession,
-                        swcr_freesession, swcr_process);
-        crypto_register(swcr_id, CRYPTO_3DES_CBC, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_BLF_CBC, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_CAST_CBC, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_SKIPJACK_CBC, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_MD5_HMAC96, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_SHA1_HMAC96, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_RIPEMD160_HMAC96, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_MD5_KPDK, NULL, NULL, NULL);
-        crypto_register(swcr_id, CRYPTO_SHA1_KPDK, NULL, NULL, NULL);
-       return;
-    }
-
-    /* This should never happen */
-    panic("Software crypto device cannot initialize!");
-}
diff --git a/sys/crypto/cryptosoft.c b/sys/crypto/cryptosoft.c
new file mode 100644 (file)
index 0000000..d877c8e
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software. 
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/md5k.h>
+#include <dev/rndvar.h>
+#include <crypto/sha1.h>
+#include <crypto/rmd160.h>
+#include <crypto/cast.h>
+#include <crypto/skipjack.h>
+#include <crypto/blf.h>
+#include <crypto/crypto.h>
+#include <crypto/xform.h>
+
+u_int8_t hmac_ipad_buffer[64] = {
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
+
+u_int8_t hmac_opad_buffer[64] = {
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+    0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C };
+
+
+struct swcr_data **swcr_sessions = NULL;
+u_int32_t swcr_sesnum = 0;
+int32_t swcr_id = -1;
+
+/*
+ * Apply a symmetric encryption/decryption algorithm.
+ */
+int
+swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
+           int outtype)
+{
+    unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
+    unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
+    struct enc_xform *exf;
+    int i, k, j, blks;
+    struct mbuf *m;
+
+    exf = sw->sw_exf;
+    blks = exf->blocksize;
+
+    /* Check for non-padded data */
+    if (crd->crd_len % blks)
+      return EINVAL;
+
+    if (outtype == CRYPTO_BUF_CONTIG)
+    {
+       if (crd->crd_flags & CRD_F_ENCRYPT)
+       {
+           /* Inject IV */
+           if (crd->crd_flags & CRD_F_HALFIV)
+           {
+               /* "Cook" half-IV */
+               for (k = 0; k < blks / 2; k++)
+                 sw->sw_iv[(blks / 2) + k] = ~sw->sw_iv[k];
+
+               bcopy(sw->sw_iv, buf + crd->crd_inject, blks / 2);
+           }
+           else
+             bcopy(sw->sw_iv, buf + crd->crd_inject, blks);
+
+           for (i = crd->crd_skip;
+                i < crd->crd_skip + crd->crd_len;
+                i += blks)
+           {
+               /* XOR with the IV/previous block, as appropriate. */
+               if (i == crd->crd_skip)
+                 for (k = 0; k < blks; k++)
+                   buf[i + k] ^= sw->sw_iv[k];
+               else
+                 for (k = 0; k < blks; k++)
+                   buf[i + k] ^= buf[i + k - blks];
+
+               exf->encrypt(sw->sw_kschedule, buf + i);
+           }
+
+           /* Keep the last block */
+           bcopy(buf + crd->crd_len - blks, sw->sw_iv, blks);
+       }
+       else /* Decrypt */
+       {
+           /* Copy the IV off the buffer */
+           bcopy(buf + crd->crd_inject, sw->sw_iv, blks);
+
+           /* "Cook" half-IV */
+           if (crd->crd_flags & CRD_F_HALFIV)
+             for (k = 0; k < blks / 2; k++)
+               sw->sw_iv[(blks / 2) + k] = ~sw->sw_iv[k];
+
+           /*
+            * Start at the end, so we don't need to keep the encrypted
+            * block as the IV for the next block.
+            */
+           for (i = crd->crd_skip + crd->crd_len - blks;
+                i >= crd->crd_skip;
+                i -= blks)
+           {
+               exf->decrypt(sw->sw_kschedule, buf + i);
+
+               /* XOR with the IV/previous block, as appropriate */
+               if (i == crd->crd_skip)
+                 for (k = 0; k < blks; k++)
+                   buf[i + k] ^= sw->sw_iv[k];
+               else
+                 for (k = 0; k < blks; k++)
+                   buf[i + k] ^= buf[i + k - blks];
+           }
+       }
+
+       return 0; /* Done with contiguous buffer encryption/decryption */
+    }
+    else /* mbuf */
+    {
+       m = (struct mbuf *) buf;
+
+       /* Initialize the IV */
+       if (crd->crd_flags & CRD_F_ENCRYPT)
+       {
+           bcopy(sw->sw_iv, iv, blks);
+
+           /* "Cook" half-IV */
+           if (crd->crd_flags & CRD_F_HALFIV)
+             for (k = 0; k < blks / 2; k++)
+               iv[(blks / 2) + k] = ~iv[k];
+
+           /* Inject IV */
+           m_copyback(m, crd->crd_inject, blks, iv);
+       }
+       else
+       {
+           m_copydata(m, crd->crd_inject, blks, iv); /* Get IV off mbuf */
+
+           /* "Cook" half-IV */
+           if (crd->crd_flags & CRD_F_HALFIV)
+             for (k = 0; k < blks / 2; k++)
+               iv[(blks / 2) + k] = ~iv[k];
+       }
+
+       ivp = iv;
+
+       /* Find beginning of data */
+       m = m_getptr(m, crd->crd_skip, &k);
+       if (m == NULL)
+         return EINVAL;
+
+       i = crd->crd_len;
+
+       while (i > 0)
+       {
+           /*
+            * If there's insufficient data at the end of an mbuf, we have
+            * to do some copying.
+            */
+           if ((m->m_len < k + blks) && (m->m_len != k))
+           {
+               m_copydata(m, k, blks, blk);
+
+               /* Actual encryption/decryption */
+               if (crd->crd_flags & CRD_F_ENCRYPT)
+               {
+                   /* XOR with previous block */
+                   for (j = 0; j < blks; j++)
+                     blk[j] ^= ivp[j];
+
+                   exf->encrypt(sw->sw_kschedule, blk);
+
+                   /* Keep encrypted block for XOR'ing with next block */
+                   bcopy(blk, iv, blks);
+                   ivp = iv;
+               }
+               else /* decrypt */
+               {
+                   /* Keep encrypted block for XOR'ing with next block */
+                   if (ivp == iv)
+                     bcopy(blk, piv, blks);
+                   else
+                     bcopy(blk, iv, blks);
+
+                   exf->decrypt(sw->sw_kschedule, blk);
+
+                   /* XOR with previous block */
+                   for (j = 0; j < blks; j++)
+                     blk[j] ^= ivp[j];
+
+                   if (ivp == iv)
+                     bcopy(piv, iv, blks);
+                   else
+                     ivp = iv;
+               }
+
+               /* Copy back decrypted block */
+               m_copyback(m, k, blks, blk);
+
+               /* Advance pointer */
+               m = m_getptr(m, k + blks, &k);
+               if (m == NULL)
+                 return EINVAL;
+
+               i -= blks;
+
+               /* Could be done... */
+               if (i == 0)
+                 break;
+           }
+
+           /* Skip possibly empty mbufs */
+           if (k == m->m_len)
+           {
+               for (m = m->m_next; m && m->m_len == 0; m = m->m_next)
+                 ;
+
+               k = 0;
+           }
+
+           /* Sanity check */
+           if (m == NULL)
+             return EINVAL;
+
+           /*
+            * Warning: idat may point to garbage here, but we only use it
+            * in the while() loop, only if there are indeed enough data.
+            */
+           idat = mtod(m, unsigned char *) + k;
+
+           while ((m->m_len >= k + blks) && (i > 0))
+           {
+               if (crd->crd_flags & CRD_F_ENCRYPT)
+               {
+                   /* XOR with previous block/IV */
+                   for (j = 0; j < blks; j++)
+                     idat[j] ^= ivp[j];
+
+                   exf->encrypt(sw->sw_kschedule, idat);
+                   ivp = idat;
+               }
+               else /* decrypt */
+               {
+                   /*
+                    * Keep encrypted block to be used in next block's
+                    * processing.
+                    */
+                   if (ivp == iv)
+                     bcopy(idat, piv, blks);
+                   else
+                     bcopy(idat, iv, blks);
+
+                   exf->decrypt(sw->sw_kschedule, idat);
+
+                   /* XOR with previous block/IV */
+                   for (j = 0; j < blks; j++)
+                     idat[j] ^= ivp[j];
+
+                   if (ivp == iv)
+                     bcopy(piv, iv, blks);
+                   else
+                     ivp = iv;
+               }
+
+               idat += blks;
+               k += blks;
+               i -= blks;
+           }
+       }
+
+       /* Keep the last block */
+       if (crd->crd_flags & CRD_F_ENCRYPT)
+         bcopy(ivp, sw->sw_iv, blks);
+
+       return 0; /* Done with mbuf encryption/decryption */
+    }
+
+    /* Unreachable */
+    return EINVAL;
+}
+
+/*
+ * Compute keyed-hash authenticator.
+ */
+int
+swcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw,
+                caddr_t buf, int outtype)
+{
+    unsigned char aalg[AALG_MAX_RESULT_LEN];
+    struct auth_hash *axf;
+    union authctx ctx;
+    int err;
+
+    if (sw->sw_ictx == 0)
+      return EINVAL;
+
+    axf = sw->sw_axf;
+
+    bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
+
+    if (outtype == CRYPTO_BUF_CONTIG)
+    {
+       axf->Update(&ctx, buf + crd->crd_skip, crd->crd_len);
+       axf->Final(aalg, &ctx);
+    }
+    else
+    {
+       err = m_apply((struct mbuf *) buf, crd->crd_skip,
+                     crd->crd_len,
+                     (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
+                     (caddr_t) &ctx);
+       if (err)
+         return err;
+
+       axf->Final(aalg, &ctx);
+    }
+
+    /* HMAC processing */
+    switch (sw->sw_alg)
+    {
+       case CRYPTO_MD5_HMAC96:
+       case CRYPTO_SHA1_HMAC96:
+       case CRYPTO_RIPEMD160_HMAC96:
+           if (sw->sw_octx == NULL)
+             return EINVAL;
+
+           bcopy(sw->sw_octx, &ctx, axf->ctxsize);
+           axf->Update(&ctx, aalg, axf->hashsize);
+           axf->Final(aalg, &ctx);
+           break;
+    }
+
+    /* Inject the authentication data */
+    if (outtype == CRYPTO_BUF_CONTIG)
+      bcopy(aalg, buf + crd->crd_inject, axf->authsize);
+    else
+      m_copyback((struct mbuf *) buf, crd->crd_inject, axf->authsize, aalg);
+
+    return 0;
+}
+
+/*
+ * Generate a new software session.
+ */
+int
+swcr_newsession(u_int32_t *sid, struct cryptoini *cri)
+{
+    struct swcr_data **swd;
+    struct auth_hash *axf;
+    struct enc_xform *txf;
+    u_int32_t i;
+    int k;
+
+    if ((sid == NULL) || (cri == NULL))
+      return EINVAL;
+
+    if (swcr_sessions)
+      for (i = 1; i < swcr_sesnum; i++)
+       if (swcr_sessions[i] == NULL)
+         break;
+
+    if ((swcr_sessions == NULL) || (i == swcr_sesnum))
+    {
+       if (swcr_sessions == NULL)
+       {
+           i = 1; /* We leave swcr_sessions[0] empty */
+           swcr_sesnum = CRYPTO_SW_SESSIONS;
+       }
+       else
+         swcr_sesnum *= 2;
+
+       MALLOC(swd, struct swcr_data **,
+              swcr_sesnum * sizeof(struct swcr_data *), M_XDATA, M_DONTWAIT);
+       if (swd == NULL)
+       {
+           /* Reset session number */
+           if (swcr_sesnum == CRYPTO_SW_SESSIONS)
+             swcr_sesnum = 0;
+           else
+             swcr_sesnum /= 2;
+
+           return ENOBUFS;
+       }
+
+       bzero(swd, swcr_sesnum * sizeof(struct swcr_data *));
+
+       /* Copy existing sessions */
+       if (swcr_sessions)
+       {
+           bcopy(swcr_sessions, swd,
+                 (swcr_sesnum / 2) * sizeof(struct swcr_data *));
+           FREE(swcr_sessions, M_XDATA);
+       }
+
+       swcr_sessions = swd;
+    }
+
+    swd = &swcr_sessions[i];
+    *sid = i;
+
+    while (cri)
+    {
+       MALLOC(*swd, struct swcr_data *, sizeof(struct swcr_data), M_XDATA,
+              M_DONTWAIT);
+       if (*swd == NULL)
+       {
+           swcr_freesession(i);
+           return ENOBUFS;
+       }
+
+       bzero(*swd, sizeof(struct swcr_data));
+
+       switch (cri->cri_alg)
+       {
+           case CRYPTO_DES_CBC:
+               txf = &enc_xform_des;
+               goto enccommon;
+
+           case CRYPTO_3DES_CBC:
+               txf = &enc_xform_3des;
+               goto enccommon;
+
+           case CRYPTO_BLF_CBC:
+               txf = &enc_xform_blf;
+               goto enccommon;
+
+           case CRYPTO_CAST_CBC:
+               txf = &enc_xform_cast5;
+               goto enccommon;
+
+           case CRYPTO_SKIPJACK_CBC:
+               txf = &enc_xform_skipjack;
+
+       enccommon:
+               txf->setkey(&((*swd)->sw_kschedule), cri->cri_key,
+                           cri->cri_klen / 8);
+               MALLOC((*swd)->sw_iv, u_int8_t *, txf->blocksize, M_XDATA,
+                      M_DONTWAIT);
+               if ((*swd)->sw_iv == NULL)
+               {
+                   swcr_freesession(i);
+                   return ENOBUFS;
+               }
+
+               (*swd)->sw_exf = txf;
+
+               get_random_bytes((*swd)->sw_iv, txf->blocksize);
+               break;
+
+           case CRYPTO_MD5_HMAC96:
+               axf = &auth_hash_hmac_md5_96;
+               goto authcommon;
+
+           case CRYPTO_SHA1_HMAC96:
+               axf = &auth_hash_hmac_sha1_96;
+               goto authcommon;
+               
+           case CRYPTO_RIPEMD160_HMAC96:
+               axf = &auth_hash_hmac_ripemd_160_96;
+
+       authcommon:
+               MALLOC((*swd)->sw_ictx, u_int8_t *, axf->ctxsize, M_XDATA,
+                      M_DONTWAIT);
+               if ((*swd)->sw_ictx == NULL)
+               {
+                   swcr_freesession(i);
+                   return ENOBUFS;
+               }
+
+               MALLOC((*swd)->sw_octx, u_int8_t *, axf->ctxsize, M_XDATA,
+                      M_DONTWAIT);
+               if ((*swd)->sw_octx == NULL)
+               {
+                   swcr_freesession(i);
+                   return ENOBUFS;
+               }
+
+               for (k = 0; k < cri->cri_klen / 8; k++)
+                 cri->cri_key[k] ^= HMAC_IPAD_VAL;
+
+               axf->Init((*swd)->sw_ictx);
+               axf->Update((*swd)->sw_ictx, cri->cri_key,
+                           cri->cri_klen / 8);
+               axf->Update((*swd)->sw_ictx, hmac_ipad_buffer,
+                           HMAC_BLOCK_LEN - (cri->cri_klen / 8));
+
+               for (k = 0; k < cri->cri_klen / 8; k++)
+                 cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
+
+               axf->Init((*swd)->sw_octx);
+               axf->Update((*swd)->sw_octx, cri->cri_key,
+                           cri->cri_klen / 8);
+               axf->Update((*swd)->sw_octx, hmac_opad_buffer,
+                           HMAC_BLOCK_LEN - (cri->cri_klen / 8));
+
+               for (k = 0; k < cri->cri_klen / 8; k++)
+                 cri->cri_key[k] ^= HMAC_OPAD_VAL;
+
+               (*swd)->sw_axf = axf;
+               break;
+
+           case CRYPTO_MD5_KPDK:
+               axf = &auth_hash_key_md5;
+               goto auth2common;
+
+           case CRYPTO_SHA1_KPDK:
+               axf = &auth_hash_key_sha1;
+
+       auth2common:
+               MALLOC((*swd)->sw_ictx, u_int8_t *, axf->ctxsize, M_XDATA,
+                      M_DONTWAIT);
+               if ((*swd)->sw_ictx == NULL)
+               {
+                   swcr_freesession(i);
+                   return ENOBUFS;
+               }
+
+               axf->Init((*swd)->sw_ictx);
+               axf->Update((*swd)->sw_ictx, cri->cri_key,
+                           cri->cri_klen / 8);
+               axf->Final(NULL, (*swd)->sw_ictx);
+
+               (*swd)->sw_axf = axf;
+               break;
+
+           default:
+               swcr_freesession(i);
+               return EINVAL;
+       }
+
+       (*swd)->sw_alg = cri->cri_alg;
+       cri = cri->cri_next;
+       swd = &((*swd)->sw_next);
+    }
+
+    return 0;
+}
+
+/*
+ * Free a session.
+ */
+int
+swcr_freesession(u_int32_t sid)
+{
+    struct swcr_data *swd;
+    struct enc_xform *txf;
+    struct auth_hash *axf;
+
+    if ((sid > swcr_sesnum) || (swcr_sessions == NULL) ||
+       (swcr_sessions[sid] == NULL))
+      return EINVAL;
+
+    /* Silently accept and return */
+    if (sid == 0)
+      return 0;
+
+    while ((swd = swcr_sessions[sid]) != NULL)
+    {
+        swcr_sessions[sid] = swd->sw_next;
+
+       switch (swd->sw_alg)
+       {
+           case CRYPTO_DES_CBC:
+           case CRYPTO_3DES_CBC:
+           case CRYPTO_BLF_CBC:
+           case CRYPTO_CAST_CBC:
+           case CRYPTO_SKIPJACK_CBC:
+               txf = swd->sw_exf;
+
+               if (swd->sw_kschedule)
+                 txf->zerokey(&(swd->sw_kschedule));
+
+               if (swd->sw_iv)
+                 FREE(swd->sw_iv, M_XDATA);
+               break;
+
+           case CRYPTO_MD5_HMAC96:
+           case CRYPTO_SHA1_HMAC96:
+           case CRYPTO_RIPEMD160_HMAC96:
+           case CRYPTO_MD5_KPDK:
+           case CRYPTO_SHA1_KPDK:
+               axf = swd->sw_axf;
+
+               if (swd->sw_ictx)
+               {
+                   bzero(swd->sw_ictx, axf->ctxsize);
+                   FREE(swd->sw_ictx, M_XDATA);
+               }
+
+               if (swd->sw_octx)
+               {
+                   bzero(swd->sw_octx, axf->ctxsize);
+                   FREE(swd->sw_octx, M_XDATA);
+               }
+               break;
+       }
+
+       FREE(swd, M_XDATA);
+    }
+
+    return 0;
+}
+
+/*
+ * Process a software request.
+ */
+int
+swcr_process(struct cryptop *crp)
+{
+    struct cryptodesc *crd;
+    struct swcr_data *sw;
+    u_int32_t lid;
+    u_int64_t nid;
+    int type;
+
+    /* Some simple sanity checks */
+    if ((crp == NULL) || (crp->crp_callback == NULL))
+      return EINVAL;
+
+    if ((crp->crp_desc == NULL) || (crp->crp_buf == NULL))
+    {
+       crp->crp_etype = EINVAL;
+       goto done;
+    }
+
+    lid = crp->crp_sid & 0xffffffff;
+    if ((lid >= swcr_sesnum) || (lid == 0) || (swcr_sessions[lid] == NULL))
+    {
+       crp->crp_etype = ENOENT;
+       goto done;
+    }
+
+    if (crp->crp_flags & CRYPTO_F_IMBUF)
+      type = CRYPTO_BUF_MBUF;
+    else
+      type = CRYPTO_BUF_CONTIG;
+
+    /* Go through crypto descriptors, processing as we go */
+    for (crd = crp->crp_desc; crd; crd = crd->crd_next)
+    {
+       /*
+        * Find the crypto context.
+        *
+        * XXX Note that the logic here prevents us from having
+        * XXX the same algorithm multiple times in a session
+        * XXX (or rather, we can but it won't give us the right
+        * XXX results). To do that, we'd need some way of differentiating
+        * XXX between the various instances of an algorithm (so we can
+        * XXX locate the correct crypto context).
+        */
+       for (sw = swcr_sessions[lid];
+            sw && sw->sw_alg != crd->crd_alg;
+            sw = sw->sw_next)
+         ;
+
+       /* No such context ? */
+       if (sw == NULL)
+       {
+           crp->crp_etype = EINVAL;
+           goto done;
+       }
+
+       switch (sw->sw_alg)
+       {
+           case CRYPTO_DES_CBC:
+           case CRYPTO_3DES_CBC:
+           case CRYPTO_BLF_CBC:
+           case CRYPTO_CAST_CBC:
+           case CRYPTO_SKIPJACK_CBC:
+               if ((crp->crp_etype = swcr_encdec(crd, sw, crp->crp_buf,
+                                                 type)) != 0)
+                 goto done;
+               break;
+
+           case CRYPTO_MD5_HMAC96:
+           case CRYPTO_SHA1_HMAC96:
+           case CRYPTO_RIPEMD160_HMAC96:
+           case CRYPTO_MD5_KPDK:
+           case CRYPTO_SHA1_KPDK:
+               if ((crp->crp_etype = swcr_authcompute(crd, sw, crp->crp_buf,
+                                                      type)) != 0)
+                 goto done;
+               break;
+
+           default:  /* Unknown/unsupported algorithm */
+               crp->crp_etype = EINVAL;
+               goto done;
+       }
+    }
+
+ done:
+    if (crp->crp_etype == ENOENT)
+    {
+       crypto_freesession(crp->crp_sid); /* Just in case */
+
+       /* Migrate session */
+       for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
+         crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
+       if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI)) == 0)
+         crp->crp_sid = nid;
+    }
+
+    return crp->crp_callback(crp);
+}
+
+/*
+ * Initialize the driver, called from the kernel main().
+ */
+void
+swcr_init(void)
+{
+    swcr_id = crypto_get_driverid();
+    if (swcr_id >= 0)
+    {
+       crypto_register(swcr_id, CRYPTO_DES_CBC, swcr_newsession,
+                        swcr_freesession, swcr_process);
+        crypto_register(swcr_id, CRYPTO_3DES_CBC, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_BLF_CBC, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_CAST_CBC, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_SKIPJACK_CBC, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_MD5_HMAC96, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_SHA1_HMAC96, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_RIPEMD160_HMAC96, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_MD5_KPDK, NULL, NULL, NULL);
+        crypto_register(swcr_id, CRYPTO_SHA1_KPDK, NULL, NULL, NULL);
+       return;
+    }
+
+    /* This should never happen */
+    panic("Software crypto device cannot initialize!");
+}