diff options
Diffstat (limited to 'sys/crypto')
-rw-r--r-- | sys/crypto/crypto.c | 1140 | ||||
-rw-r--r-- | sys/crypto/crypto.h | 200 | ||||
-rw-r--r-- | sys/crypto/xform.c | 354 | ||||
-rw-r--r-- | sys/crypto/xform.h | 73 |
4 files changed, 1767 insertions, 0 deletions
diff --git a/sys/crypto/crypto.c b/sys/crypto/crypto.c new file mode 100644 index 00000000000..14fa7f885ca --- /dev/null +++ b/sys/crypto/crypto.c @@ -0,0 +1,1140 @@ +/* + * 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> + +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. + */ +int +crypto_newsession(u_int64_t *sid, struct cryptoini *cri) +{ + struct cryptoini *cr; + u_int32_t hid, lid; + int err; + + if (crypto_drivers == NULL) + return EINVAL; + + /* + * The algorithm we use here is pretty stupid; just use the + * first driver that supports all the algorithms we need. + * + * XXX We need more smarts here (in real life too, but that's + * XXX another story altogether). + */ + + for (hid = 0; hid < crypto_drivers_num; hid++) + { + /* + * If it's not initialized or has remaining sessions referencing + * it, skip. + */ + if ((crypto_drivers[hid].cc_newsession == NULL) || + (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP)) + continue; + + /* See if all the algorithms are supported */ + for (cr = cri; cr; cr = cr->cri_next) + if (crypto_drivers[hid].cc_alg[cr->cri_alg] == 0) + break; + + /* Ok, all algorithms are supported */ + if (cr == NULL) + break; + } + + /* + * Can't do everything in one session. + * + * XXX Fix this. We need to inject a "virtual" session layer right + * XXX about here. + */ + + if (hid == crypto_drivers_num) + return EINVAL; + + /* Call the driver initialization routine */ + lid = hid; /* Pass the driver ID */ + err = crypto_drivers[hid].cc_newsession(&lid, cri); + if (err == 0) + { + (*sid) = hid; + (*sid) <<= 31; + (*sid) |= (lid & 0xffffffff); + crypto_drivers[hid].cc_sessions++; + } + + return err; +} + +/* + * Delete an existing session (or a reserved session on an unregistered + * driver). + */ +int +crypto_freesession(u_int64_t sid) +{ + u_int32_t hid, lid; + int err = 0; + + if (crypto_drivers == NULL) + return EINVAL; + + /* Determine two IDs */ + hid = (sid >> 31) & 0xffffffff; + lid = sid & 0xffffffff; + + if (hid >= crypto_drivers_num) + return ENOENT; + + if (crypto_drivers[hid].cc_sessions) + crypto_drivers[hid].cc_sessions--; + + /* Call the driver cleanup routine, if available */ + if (crypto_drivers[hid].cc_freesession) + err = crypto_drivers[hid].cc_freesession(lid); + + /* + * If this was the last session of a driver marked as invalid, make + * the entry available for reuse. + */ + if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) && + (crypto_drivers[hid].cc_sessions == 0)) + bzero(&crypto_drivers[hid], sizeof(struct cryptocap)); + + return err; +} + +/* + * Find an empty slot. + */ +int32_t +crypto_get_driverid(void) +{ + struct cryptocap *newdrv; + int i; + + if (crypto_drivers_num == 0) + { + crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; + MALLOC(crypto_drivers, struct cryptocap *, + crypto_drivers_num * sizeof(struct cryptocap), M_XDATA, + M_DONTWAIT); + if (crypto_drivers == NULL) + { + crypto_drivers_num = 0; + return -1; + } + + bzero(crypto_drivers, crypto_drivers_num * sizeof(struct cryptocap)); + } + + for (i = 0; i < crypto_drivers_num; i++) + if ((crypto_drivers[i].cc_process == NULL) && + !(crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) && + (crypto_drivers[i].cc_sessions == 0)) + return i; + + /* Out of entries, allocate some more */ + if (i == crypto_drivers_num) + { + /* Be careful about wrap-around */ + if (2 * crypto_drivers_num <= crypto_drivers_num) + return -1; + + MALLOC(newdrv, struct cryptocap *, + 2 * crypto_drivers_num * sizeof(struct cryptocap), + M_XDATA, M_DONTWAIT); + if (newdrv == NULL) + return -1; + + bcopy(crypto_drivers, newdrv, + crypto_drivers_num * sizeof(struct cryptocap)); + bzero(&newdrv[crypto_drivers_num], + crypto_drivers_num * sizeof(struct cryptocap)); + crypto_drivers_num *= 2; + return i; + } + + /* Shouldn't really get here... */ + return -1; +} + +/* + * Register a crypto driver. It should be called once for each algorithm + * supported by the driver. + */ +int +crypto_register(u_int32_t driverid, int alg, void *newses, void *freeses, + void *process) +{ + if ((driverid >= crypto_drivers_num) || (alg <= 0) || + (alg > CRYPTO_ALGORITHM_MAX) || (crypto_drivers == NULL)) + return EINVAL; + + /* + * XXX Do some performance testing to determine placing. + * XXX We probably need an auxiliary data structure that describes + * XXX relative performances. + */ + + crypto_drivers[driverid].cc_alg[alg] = 1; + + if (crypto_drivers[driverid].cc_process == NULL) + { + crypto_drivers[driverid].cc_newsession = + (int (*) (u_int32_t *, struct cryptoini *)) newses; + crypto_drivers[driverid].cc_process = + (int (*) (struct cryptop *)) process; + crypto_drivers[driverid].cc_freesession = + (int (*) (u_int32_t)) freeses; + } + + return 0; +} + +/* + * Unregister a crypto driver. If there are pending sessions using it, + * leave enough information around so that subsequent calls using those + * sessions will correctly detect the driver being unregistered and reroute + * the request. + */ +int +crypto_unregister(u_int32_t driverid, int alg) +{ + u_int32_t ses; + int i; + + /* Sanity checks */ + if ((driverid >= crypto_drivers_num) || (alg <= 0) || + (alg > CRYPTO_ALGORITHM_MAX) || (crypto_drivers == NULL) || + (crypto_drivers[driverid].cc_alg[alg] == 0)) + return EINVAL; + + crypto_drivers[driverid].cc_alg[alg] = 0; + + /* Was this the last algorithm ? */ + for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) + if (crypto_drivers[driverid].cc_alg[i] != 0) + break; + + if (i == CRYPTO_ALGORITHM_MAX + 1) + { + ses = crypto_drivers[driverid].cc_sessions; + bzero(&crypto_drivers[driverid], sizeof(struct cryptocap)); + + if (ses != 0) + { + /* If there are pending sessions, just mark as invalid */ + crypto_drivers[driverid].cc_flags |= CRYPTOCAP_F_CLEANUP; + crypto_drivers[driverid].cc_sessions = ses; + } + } + + return 0; +} + +/* + * Dispatch a crypto request to the appropriate crypto devices. + */ +int +crypto_dispatch(struct cryptop *crp) +{ + struct cryptodesc *crd; + u_int64_t nid; + u_int32_t hid; + + /* Sanity checks */ + if ((crp == NULL) || (crp->crp_callback == NULL)) + return EINVAL; + + if ((crp->crp_desc == NULL) || (crypto_drivers == NULL)) + { + crp->crp_etype = EINVAL; + return crp->crp_callback(crp); + } + + hid = (crp->crp_sid >> 31) & 0xffffffff; + + if (hid >= crypto_drivers_num) + { + /* 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; + + crp->crp_etype = EAGAIN; + return crp->crp_callback(crp); + } + + if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) + crypto_freesession(crp->crp_sid); + + if (crypto_drivers[hid].cc_process == NULL) + { + /* 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; + + crp->crp_etype = EAGAIN; + return crp->crp_callback(crp); + } + + return crypto_drivers[hid].cc_process(crp); +} + +/* + * Release a set of crypto descriptors. + */ +void +crypto_freereq(struct cryptop *crp) +{ + struct cryptodesc *crd; + + if (crp == NULL) + return; + + while ((crd = crp->crp_desc) != NULL) + { + crp->crp_desc = crd->crd_next; + + if (crypto_queue_num + 1 > crypto_queue_max) + FREE(crd, M_XDATA); + else + { + crd->crd_next = cryptodesc_queue; + cryptodesc_queue = crd; + crypto_queue_num++; + } + } + + if (crypto_queue_num + 1 > crypto_queue_max) + FREE(crp, M_XDATA); + else + { + crp->crp_next = cryptop_queue; + cryptop_queue = crp; + crypto_queue_num++; + } +} + +/* + * Acquire a set of crypto descriptors. + */ +struct cryptop * +crypto_getreq(int num) +{ + struct cryptodesc *crd; + struct cryptop *crp; + + if (cryptop_queue == NULL) + { + MALLOC(crp, struct cryptop *, sizeof(struct cryptop), M_XDATA, + M_DONTWAIT); + if (crp == NULL) + return NULL; + } + else + { + crp = cryptop_queue; + cryptop_queue = crp->crp_next; + crypto_queue_num--; + } + + bzero(crp, sizeof(struct cryptop)); + + while (num--) + { + if (cryptodesc_queue == NULL) + { + MALLOC(crd, struct cryptodesc *, sizeof(struct cryptodesc), + M_XDATA, M_DONTWAIT); + if (crd == NULL) + { + crypto_freereq(crp); + return NULL; + } + } + else + { + crd = cryptodesc_queue; + cryptodesc_queue = crd->crd_next; + crypto_queue_num--; + } + + bzero(crd, sizeof(struct cryptodesc)); + crd->crd_next = crp->crp_desc; + crp->crp_desc = crd; + } + + 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/crypto.h b/sys/crypto/crypto.h new file mode 100644 index 00000000000..ba1ad389c23 --- /dev/null +++ b/sys/crypto/crypto.h @@ -0,0 +1,200 @@ +/* + * 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. + */ + +#ifndef _CRYPTO_CRYPTO_H_ +#define _CRYPTO_CRYPTO_H_ + +/* Some initial values */ +#define CRYPTO_DRIVERS_INITIAL 4 +#define CRYPTO_SW_SESSIONS 32 + +#ifndef CRYPTO_MAX_CACHED +#define CRYPTO_MAX_CACHED 128 +#endif + +/* HMAC values */ +#define HMAC_BLOCK_LEN 64 +#define HMAC_IPAD_VAL 0x36 +#define HMAC_OPAD_VAL 0x5C + +/* Encryption algorithm block sizes */ +#define DES_BLOCK_LEN 8 +#define DES3_BLOCK_LEN 8 +#define BLOWFISH_BLOCK_LEN 8 +#define SKIPJACK_BLOCK_LEN 8 +#define CAST128_BLOCK_LEN 8 +#define EALG_MAX_BLOCK_LEN 8 /* Keep this updated */ + +/* Maximum hash algorithm result length */ +#define AALG_MAX_RESULT_LEN 20 /* Keep this updated */ + +#define CRYPTO_DES_CBC 1 +#define CRYPTO_3DES_CBC 2 +#define CRYPTO_BLF_CBC 3 +#define CRYPTO_CAST_CBC 4 +#define CRYPTO_SKIPJACK_CBC 5 +#define CRYPTO_MD5_HMAC96 6 +#define CRYPTO_SHA1_HMAC96 7 +#define CRYPTO_RIPEMD160_HMAC96 8 +#define CRYPTO_MD5_KPDK 9 +#define CRYPTO_SHA1_KPDK 10 + +#define CRYPTO_ALGORITHM_MAX 10 /* Keep this updated */ + +/* Standard initialization structure beginning */ +struct cryptoini +{ + int cri_alg; /* Algorithm to use */ + int cri_klen; /* Key length, in bits */ + int cri_rnd; /* Algorithm rounds, where relevant */ + caddr_t cri_key; /* key to use */ + struct cryptoini *cri_next; +}; + +/* Describe boundaries of a single crypto operation */ +struct cryptodesc +{ + int crd_skip; /* How many bytes to ignore from start */ + int crd_len; /* How many bytes to process */ + int crd_inject; /* Where to inject results, if applicable */ + int crd_flags; + +#define CRD_F_ENCRYPT 0x1 /* Set when doing encryption */ +#define CRD_F_HALFIV 0x2 + + struct cryptoini CRD_INI; /* Initialization/context data */ +#define crd_key CRD_INI.cri_key +#define crd_rnd CRD_INI.cri_rnd +#define crd_alg CRD_INI.cri_alg +#define crd_klen CRD_INI.cri_klen + + struct cryptodesc *crd_next; +}; + +/* Structure describing complete operation */ +struct cryptop +{ + u_int64_t crp_sid; /* Session ID */ + int crp_ilen; /* Input data total length */ + int crp_olen; /* Result total length (unused for now) */ + int crp_alloctype; /* Type of buf to allocate if needed */ + + int crp_etype; /* Error type (zero means no error). + * All error codes except EAGAIN + * indicate possible data corruption (as in, + * the data have been touched). On all + * errors, the crp_sid may have changed + * (reset to a new one), so the caller + * should always check and use the new + * value on future requests. + */ + int crp_flags; + +#define CRYPTO_F_IMBUF 0x0001 /* Input is an mbuf chain, otherwise contig */ + + caddr_t crp_buf; /* Data to be processed */ + + caddr_t crp_opaque1;/* Opaque pointer, passed along */ + caddr_t crp_opaque2;/* Opaque pointer, passed along */ + caddr_t crp_opaque3;/* Opaque pointer, passed along */ + caddr_t crp_opaque4;/* Opaque pointer, passed along */ + + struct cryptodesc *crp_desc; /* Linked list of processing descriptors */ + + int (*crp_callback) (struct cryptop *); /* Callback function */ + + struct cryptop *crp_next; +}; + +#define CRYPTO_BUF_CONTIG 0x1 +#define CRYPTO_BUF_MBUF 0x2 + +#define CRYPTO_OP_DECRYPT 0x0 +#define CRYPTO_OP_ENCRYPT 0x1 + +/* Crypto capabilities structure */ +struct cryptocap +{ + u_int32_t cc_sessions; + + u_int8_t cc_alg[CRYPTO_ALGORITHM_MAX + 1]; /* Supported */ + u_int8_t cc_flags; +#define CRYPTOCAP_F_CLEANUP 0x1 + + int (*cc_newsession) (u_int32_t *, struct cryptoini *); + int (*cc_process) (struct cryptop *); + int (*cc_freesession) (u_int32_t); +}; + +/* Software session entry */ +struct swcr_data +{ + int sw_alg; /* Algorithm */ + union + { + struct + { + u_int8_t *SW_ictx; + u_int8_t *SW_octx; + struct auth_hash *SW_axf; + } SWCR_AUTH; + + struct + { + u_int8_t *SW_kschedule; + u_int8_t *SW_iv; + struct enc_xform *SW_exf; + } SWCR_ENC; + } SWCR_UN; + +#define sw_ictx SWCR_UN.SWCR_AUTH.SW_ictx +#define sw_octx SWCR_UN.SWCR_AUTH.SW_octx +#define sw_axf SWCR_UN.SWCR_AUTH.SW_axf +#define sw_kschedule SWCR_UN.SWCR_ENC.SW_kschedule +#define sw_iv SWCR_UN.SWCR_ENC.SW_iv +#define sw_exf SWCR_UN.SWCR_ENC.SW_exf + + struct swcr_data *sw_next; +}; + +#ifdef _KERNEL +extern u_int8_t hmac_ipad_buffer[64]; +extern u_int8_t hmac_opad_buffer[64]; + +extern int swcr_encdec(struct cryptodesc *, struct swcr_data *, caddr_t, int); +extern int swcr_authcompute(struct cryptodesc *, struct swcr_data *, + caddr_t, int); +extern int swcr_process(struct cryptop *); +extern int swcr_newsession(u_int32_t *, struct cryptoini *); +extern int swcr_freesession(u_int32_t); +extern void swcr_init(void); + +extern int crypto_newsession(u_int64_t *, struct cryptoini *); +extern int crypto_freesession(u_int64_t); +extern int crypto_dispatch(struct cryptop *); +extern int crypto_register(u_int32_t, int, void *, void *, void *); +extern int crypto_unregister(u_int32_t, int); +extern int32_t crypto_get_driverid(void); + +extern struct cryptop *crypto_getreq(int); +extern void crypto_freereq(struct cryptop *); +#endif /* _KERNEL */ +#endif /* _CRYPTO_CRYPTO_H_ */ diff --git a/sys/crypto/xform.c b/sys/crypto/xform.c new file mode 100644 index 00000000000..98bb2017494 --- /dev/null +++ b/sys/crypto/xform.c @@ -0,0 +1,354 @@ +/* $OpenBSD: xform.c,v 1.1 2000/03/17 10:25:21 angelos Exp $ */ + +/* + * The authors of this code are John Ioannidis (ji@tla.org), + * Angelos D. Keromytis (kermit@csd.uch.gr) and + * Niels Provos (provos@physnet.uni-hamburg.de). + * + * This code was written by John Ioannidis for BSD/OS in Athens, Greece, + * in November 1995. + * + * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, + * by Angelos D. Keromytis. + * + * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis + * and Niels Provos. + * + * Additional features in 1999 by Angelos D. Keromytis. + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, + * Angelos D. Keromytis and Niels Provos. + * + * Permission to use, copy, and modify this software without fee + * is hereby granted, provided that this entire notice is included in + * all copies of any software which is or includes a copy or + * modification of this software. + * You may use this code under the GNU public license if you so wish. Please + * contribute changes back to the authors under this freer than GPL license + * so that we may further the use of strong encryption without limitations to + * all. + * + * 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/sysctl.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <machine/cpu.h> + +#include <sys/md5k.h> +#include <crypto/sha1.h> +#include <crypto/rmd160.h> +#include <crypto/blf.h> +#include <crypto/cast.h> +#include <crypto/skipjack.h> +#include <crypto/crypto.h> +#include <crypto/xform.h> + +extern void des_ecb3_encrypt(caddr_t, caddr_t, caddr_t, caddr_t, caddr_t, int); +extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int); + +void des_set_key(caddr_t, caddr_t); +void des1_setkey(u_int8_t **, u_int8_t *, int); +void des3_setkey(u_int8_t **, u_int8_t *, int); +void blf_setkey(u_int8_t **, u_int8_t *, int); +void cast5_setkey(u_int8_t **, u_int8_t *, int); +void skipjack_setkey(u_int8_t **, u_int8_t *, int); +void des1_encrypt(caddr_t, u_int8_t *); +void des3_encrypt(caddr_t, u_int8_t *); +void blf_encrypt(caddr_t, u_int8_t *); +void cast5_encrypt(caddr_t, u_int8_t *); +void skipjack_encrypt(caddr_t, u_int8_t *); +void des1_decrypt(caddr_t, u_int8_t *); +void des3_decrypt(caddr_t, u_int8_t *); +void blf_decrypt(caddr_t, u_int8_t *); +void cast5_decrypt(caddr_t, u_int8_t *); +void skipjack_decrypt(caddr_t, u_int8_t *); +void des1_zerokey(u_int8_t **); +void des3_zerokey(u_int8_t **); +void blf_zerokey(u_int8_t **); +void cast5_zerokey(u_int8_t **); +void skipjack_zerokey(u_int8_t **); + +int MD5Update_int(void *, u_int8_t *, u_int16_t); +int SHA1Update_int(void *, u_int8_t *, u_int16_t); +int RMD160Update_int(void *, u_int8_t *, u_int16_t); + +/* Encryption instances */ +struct enc_xform enc_xform_des = +{ + CRYPTO_DES_CBC, "DES", + 8, 8, 8, 8, + des1_encrypt, + des1_decrypt, + des1_setkey, + des1_zerokey, +}; + +struct enc_xform enc_xform_3des = +{ + CRYPTO_3DES_CBC, "3DES", + 8, 24, 24, 8, + des3_encrypt, + des3_decrypt, + des3_setkey, + des3_zerokey +}; + +struct enc_xform enc_xform_blf = +{ + CRYPTO_BLF_CBC, "Blowfish", + 8, 5, 56 /* 448 bits, max key */, 8, + blf_encrypt, + blf_decrypt, + blf_setkey, + blf_zerokey +}; + +struct enc_xform enc_xform_cast5 = +{ + CRYPTO_CAST_CBC, "CAST-128", + 8, 5, 16, 8, + cast5_encrypt, + cast5_decrypt, + cast5_setkey, + cast5_zerokey +}; + +struct enc_xform enc_xform_skipjack = +{ + CRYPTO_SKIPJACK_CBC, "Skipjack", + 8, 10, 10, 8, + skipjack_encrypt, + skipjack_decrypt, + skipjack_setkey, + skipjack_zerokey +}; + +/* Authentication instances */ +struct auth_hash auth_hash_hmac_md5_96 = +{ + CRYPTO_MD5_HMAC96, "HMAC-MD5-96", + 16, 16, 12, sizeof(MD5_CTX), + (void (*) (void *)) MD5Init, MD5Update_int, + (void (*) (u_int8_t *, void *)) MD5Final +}; + +struct auth_hash auth_hash_hmac_sha1_96 = +{ + CRYPTO_SHA1_HMAC96, "HMAC-SHA1-96", + 20, 20, 12, sizeof(SHA1_CTX), + (void (*) (void *)) SHA1Init, SHA1Update_int, + (void (*) (u_int8_t *, void *)) SHA1Final +}; + +struct auth_hash auth_hash_hmac_ripemd_160_96 = +{ + CRYPTO_RIPEMD160_HMAC96, "HMAC-RIPEMD-160-96", + 20, 20, 12, sizeof(RMD160_CTX), + (void (*)(void *)) RMD160Init, RMD160Update_int, + (void (*)(u_int8_t *, void *)) RMD160Final +}; + +struct auth_hash auth_hash_key_md5 = +{ + CRYPTO_MD5_KPDK, "Keyed MD5", + 0, 16, 16, sizeof(MD5_CTX), + (void (*)(void *)) MD5Init, MD5Update_int, + (void (*)(u_int8_t *, void *)) MD5Final +}; + +struct auth_hash auth_hash_key_sha1 = +{ + CRYPTO_SHA1_KPDK, "Keyed SHA1", + 0, 20, 20, sizeof(SHA1_CTX), + (void (*)(void *)) SHA1Init, SHA1Update_int, + (void (*)(u_int8_t *, void *)) SHA1Final +}; + +/* + * Encryption wrapper routines. + */ +void +des1_encrypt(caddr_t key, u_int8_t *blk) +{ + des_ecb_encrypt(blk, blk, key, 1); +} + +void +des1_decrypt(caddr_t key, u_int8_t *blk) +{ + des_ecb_encrypt(blk, blk, key, 0); +} + +void +des1_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + MALLOC(*sched, u_int8_t *, 128, M_XDATA, M_WAITOK); + bzero(*sched, 128); + des_set_key(key, *sched); +} + +void +des1_zerokey(u_int8_t **sched) +{ + bzero(*sched, 128); + FREE(*sched, M_XDATA); + *sched = NULL; +} + +void +des3_encrypt(caddr_t key, u_int8_t *blk) +{ + des_ecb3_encrypt(blk, blk, key, key + 128, key + 256, 1); +} + +void +des3_decrypt(caddr_t key, u_int8_t *blk) +{ + des_ecb3_encrypt(blk, blk, key + 256, key + 128, key, 0); +} + +void +des3_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + MALLOC(*sched, u_int8_t *, 384, M_XDATA, M_WAITOK); + bzero(*sched, 384); + des_set_key(key, *sched); + des_set_key(key + 8, *sched + 128); + des_set_key(key + 16, *sched + 256); +} + +void +des3_zerokey(u_int8_t **sched) +{ + bzero(*sched, 384); + FREE(*sched, M_XDATA); + *sched = NULL; +} + +void +blf_encrypt(caddr_t key, u_int8_t *blk) +{ + blf_ecb_encrypt((blf_ctx *) key, blk, 8); +} + +void +blf_decrypt(caddr_t key, u_int8_t *blk) +{ + blf_ecb_decrypt((blf_ctx *) key, blk, 8); +} + +void +blf_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + MALLOC(*sched, u_int8_t *, sizeof(blf_ctx), M_XDATA, M_WAITOK); + bzero(*sched, sizeof(blf_ctx)); + blf_key((blf_ctx *)*sched, key, len); +} + +void +blf_zerokey(u_int8_t **sched) +{ + bzero(*sched, sizeof(blf_ctx)); + FREE(*sched, M_XDATA); + *sched = NULL; +} + +void +cast5_encrypt(caddr_t key, u_int8_t *blk) +{ + cast_encrypt((cast_key *) key, blk, blk); +} + +void +cast5_decrypt(caddr_t key, u_int8_t *blk) +{ + cast_decrypt((cast_key *) key, blk, blk); +} + +void +cast5_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + MALLOC(*sched, u_int8_t *, sizeof(blf_ctx), M_XDATA, M_WAITOK); + bzero(*sched, sizeof(blf_ctx)); + cast_setkey((cast_key *)*sched, key, len); +} + +void +cast5_zerokey(u_int8_t **sched) +{ + bzero(*sched, sizeof(cast_key)); + FREE(*sched, M_XDATA); + *sched = NULL; +} + +void +skipjack_encrypt(caddr_t key, u_int8_t *blk) +{ + skipjack_forwards(blk, blk, (u_int8_t **) key); +} + +void +skipjack_decrypt(caddr_t key, u_int8_t *blk) +{ + skipjack_backwards(blk, blk, (u_int8_t **) key); +} + +void +skipjack_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + MALLOC(*sched, u_int8_t *, 10 * sizeof(u_int8_t *), M_XDATA, M_WAITOK); + bzero(*sched, 10 * sizeof(u_int8_t *)); + subkey_table_gen(key, (u_int8_t **) *sched); +} + +void +skipjack_zerokey(u_int8_t **sched) +{ + int k; + + for (k = 0; k < 10; k++) + if (((u_int8_t **)(*sched))[k]) + { + bzero(((u_int8_t **)(*sched))[k], 0x100); + FREE(((u_int8_t **)(*sched))[k], M_XDATA); + } + bzero(*sched, 10 * sizeof(u_int8_t *)); + FREE(*sched, M_XDATA); + *sched = NULL; +} + +/* + * And now for auth. + */ + +int +RMD160Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +{ + RMD160Update(ctx, buf, len); + return 0; +} + +int +MD5Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +{ + MD5Update(ctx, buf, len); + return 0; +} + +int +SHA1Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +{ + SHA1Update(ctx, buf, len); + return 0; +} + diff --git a/sys/crypto/xform.h b/sys/crypto/xform.h new file mode 100644 index 00000000000..7e220789a56 --- /dev/null +++ b/sys/crypto/xform.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef _CRYPTO_XFORM_H_ +#define _CRYPTO_XFORM_H_ + +#include <sys/md5k.h> +#include <crypto/sha1.h> +#include <crypto/rmd160.h> + +/* Declarations */ +struct auth_hash +{ + int type; + char *name; + u_int16_t keysize; + u_int16_t hashsize; + u_int16_t authsize; + u_int16_t ctxsize; + void (*Init) (void *); + int (*Update) (void *, u_int8_t *, u_int16_t); + void (*Final) (u_int8_t *, void *); +}; + +struct enc_xform +{ + int type; + char *name; + u_int16_t blocksize; + u_int16_t minkey, maxkey; + u_int32_t ivmask; /* Or all possible modes, zero iv = 1 */ + void (*encrypt) (caddr_t, u_int8_t *); + void (*decrypt) (caddr_t, u_int8_t *); + void (*setkey) (u_int8_t **, u_int8_t *, int len); + void (*zerokey) (u_int8_t **); +}; + +union authctx { + MD5_CTX md5ctx; + SHA1_CTX sha1ctx; + RMD160_CTX rmd160ctx; +}; + +extern struct enc_xform enc_xform_des; +extern struct enc_xform enc_xform_3des; +extern struct enc_xform enc_xform_blf; +extern struct enc_xform enc_xform_cast5; +extern struct enc_xform enc_xform_skipjack; + +extern struct auth_hash auth_hash_key_md5; +extern struct auth_hash auth_hash_key_sha1; +extern struct auth_hash auth_hash_hmac_md5_96; +extern struct auth_hash auth_hash_hmac_sha1_96; +extern struct auth_hash auth_hash_hmac_ripemd_160_96; +#endif /* _CRYPTO_XFORM_H_ */ |