1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180 |
- /* $OpenBSD: cryptosoft.c,v 1.73 2015/03/14 03:38:46 jsg Exp $ */
- /*
- * 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, 2001 Angelos D. Keromytis
- *
- * Permission to use, copy, and modify this software with or 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/errno.h>
- #include <dev/rndvar.h>
- #include <crypto/md5.h>
- #include <crypto/sha1.h>
- #include <crypto/rmd160.h>
- #include <crypto/cast.h>
- #include <crypto/cryptodev.h>
- #include <crypto/cryptosoft.h>
- #include <crypto/xform.h>
- const u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN] = {
- 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,
- 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
- };
- const u_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN] = {
- 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,
- 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;
- #define COPYBACK(x, a, b, c, d) \
- do { \
- if ((x) == CRYPTO_BUF_MBUF) \
- m_copyback((struct mbuf *)a,b,c,d,M_NOWAIT); \
- else \
- cuio_copyback((struct uio *)a,b,c,d); \
- } while (0)
- #define COPYDATA(x, a, b, c, d) \
- do { \
- if ((x) == CRYPTO_BUF_MBUF) \
- m_copydata((struct mbuf *)a,b,c,d); \
- else \
- cuio_copydata((struct uio *)a,b,c,d); \
- } while (0)
- /*
- * 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, *nivp, iv2[EALG_MAX_BLOCK_LEN];
- struct enc_xform *exf;
- int i, k, j, blks, ind, count, ivlen;
- struct mbuf *m = NULL;
- struct uio *uio = NULL;
- exf = sw->sw_exf;
- blks = exf->blocksize;
- ivlen = exf->ivsize;
- /* Check for non-padded data */
- if (crd->crd_len % blks)
- return EINVAL;
- if (outtype == CRYPTO_BUF_MBUF)
- m = (struct mbuf *) buf;
- else
- uio = (struct uio *) buf;
- /* Initialize the IV */
- if (crd->crd_flags & CRD_F_ENCRYPT) {
- /* IV explicitly provided ? */
- if (crd->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crd->crd_iv, iv, ivlen);
- else
- arc4random_buf(iv, ivlen);
- /* Do we need to write the IV */
- if (!(crd->crd_flags & CRD_F_IV_PRESENT))
- COPYBACK(outtype, buf, crd->crd_inject, ivlen, iv);
- } else { /* Decryption */
- /* IV explicitly provided ? */
- if (crd->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crd->crd_iv, iv, ivlen);
- else {
- /* Get IV off buf */
- COPYDATA(outtype, buf, crd->crd_inject, ivlen, iv);
- }
- }
- ivp = iv;
- /*
- * xforms that provide a reinit method perform all IV
- * handling themselves.
- */
- if (exf->reinit)
- exf->reinit(sw->sw_kschedule, iv);
- if (outtype == CRYPTO_BUF_MBUF) {
- /* 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 (exf->reinit) {
- if (crd->crd_flags & CRD_F_ENCRYPT) {
- exf->encrypt(sw->sw_kschedule,
- blk);
- } else {
- exf->decrypt(sw->sw_kschedule,
- blk);
- }
- } else 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
- */
- nivp = (ivp == iv) ? iv2 : iv;
- bcopy(blk, nivp, blks);
- exf->decrypt(sw->sw_kschedule, blk);
- /* XOR with previous block */
- for (j = 0; j < blks; j++)
- blk[j] ^= ivp[j];
- ivp = nivp;
- }
- /* Copy back decrypted block */
- m_copyback(m, k, blks, blk, M_NOWAIT);
- /* 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 (exf->reinit) {
- if (crd->crd_flags & CRD_F_ENCRYPT) {
- exf->encrypt(sw->sw_kschedule,
- idat);
- } else {
- exf->decrypt(sw->sw_kschedule,
- idat);
- }
- } else 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.
- */
- nivp = (ivp == iv) ? iv2 : iv;
- bcopy(idat, nivp, blks);
- exf->decrypt(sw->sw_kschedule, idat);
- /* XOR with previous block/IV */
- for (j = 0; j < blks; j++)
- idat[j] ^= ivp[j];
- ivp = nivp;
- }
- idat += blks;
- k += blks;
- i -= blks;
- }
- }
- } else {
- /* Find beginning of data */
- count = crd->crd_skip;
- ind = cuio_getptr(uio, count, &k);
- if (ind == -1)
- return EINVAL;
- i = crd->crd_len;
- while (i > 0) {
- /*
- * If there's insufficient data at the end,
- * we have to do some copying.
- */
- if (uio->uio_iov[ind].iov_len < k + blks &&
- uio->uio_iov[ind].iov_len != k) {
- cuio_copydata(uio, count, blks, blk);
- /* Actual encryption/decryption */
- if (exf->reinit) {
- if (crd->crd_flags & CRD_F_ENCRYPT) {
- exf->encrypt(sw->sw_kschedule,
- blk);
- } else {
- exf->decrypt(sw->sw_kschedule,
- blk);
- }
- } else 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
- */
- nivp = (ivp == iv) ? iv2 : iv;
- bcopy(blk, nivp, blks);
- exf->decrypt(sw->sw_kschedule, blk);
- /* XOR with previous block */
- for (j = 0; j < blks; j++)
- blk[j] ^= ivp[j];
- ivp = nivp;
- }
- /* Copy back decrypted block */
- cuio_copyback(uio, count, blks, blk);
- count += blks;
- /* Advance pointer */
- ind = cuio_getptr(uio, count, &k);
- if (ind == -1)
- return (EINVAL);
- i -= blks;
- /* Could be done... */
- if (i == 0)
- break;
- }
- /*
- * Warning: idat may point to garbage here, but
- * we only use it in the while() loop, only if
- * there are indeed enough data.
- */
- idat = (char *)uio->uio_iov[ind].iov_base + k;
- while (uio->uio_iov[ind].iov_len >= k + blks &&
- i > 0) {
- if (exf->reinit) {
- if (crd->crd_flags & CRD_F_ENCRYPT) {
- exf->encrypt(sw->sw_kschedule,
- idat);
- } else {
- exf->decrypt(sw->sw_kschedule,
- idat);
- }
- } else 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.
- */
- nivp = (ivp == iv) ? iv2 : iv;
- bcopy(idat, nivp, blks);
- exf->decrypt(sw->sw_kschedule, idat);
- /* XOR with previous block/IV */
- for (j = 0; j < blks; j++)
- idat[j] ^= ivp[j];
- ivp = nivp;
- }
- idat += blks;
- count += blks;
- k += blks;
- i -= blks;
- }
- /*
- * Advance to the next iov if the end of the current iov
- * is aligned with the end of a cipher block.
- * Note that the code is equivalent to calling:
- * ind = cuio_getptr(uio, count, &k);
- */
- if (i > 0 && k == uio->uio_iov[ind].iov_len) {
- k = 0;
- ind++;
- if (ind >= uio->uio_iovcnt)
- return (EINVAL);
- }
- }
- }
- return 0; /* Done with encryption/decryption */
- }
- /*
- * Compute keyed-hash authenticator.
- */
- int
- swcr_authcompute(struct cryptop *crp, 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_MBUF)
- err = m_apply((struct mbuf *) buf, crd->crd_skip, crd->crd_len,
- (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
- (caddr_t) &ctx);
- else
- err = cuio_apply((struct uio *) buf, crd->crd_skip,
- crd->crd_len,
- (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
- (caddr_t) &ctx);
- if (err)
- return err;
- if (crd->crd_flags & CRD_F_ESN)
- axf->Update(&ctx, crd->crd_esn, 4);
- switch (sw->sw_alg) {
- case CRYPTO_MD5_HMAC:
- case CRYPTO_SHA1_HMAC:
- case CRYPTO_RIPEMD160_HMAC:
- case CRYPTO_SHA2_256_HMAC:
- case CRYPTO_SHA2_384_HMAC:
- case CRYPTO_SHA2_512_HMAC:
- if (sw->sw_octx == NULL)
- return EINVAL;
- axf->Final(aalg, &ctx);
- bcopy(sw->sw_octx, &ctx, axf->ctxsize);
- axf->Update(&ctx, aalg, axf->hashsize);
- axf->Final(aalg, &ctx);
- break;
- case CRYPTO_MD5:
- case CRYPTO_SHA1:
- axf->Final(aalg, &ctx);
- break;
- }
- /* Inject the authentication data */
- if (outtype == CRYPTO_BUF_MBUF)
- COPYBACK(outtype, buf, crd->crd_inject, axf->authsize, aalg);
- else
- bcopy(aalg, crp->crp_mac, axf->authsize);
- return 0;
- }
- /*
- * Apply a combined encryption-authentication transformation
- */
- int
- swcr_authenc(struct cryptop *crp)
- {
- uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
- u_char *blk = (u_char *)blkbuf;
- u_char aalg[AALG_MAX_RESULT_LEN];
- u_char iv[EALG_MAX_BLOCK_LEN];
- union authctx ctx;
- struct cryptodesc *crd, *crda = NULL, *crde = NULL;
- struct swcr_data *sw, *swa, *swe = NULL;
- struct auth_hash *axf = NULL;
- struct enc_xform *exf = NULL;
- struct mbuf *m = NULL;
- struct uio *uio = NULL;
- caddr_t buf = (caddr_t)crp->crp_buf;
- uint32_t *blkp;
- int aadlen, blksz, i, ivlen, outtype, len, iskip, oskip;
- ivlen = blksz = iskip = oskip = 0;
- for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
- for (sw = swcr_sessions[crp->crp_sid & 0xffffffff];
- sw && sw->sw_alg != crd->crd_alg;
- sw = sw->sw_next)
- ;
- if (sw == NULL)
- return (EINVAL);
- switch (sw->sw_alg) {
- case CRYPTO_AES_GCM_16:
- case CRYPTO_AES_GMAC:
- swe = sw;
- crde = crd;
- exf = swe->sw_exf;
- ivlen = exf->ivsize;
- break;
- case CRYPTO_AES_128_GMAC:
- case CRYPTO_AES_192_GMAC:
- case CRYPTO_AES_256_GMAC:
- swa = sw;
- crda = crd;
- axf = swa->sw_axf;
- if (swa->sw_ictx == 0)
- return (EINVAL);
- bcopy(swa->sw_ictx, &ctx, axf->ctxsize);
- blksz = axf->blocksize;
- break;
- default:
- return (EINVAL);
- }
- }
- if (crde == NULL || crda == NULL)
- return (EINVAL);
- if (crp->crp_flags & CRYPTO_F_IMBUF) {
- outtype = CRYPTO_BUF_MBUF;
- m = (struct mbuf *)buf;
- } else {
- outtype = CRYPTO_BUF_IOV;
- uio = (struct uio *)buf;
- }
- /* Initialize the IV */
- if (crde->crd_flags & CRD_F_ENCRYPT) {
- /* IV explicitly provided ? */
- if (crde->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crde->crd_iv, iv, ivlen);
- else
- arc4random_buf(iv, ivlen);
- /* Do we need to write the IV */
- if (!(crde->crd_flags & CRD_F_IV_PRESENT))
- COPYBACK(outtype, buf, crde->crd_inject, ivlen, iv);
- } else { /* Decryption */
- /* IV explicitly provided ? */
- if (crde->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crde->crd_iv, iv, ivlen);
- else {
- /* Get IV off buf */
- COPYDATA(outtype, buf, crde->crd_inject, ivlen, iv);
- }
- }
- /* Supply MAC with IV */
- if (axf->Reinit)
- axf->Reinit(&ctx, iv, ivlen);
- /* Supply MAC with AAD */
- aadlen = crda->crd_len;
- /*
- * Section 5 of RFC 4106 specifies that AAD construction consists of
- * {SPI, ESN, SN} whereas the real packet contains only {SPI, SN}.
- * Unfortunately it doesn't follow a good example set in the Section
- * 3.3.2.1 of RFC 4303 where upper part of the ESN, located in the
- * external (to the packet) memory buffer, is processed by the hash
- * function in the end thus allowing to retain simple programming
- * interfaces and avoid kludges like the one below.
- */
- if (crda->crd_flags & CRD_F_ESN) {
- aadlen += 4;
- /* SPI */
- COPYDATA(outtype, buf, crda->crd_skip, 4, blk);
- iskip = 4; /* loop below will start with an offset of 4 */
- /* ESN */
- bcopy(crda->crd_esn, blk + 4, 4);
- oskip = iskip + 4; /* offset output buffer blk by 8 */
- }
- for (i = iskip; i < crda->crd_len; i += blksz) {
- len = MIN(crda->crd_len - i, blksz - oskip);
- COPYDATA(outtype, buf, crda->crd_skip + i, len, blk + oskip);
- bzero(blk + len + oskip, blksz - len - oskip);
- axf->Update(&ctx, blk, blksz);
- oskip = 0; /* reset initial output offset */
- }
- if (exf->reinit)
- exf->reinit(swe->sw_kschedule, iv);
- /* Do encryption/decryption with MAC */
- for (i = 0; i < crde->crd_len; i += blksz) {
- len = MIN(crde->crd_len - i, blksz);
- if (len < blksz)
- bzero(blk, blksz);
- COPYDATA(outtype, buf, crde->crd_skip + i, len, blk);
- if (crde->crd_flags & CRD_F_ENCRYPT) {
- exf->encrypt(swe->sw_kschedule, blk);
- axf->Update(&ctx, blk, len);
- } else {
- axf->Update(&ctx, blk, len);
- exf->decrypt(swe->sw_kschedule, blk);
- }
- COPYBACK(outtype, buf, crde->crd_skip + i, len, blk);
- }
- /* Do any required special finalization */
- switch (crda->crd_alg) {
- case CRYPTO_AES_128_GMAC:
- case CRYPTO_AES_192_GMAC:
- case CRYPTO_AES_256_GMAC:
- /* length block */
- bzero(blk, blksz);
- blkp = (uint32_t *)blk + 1;
- *blkp = htobe32(aadlen * 8);
- blkp = (uint32_t *)blk + 3;
- *blkp = htobe32(crde->crd_len * 8);
- axf->Update(&ctx, blk, blksz);
- break;
- }
- /* Finalize MAC */
- axf->Final(aalg, &ctx);
- /* Inject the authentication data */
- if (outtype == CRYPTO_BUF_MBUF)
- COPYBACK(outtype, buf, crda->crd_inject, axf->authsize, aalg);
- else
- bcopy(aalg, crp->crp_mac, axf->authsize);
- return (0);
- }
- /*
- * Apply a compression/decompression algorithm
- */
- int
- swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw,
- caddr_t buf, int outtype)
- {
- u_int8_t *data, *out;
- struct comp_algo *cxf;
- int adj;
- u_int32_t result;
- cxf = sw->sw_cxf;
- /* We must handle the whole buffer of data in one time
- * then if there is not all the data in the mbuf, we must
- * copy in a buffer.
- */
- data = malloc(crd->crd_len, M_CRYPTO_DATA, M_NOWAIT);
- if (data == NULL)
- return (EINVAL);
- COPYDATA(outtype, buf, crd->crd_skip, crd->crd_len, data);
- if (crd->crd_flags & CRD_F_COMP)
- result = cxf->compress(data, crd->crd_len, &out);
- else
- result = cxf->decompress(data, crd->crd_len, &out);
- free(data, M_CRYPTO_DATA, 0);
- if (result == 0)
- return EINVAL;
- /* Copy back the (de)compressed data. m_copyback is
- * extending the mbuf as necessary.
- */
- sw->sw_size = result;
- /* Check the compressed size when doing compression */
- if (crd->crd_flags & CRD_F_COMP) {
- if (result > crd->crd_len) {
- /* Compression was useless, we lost time */
- free(out, M_CRYPTO_DATA, 0);
- return 0;
- }
- }
- COPYBACK(outtype, buf, crd->crd_skip, result, out);
- if (result < crd->crd_len) {
- adj = result - crd->crd_len;
- if (outtype == CRYPTO_BUF_MBUF) {
- adj = result - crd->crd_len;
- m_adj((struct mbuf *)buf, adj);
- } else {
- struct uio *uio = (struct uio *)buf;
- int ind;
- adj = crd->crd_len - result;
- ind = uio->uio_iovcnt - 1;
- while (adj > 0 && ind >= 0) {
- if (adj < uio->uio_iov[ind].iov_len) {
- uio->uio_iov[ind].iov_len -= adj;
- break;
- }
- adj -= uio->uio_iov[ind].iov_len;
- uio->uio_iov[ind].iov_len = 0;
- ind--;
- uio->uio_iovcnt--;
- }
- }
- }
- free(out, M_CRYPTO_DATA, 0);
- 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;
- struct comp_algo *cxf;
- 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;
- swd = mallocarray(swcr_sesnum, sizeof(struct swcr_data *),
- M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
- if (swd == NULL) {
- /* Reset session number */
- if (swcr_sesnum == CRYPTO_SW_SESSIONS)
- swcr_sesnum = 0;
- else
- swcr_sesnum /= 2;
- return ENOBUFS;
- }
- /* Copy existing sessions */
- if (swcr_sessions) {
- bcopy(swcr_sessions, swd,
- (swcr_sesnum / 2) * sizeof(struct swcr_data *));
- free(swcr_sessions, M_CRYPTO_DATA, 0);
- }
- swcr_sessions = swd;
- }
- swd = &swcr_sessions[i];
- *sid = i;
- while (cri) {
- *swd = malloc(sizeof(struct swcr_data), M_CRYPTO_DATA,
- M_NOWAIT | M_ZERO);
- if (*swd == NULL) {
- swcr_freesession(i);
- return ENOBUFS;
- }
- 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_RIJNDAEL128_CBC:
- txf = &enc_xform_rijndael128;
- goto enccommon;
- case CRYPTO_AES_CTR:
- txf = &enc_xform_aes_ctr;
- goto enccommon;
- case CRYPTO_AES_XTS:
- txf = &enc_xform_aes_xts;
- goto enccommon;
- case CRYPTO_AES_GCM_16:
- txf = &enc_xform_aes_gcm;
- goto enccommon;
- case CRYPTO_AES_GMAC:
- txf = &enc_xform_aes_gmac;
- (*swd)->sw_exf = txf;
- break;
- case CRYPTO_NULL:
- txf = &enc_xform_null;
- goto enccommon;
- enccommon:
- if (txf->ctxsize > 0) {
- (*swd)->sw_kschedule = malloc(txf->ctxsize,
- M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
- if ((*swd)->sw_kschedule == NULL) {
- swcr_freesession(i);
- return EINVAL;
- }
- }
- if (txf->setkey((*swd)->sw_kschedule, cri->cri_key,
- cri->cri_klen / 8) < 0) {
- swcr_freesession(i);
- return EINVAL;
- }
- (*swd)->sw_exf = txf;
- break;
- case CRYPTO_MD5_HMAC:
- axf = &auth_hash_hmac_md5_96;
- goto authcommon;
- case CRYPTO_SHA1_HMAC:
- axf = &auth_hash_hmac_sha1_96;
- goto authcommon;
- case CRYPTO_RIPEMD160_HMAC:
- axf = &auth_hash_hmac_ripemd_160_96;
- goto authcommon;
- case CRYPTO_SHA2_256_HMAC:
- axf = &auth_hash_hmac_sha2_256_128;
- goto authcommon;
- case CRYPTO_SHA2_384_HMAC:
- axf = &auth_hash_hmac_sha2_384_192;
- goto authcommon;
- case CRYPTO_SHA2_512_HMAC:
- axf = &auth_hash_hmac_sha2_512_256;
- authcommon:
- (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
- M_NOWAIT);
- if ((*swd)->sw_ictx == NULL) {
- swcr_freesession(i);
- return ENOBUFS;
- }
- (*swd)->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
- M_NOWAIT);
- 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,
- axf->blocksize - (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,
- axf->blocksize - (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:
- axf = &auth_hash_md5;
- goto auth3common;
- case CRYPTO_SHA1:
- axf = &auth_hash_sha1;
- auth3common:
- (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
- M_NOWAIT);
- if ((*swd)->sw_ictx == NULL) {
- swcr_freesession(i);
- return ENOBUFS;
- }
- axf->Init((*swd)->sw_ictx);
- (*swd)->sw_axf = axf;
- break;
- case CRYPTO_AES_128_GMAC:
- axf = &auth_hash_gmac_aes_128;
- goto auth4common;
- case CRYPTO_AES_192_GMAC:
- axf = &auth_hash_gmac_aes_192;
- goto auth4common;
- case CRYPTO_AES_256_GMAC:
- axf = &auth_hash_gmac_aes_256;
- auth4common:
- (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
- M_NOWAIT);
- if ((*swd)->sw_ictx == NULL) {
- swcr_freesession(i);
- return ENOBUFS;
- }
- axf->Init((*swd)->sw_ictx);
- axf->Setkey((*swd)->sw_ictx, cri->cri_key,
- cri->cri_klen / 8);
- (*swd)->sw_axf = axf;
- break;
- case CRYPTO_DEFLATE_COMP:
- cxf = &comp_algo_deflate;
- (*swd)->sw_cxf = cxf;
- break;
- case CRYPTO_ESN:
- /* nothing to do */
- 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_int64_t tid)
- {
- struct swcr_data *swd;
- struct enc_xform *txf;
- struct auth_hash *axf;
- u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
- 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_RIJNDAEL128_CBC:
- case CRYPTO_AES_CTR:
- case CRYPTO_AES_XTS:
- case CRYPTO_AES_GCM_16:
- case CRYPTO_AES_GMAC:
- case CRYPTO_NULL:
- txf = swd->sw_exf;
- if (swd->sw_kschedule) {
- explicit_bzero(swd->sw_kschedule, txf->ctxsize);
- free(swd->sw_kschedule, M_CRYPTO_DATA, 0);
- }
- break;
- case CRYPTO_MD5_HMAC:
- case CRYPTO_SHA1_HMAC:
- case CRYPTO_RIPEMD160_HMAC:
- case CRYPTO_SHA2_256_HMAC:
- case CRYPTO_SHA2_384_HMAC:
- case CRYPTO_SHA2_512_HMAC:
- axf = swd->sw_axf;
- if (swd->sw_ictx) {
- explicit_bzero(swd->sw_ictx, axf->ctxsize);
- free(swd->sw_ictx, M_CRYPTO_DATA, 0);
- }
- if (swd->sw_octx) {
- explicit_bzero(swd->sw_octx, axf->ctxsize);
- free(swd->sw_octx, M_CRYPTO_DATA, 0);
- }
- break;
- case CRYPTO_AES_128_GMAC:
- case CRYPTO_AES_192_GMAC:
- case CRYPTO_AES_256_GMAC:
- case CRYPTO_MD5:
- case CRYPTO_SHA1:
- axf = swd->sw_axf;
- if (swd->sw_ictx) {
- explicit_bzero(swd->sw_ictx, axf->ctxsize);
- free(swd->sw_ictx, M_CRYPTO_DATA, 0);
- }
- break;
- }
- free(swd, M_CRYPTO_DATA, 0);
- }
- return 0;
- }
- /*
- * Process a software request.
- */
- int
- swcr_process(struct cryptop *crp)
- {
- struct cryptodesc *crd;
- struct swcr_data *sw;
- u_int32_t lid;
- int type;
- /* Sanity check */
- if (crp == 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_IOV;
- /* 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_NULL:
- break;
- case CRYPTO_DES_CBC:
- case CRYPTO_3DES_CBC:
- case CRYPTO_BLF_CBC:
- case CRYPTO_CAST_CBC:
- case CRYPTO_RIJNDAEL128_CBC:
- case CRYPTO_AES_CTR:
- case CRYPTO_AES_XTS:
- if ((crp->crp_etype = swcr_encdec(crd, sw,
- crp->crp_buf, type)) != 0)
- goto done;
- break;
- case CRYPTO_MD5_HMAC:
- case CRYPTO_SHA1_HMAC:
- case CRYPTO_RIPEMD160_HMAC:
- case CRYPTO_SHA2_256_HMAC:
- case CRYPTO_SHA2_384_HMAC:
- case CRYPTO_SHA2_512_HMAC:
- case CRYPTO_MD5:
- case CRYPTO_SHA1:
- if ((crp->crp_etype = swcr_authcompute(crp, crd, sw,
- crp->crp_buf, type)) != 0)
- goto done;
- break;
- case CRYPTO_AES_GCM_16:
- case CRYPTO_AES_GMAC:
- case CRYPTO_AES_128_GMAC:
- case CRYPTO_AES_192_GMAC:
- case CRYPTO_AES_256_GMAC:
- crp->crp_etype = swcr_authenc(crp);
- goto done;
- case CRYPTO_DEFLATE_COMP:
- if ((crp->crp_etype = swcr_compdec(crd, sw,
- crp->crp_buf, type)) != 0)
- goto done;
- else
- crp->crp_olen = (int)sw->sw_size;
- break;
- default:
- /* Unknown/unsupported algorithm */
- crp->crp_etype = EINVAL;
- goto done;
- }
- }
- done:
- crypto_done(crp);
- return 0;
- }
- /*
- * Initialize the driver, called from the kernel main().
- */
- void
- swcr_init(void)
- {
- int algs[CRYPTO_ALGORITHM_MAX + 1];
- int flags = CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_ENCRYPT_MAC |
- CRYPTOCAP_F_MAC_ENCRYPT;
- swcr_id = crypto_get_driverid(flags);
- if (swcr_id < 0) {
- /* This should never happen */
- panic("Software crypto device cannot initialize!");
- }
- bzero(algs, sizeof(algs));
- algs[CRYPTO_DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_3DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_BLF_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_CAST_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_MD5] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_SHA1] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_RIJNDAEL128_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_XTS] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_GCM_16] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_DEFLATE_COMP] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_NULL] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_128_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_192_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_AES_256_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
- algs[CRYPTO_ESN] = CRYPTO_ALG_FLAG_SUPPORTED;
- crypto_register(swcr_id, algs, swcr_newsession,
- swcr_freesession, swcr_process);
- }
|