From 5b6944e5061c5d9995172e8ee102e807211d5656 Mon Sep 17 00:00:00 2001 From: deraadt Date: Sun, 19 Mar 2000 06:53:40 +0000 Subject: [PATCH] split crypto driver front-end from software crypto engine --- sys/conf/files | 3 +- sys/crypto/crypto.c | 725 -------------------------------------- sys/crypto/cryptosoft.c | 762 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 764 insertions(+), 726 deletions(-) create mode 100644 sys/crypto/cryptosoft.c diff --git a/sys/conf/files b/sys/conf/files index 7b82dff2071..f9da9127d31 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 diff --git a/sys/crypto/crypto.c b/sys/crypto/crypto.c index 14fa7f885ca..4ef43f154f2 100644 --- a/sys/crypto/crypto.c +++ b/sys/crypto/crypto.c @@ -38,35 +38,11 @@ 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 index 00000000000..d877c8e957b --- /dev/null +++ b/sys/crypto/cryptosoft.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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!"); +} -- 2.20.1