1091d81d1SSam Leffler /* $OpenBSD: cryptosoft.c,v 1.35 2002/04/26 08:43:50 deraadt Exp $ */ 2091d81d1SSam Leffler 360727d8bSWarner Losh /*- 4091d81d1SSam Leffler * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) 5091d81d1SSam Leffler * 6091d81d1SSam Leffler * This code was written by Angelos D. Keromytis in Athens, Greece, in 7091d81d1SSam Leffler * February 2000. Network Security Technologies Inc. (NSTI) kindly 8091d81d1SSam Leffler * supported the development of this code. 9091d81d1SSam Leffler * 10091d81d1SSam Leffler * Copyright (c) 2000, 2001 Angelos D. Keromytis 11091d81d1SSam Leffler * 12091d81d1SSam Leffler * Permission to use, copy, and modify this software with or without fee 13091d81d1SSam Leffler * is hereby granted, provided that this entire notice is included in 14091d81d1SSam Leffler * all source code copies of any software which is or includes a copy or 15091d81d1SSam Leffler * modification of this software. 16091d81d1SSam Leffler * 17091d81d1SSam Leffler * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 18091d81d1SSam Leffler * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 19091d81d1SSam Leffler * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 20091d81d1SSam Leffler * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 21091d81d1SSam Leffler * PURPOSE. 22091d81d1SSam Leffler */ 23091d81d1SSam Leffler 242c446514SDavid E. O'Brien #include <sys/cdefs.h> 252c446514SDavid E. O'Brien __FBSDID("$FreeBSD$"); 262c446514SDavid E. O'Brien 27091d81d1SSam Leffler #include <sys/param.h> 28091d81d1SSam Leffler #include <sys/systm.h> 29091d81d1SSam Leffler #include <sys/malloc.h> 30091d81d1SSam Leffler #include <sys/mbuf.h> 31091d81d1SSam Leffler #include <sys/sysctl.h> 32091d81d1SSam Leffler #include <sys/errno.h> 33091d81d1SSam Leffler #include <sys/random.h> 34091d81d1SSam Leffler #include <sys/kernel.h> 35091d81d1SSam Leffler #include <sys/uio.h> 36091d81d1SSam Leffler 37091d81d1SSam Leffler #include <crypto/blowfish/blowfish.h> 38091d81d1SSam Leffler #include <crypto/cast128/cast128.h> 39091d81d1SSam Leffler #include <crypto/sha1.h> 40091d81d1SSam Leffler #include <opencrypto/rmd160.h> 41091d81d1SSam Leffler #include <opencrypto/skipjack.h> 42091d81d1SSam Leffler #include <sys/md5.h> 43091d81d1SSam Leffler 44091d81d1SSam Leffler #include <opencrypto/cryptodev.h> 45091d81d1SSam Leffler #include <opencrypto/cryptosoft.h> 46091d81d1SSam Leffler #include <opencrypto/xform.h> 47091d81d1SSam Leffler 48091d81d1SSam Leffler u_int8_t hmac_ipad_buffer[64] = { 49091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 50091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 51091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 52091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 53091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 54091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 55091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 56091d81d1SSam Leffler 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 57091d81d1SSam Leffler }; 58091d81d1SSam Leffler 59091d81d1SSam Leffler u_int8_t hmac_opad_buffer[64] = { 60091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 61091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 62091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 63091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 64091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 65091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 66091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 67091d81d1SSam Leffler 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C 68091d81d1SSam Leffler }; 69091d81d1SSam Leffler 70091d81d1SSam Leffler 71091d81d1SSam Leffler struct swcr_data **swcr_sessions = NULL; 72091d81d1SSam Leffler u_int32_t swcr_sesnum = 0; 73091d81d1SSam Leffler int32_t swcr_id = -1; 74091d81d1SSam Leffler 75091d81d1SSam Leffler #define COPYBACK(x, a, b, c, d) \ 76091d81d1SSam Leffler (x) == CRYPTO_BUF_MBUF ? m_copyback((struct mbuf *)a,b,c,d) \ 77091d81d1SSam Leffler : cuio_copyback((struct uio *)a,b,c,d) 78091d81d1SSam Leffler #define COPYDATA(x, a, b, c, d) \ 79091d81d1SSam Leffler (x) == CRYPTO_BUF_MBUF ? m_copydata((struct mbuf *)a,b,c,d) \ 80091d81d1SSam Leffler : cuio_copydata((struct uio *)a,b,c,d) 81091d81d1SSam Leffler 82091d81d1SSam Leffler static int swcr_encdec(struct cryptodesc *, struct swcr_data *, caddr_t, int); 83091d81d1SSam Leffler static int swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd, 84091d81d1SSam Leffler struct swcr_data *sw, caddr_t buf, int outtype); 85091d81d1SSam Leffler static int swcr_compdec(struct cryptodesc *, struct swcr_data *, caddr_t, int); 86091d81d1SSam Leffler static int swcr_process(void *, struct cryptop *, int); 87091d81d1SSam Leffler static int swcr_newsession(void *, u_int32_t *, struct cryptoini *); 88091d81d1SSam Leffler static int swcr_freesession(void *, u_int64_t); 89091d81d1SSam Leffler 90091d81d1SSam Leffler /* 91091d81d1SSam Leffler * Apply a symmetric encryption/decryption algorithm. 92091d81d1SSam Leffler */ 93091d81d1SSam Leffler static int 94091d81d1SSam Leffler swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, 95091d81d1SSam Leffler int outtype) 96091d81d1SSam Leffler { 97091d81d1SSam Leffler unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat; 98091d81d1SSam Leffler unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN]; 99091d81d1SSam Leffler struct enc_xform *exf; 100091d81d1SSam Leffler int i, k, j, blks; 101091d81d1SSam Leffler 102091d81d1SSam Leffler exf = sw->sw_exf; 103091d81d1SSam Leffler blks = exf->blocksize; 104091d81d1SSam Leffler 105091d81d1SSam Leffler /* Check for non-padded data */ 106091d81d1SSam Leffler if (crd->crd_len % blks) 107091d81d1SSam Leffler return EINVAL; 108091d81d1SSam Leffler 109091d81d1SSam Leffler /* Initialize the IV */ 110091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 111091d81d1SSam Leffler /* IV explicitly provided ? */ 112091d81d1SSam Leffler if (crd->crd_flags & CRD_F_IV_EXPLICIT) 113091d81d1SSam Leffler bcopy(crd->crd_iv, iv, blks); 114091d81d1SSam Leffler else { 115091d81d1SSam Leffler /* Get random IV */ 116091d81d1SSam Leffler for (i = 0; 117091d81d1SSam Leffler i + sizeof (u_int32_t) < EALG_MAX_BLOCK_LEN; 118091d81d1SSam Leffler i += sizeof (u_int32_t)) { 119091d81d1SSam Leffler u_int32_t temp = arc4random(); 120091d81d1SSam Leffler 121091d81d1SSam Leffler bcopy(&temp, iv + i, sizeof(u_int32_t)); 122091d81d1SSam Leffler } 123091d81d1SSam Leffler /* 124091d81d1SSam Leffler * What if the block size is not a multiple 125091d81d1SSam Leffler * of sizeof (u_int32_t), which is the size of 126091d81d1SSam Leffler * what arc4random() returns ? 127091d81d1SSam Leffler */ 128091d81d1SSam Leffler if (EALG_MAX_BLOCK_LEN % sizeof (u_int32_t) != 0) { 129091d81d1SSam Leffler u_int32_t temp = arc4random(); 130091d81d1SSam Leffler 131091d81d1SSam Leffler bcopy (&temp, iv + i, 132091d81d1SSam Leffler EALG_MAX_BLOCK_LEN - i); 133091d81d1SSam Leffler } 134091d81d1SSam Leffler } 135091d81d1SSam Leffler 136091d81d1SSam Leffler /* Do we need to write the IV */ 137091d81d1SSam Leffler if (!(crd->crd_flags & CRD_F_IV_PRESENT)) { 138091d81d1SSam Leffler COPYBACK(outtype, buf, crd->crd_inject, blks, iv); 139091d81d1SSam Leffler } 140091d81d1SSam Leffler 141091d81d1SSam Leffler } else { /* Decryption */ 142091d81d1SSam Leffler /* IV explicitly provided ? */ 143091d81d1SSam Leffler if (crd->crd_flags & CRD_F_IV_EXPLICIT) 144091d81d1SSam Leffler bcopy(crd->crd_iv, iv, blks); 145091d81d1SSam Leffler else { 146091d81d1SSam Leffler /* Get IV off buf */ 147091d81d1SSam Leffler COPYDATA(outtype, buf, crd->crd_inject, blks, iv); 148091d81d1SSam Leffler } 149091d81d1SSam Leffler } 150091d81d1SSam Leffler 151c740ae4bSPoul-Henning Kamp if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { 152c740ae4bSPoul-Henning Kamp int error; 153c740ae4bSPoul-Henning Kamp 154c740ae4bSPoul-Henning Kamp if (sw->sw_kschedule) 155c740ae4bSPoul-Henning Kamp exf->zerokey(&(sw->sw_kschedule)); 156c740ae4bSPoul-Henning Kamp error = exf->setkey(&sw->sw_kschedule, 157c740ae4bSPoul-Henning Kamp crd->crd_key, crd->crd_klen / 8); 158c740ae4bSPoul-Henning Kamp if (error) 159c740ae4bSPoul-Henning Kamp return (error); 160c740ae4bSPoul-Henning Kamp } 161091d81d1SSam Leffler ivp = iv; 162091d81d1SSam Leffler 163091d81d1SSam Leffler if (outtype == CRYPTO_BUF_CONTIG) { 164091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 165091d81d1SSam Leffler for (i = crd->crd_skip; 166091d81d1SSam Leffler i < crd->crd_skip + crd->crd_len; i += blks) { 167091d81d1SSam Leffler /* XOR with the IV/previous block, as appropriate. */ 168091d81d1SSam Leffler if (i == crd->crd_skip) 169091d81d1SSam Leffler for (k = 0; k < blks; k++) 170091d81d1SSam Leffler buf[i + k] ^= ivp[k]; 171091d81d1SSam Leffler else 172091d81d1SSam Leffler for (k = 0; k < blks; k++) 173091d81d1SSam Leffler buf[i + k] ^= buf[i + k - blks]; 174091d81d1SSam Leffler exf->encrypt(sw->sw_kschedule, buf + i); 175091d81d1SSam Leffler } 176091d81d1SSam Leffler } else { /* Decrypt */ 177091d81d1SSam Leffler /* 178091d81d1SSam Leffler * Start at the end, so we don't need to keep the encrypted 179091d81d1SSam Leffler * block as the IV for the next block. 180091d81d1SSam Leffler */ 181091d81d1SSam Leffler for (i = crd->crd_skip + crd->crd_len - blks; 182091d81d1SSam Leffler i >= crd->crd_skip; i -= blks) { 183091d81d1SSam Leffler exf->decrypt(sw->sw_kschedule, buf + i); 184091d81d1SSam Leffler 185091d81d1SSam Leffler /* XOR with the IV/previous block, as appropriate */ 186091d81d1SSam Leffler if (i == crd->crd_skip) 187091d81d1SSam Leffler for (k = 0; k < blks; k++) 188091d81d1SSam Leffler buf[i + k] ^= ivp[k]; 189091d81d1SSam Leffler else 190091d81d1SSam Leffler for (k = 0; k < blks; k++) 191091d81d1SSam Leffler buf[i + k] ^= buf[i + k - blks]; 192091d81d1SSam Leffler } 193091d81d1SSam Leffler } 194091d81d1SSam Leffler 195091d81d1SSam Leffler return 0; 196091d81d1SSam Leffler } else if (outtype == CRYPTO_BUF_MBUF) { 197091d81d1SSam Leffler struct mbuf *m = (struct mbuf *) buf; 198091d81d1SSam Leffler 199091d81d1SSam Leffler /* Find beginning of data */ 200091d81d1SSam Leffler m = m_getptr(m, crd->crd_skip, &k); 201091d81d1SSam Leffler if (m == NULL) 202091d81d1SSam Leffler return EINVAL; 203091d81d1SSam Leffler 204091d81d1SSam Leffler i = crd->crd_len; 205091d81d1SSam Leffler 206091d81d1SSam Leffler while (i > 0) { 207091d81d1SSam Leffler /* 208091d81d1SSam Leffler * If there's insufficient data at the end of 209091d81d1SSam Leffler * an mbuf, we have to do some copying. 210091d81d1SSam Leffler */ 211091d81d1SSam Leffler if (m->m_len < k + blks && m->m_len != k) { 212091d81d1SSam Leffler m_copydata(m, k, blks, blk); 213091d81d1SSam Leffler 214091d81d1SSam Leffler /* Actual encryption/decryption */ 215091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 216091d81d1SSam Leffler /* XOR with previous block */ 217091d81d1SSam Leffler for (j = 0; j < blks; j++) 218091d81d1SSam Leffler blk[j] ^= ivp[j]; 219091d81d1SSam Leffler 220091d81d1SSam Leffler exf->encrypt(sw->sw_kschedule, blk); 221091d81d1SSam Leffler 222091d81d1SSam Leffler /* 223091d81d1SSam Leffler * Keep encrypted block for XOR'ing 224091d81d1SSam Leffler * with next block 225091d81d1SSam Leffler */ 226091d81d1SSam Leffler bcopy(blk, iv, blks); 227091d81d1SSam Leffler ivp = iv; 228091d81d1SSam Leffler } else { /* decrypt */ 229091d81d1SSam Leffler /* 230091d81d1SSam Leffler * Keep encrypted block for XOR'ing 231091d81d1SSam Leffler * with next block 232091d81d1SSam Leffler */ 233091d81d1SSam Leffler if (ivp == iv) 234091d81d1SSam Leffler bcopy(blk, piv, blks); 235091d81d1SSam Leffler else 236091d81d1SSam Leffler bcopy(blk, iv, blks); 237091d81d1SSam Leffler 238091d81d1SSam Leffler exf->decrypt(sw->sw_kschedule, blk); 239091d81d1SSam Leffler 240091d81d1SSam Leffler /* XOR with previous block */ 241091d81d1SSam Leffler for (j = 0; j < blks; j++) 242091d81d1SSam Leffler blk[j] ^= ivp[j]; 243091d81d1SSam Leffler 244091d81d1SSam Leffler if (ivp == iv) 245091d81d1SSam Leffler bcopy(piv, iv, blks); 246091d81d1SSam Leffler else 247091d81d1SSam Leffler ivp = iv; 248091d81d1SSam Leffler } 249091d81d1SSam Leffler 250091d81d1SSam Leffler /* Copy back decrypted block */ 251091d81d1SSam Leffler m_copyback(m, k, blks, blk); 252091d81d1SSam Leffler 253091d81d1SSam Leffler /* Advance pointer */ 254091d81d1SSam Leffler m = m_getptr(m, k + blks, &k); 255091d81d1SSam Leffler if (m == NULL) 256091d81d1SSam Leffler return EINVAL; 257091d81d1SSam Leffler 258091d81d1SSam Leffler i -= blks; 259091d81d1SSam Leffler 260091d81d1SSam Leffler /* Could be done... */ 261091d81d1SSam Leffler if (i == 0) 262091d81d1SSam Leffler break; 263091d81d1SSam Leffler } 264091d81d1SSam Leffler 265091d81d1SSam Leffler /* Skip possibly empty mbufs */ 266091d81d1SSam Leffler if (k == m->m_len) { 267091d81d1SSam Leffler for (m = m->m_next; m && m->m_len == 0; 268091d81d1SSam Leffler m = m->m_next) 269091d81d1SSam Leffler ; 270091d81d1SSam Leffler k = 0; 271091d81d1SSam Leffler } 272091d81d1SSam Leffler 273091d81d1SSam Leffler /* Sanity check */ 274091d81d1SSam Leffler if (m == NULL) 275091d81d1SSam Leffler return EINVAL; 276091d81d1SSam Leffler 277091d81d1SSam Leffler /* 278091d81d1SSam Leffler * Warning: idat may point to garbage here, but 279091d81d1SSam Leffler * we only use it in the while() loop, only if 280091d81d1SSam Leffler * there are indeed enough data. 281091d81d1SSam Leffler */ 282091d81d1SSam Leffler idat = mtod(m, unsigned char *) + k; 283091d81d1SSam Leffler 284091d81d1SSam Leffler while (m->m_len >= k + blks && i > 0) { 285091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 286091d81d1SSam Leffler /* XOR with previous block/IV */ 287091d81d1SSam Leffler for (j = 0; j < blks; j++) 288091d81d1SSam Leffler idat[j] ^= ivp[j]; 289091d81d1SSam Leffler 290091d81d1SSam Leffler exf->encrypt(sw->sw_kschedule, idat); 291091d81d1SSam Leffler ivp = idat; 292091d81d1SSam Leffler } else { /* decrypt */ 293091d81d1SSam Leffler /* 294091d81d1SSam Leffler * Keep encrypted block to be used 295091d81d1SSam Leffler * in next block's processing. 296091d81d1SSam Leffler */ 297091d81d1SSam Leffler if (ivp == iv) 298091d81d1SSam Leffler bcopy(idat, piv, blks); 299091d81d1SSam Leffler else 300091d81d1SSam Leffler bcopy(idat, iv, blks); 301091d81d1SSam Leffler 302091d81d1SSam Leffler exf->decrypt(sw->sw_kschedule, idat); 303091d81d1SSam Leffler 304091d81d1SSam Leffler /* XOR with previous block/IV */ 305091d81d1SSam Leffler for (j = 0; j < blks; j++) 306091d81d1SSam Leffler idat[j] ^= ivp[j]; 307091d81d1SSam Leffler 308091d81d1SSam Leffler if (ivp == iv) 309091d81d1SSam Leffler bcopy(piv, iv, blks); 310091d81d1SSam Leffler else 311091d81d1SSam Leffler ivp = iv; 312091d81d1SSam Leffler } 313091d81d1SSam Leffler 314091d81d1SSam Leffler idat += blks; 315091d81d1SSam Leffler k += blks; 316091d81d1SSam Leffler i -= blks; 317091d81d1SSam Leffler } 318091d81d1SSam Leffler } 319091d81d1SSam Leffler 320091d81d1SSam Leffler return 0; /* Done with mbuf encryption/decryption */ 321091d81d1SSam Leffler } else if (outtype == CRYPTO_BUF_IOV) { 322091d81d1SSam Leffler struct uio *uio = (struct uio *) buf; 323091d81d1SSam Leffler struct iovec *iov; 324091d81d1SSam Leffler 325091d81d1SSam Leffler /* Find beginning of data */ 326091d81d1SSam Leffler iov = cuio_getptr(uio, crd->crd_skip, &k); 327091d81d1SSam Leffler if (iov == NULL) 328091d81d1SSam Leffler return EINVAL; 329091d81d1SSam Leffler 330091d81d1SSam Leffler i = crd->crd_len; 331091d81d1SSam Leffler 332091d81d1SSam Leffler while (i > 0) { 333091d81d1SSam Leffler /* 334091d81d1SSam Leffler * If there's insufficient data at the end of 335091d81d1SSam Leffler * an iovec, we have to do some copying. 336091d81d1SSam Leffler */ 337091d81d1SSam Leffler if (iov->iov_len < k + blks && iov->iov_len != k) { 338091d81d1SSam Leffler cuio_copydata(uio, k, blks, blk); 339091d81d1SSam Leffler 340091d81d1SSam Leffler /* Actual encryption/decryption */ 341091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 342091d81d1SSam Leffler /* XOR with previous block */ 343091d81d1SSam Leffler for (j = 0; j < blks; j++) 344091d81d1SSam Leffler blk[j] ^= ivp[j]; 345091d81d1SSam Leffler 346091d81d1SSam Leffler exf->encrypt(sw->sw_kschedule, blk); 347091d81d1SSam Leffler 348091d81d1SSam Leffler /* 349091d81d1SSam Leffler * Keep encrypted block for XOR'ing 350091d81d1SSam Leffler * with next block 351091d81d1SSam Leffler */ 352091d81d1SSam Leffler bcopy(blk, iv, blks); 353091d81d1SSam Leffler ivp = iv; 354091d81d1SSam Leffler } else { /* decrypt */ 355091d81d1SSam Leffler /* 356091d81d1SSam Leffler * Keep encrypted block for XOR'ing 357091d81d1SSam Leffler * with next block 358091d81d1SSam Leffler */ 359091d81d1SSam Leffler if (ivp == iv) 360091d81d1SSam Leffler bcopy(blk, piv, blks); 361091d81d1SSam Leffler else 362091d81d1SSam Leffler bcopy(blk, iv, blks); 363091d81d1SSam Leffler 364091d81d1SSam Leffler exf->decrypt(sw->sw_kschedule, blk); 365091d81d1SSam Leffler 366091d81d1SSam Leffler /* XOR with previous block */ 367091d81d1SSam Leffler for (j = 0; j < blks; j++) 368091d81d1SSam Leffler blk[j] ^= ivp[j]; 369091d81d1SSam Leffler 370091d81d1SSam Leffler if (ivp == iv) 371091d81d1SSam Leffler bcopy(piv, iv, blks); 372091d81d1SSam Leffler else 373091d81d1SSam Leffler ivp = iv; 374091d81d1SSam Leffler } 375091d81d1SSam Leffler 376091d81d1SSam Leffler /* Copy back decrypted block */ 377091d81d1SSam Leffler cuio_copyback(uio, k, blks, blk); 378091d81d1SSam Leffler 379091d81d1SSam Leffler /* Advance pointer */ 380091d81d1SSam Leffler iov = cuio_getptr(uio, k + blks, &k); 381091d81d1SSam Leffler if (iov == NULL) 382091d81d1SSam Leffler return EINVAL; 383091d81d1SSam Leffler 384091d81d1SSam Leffler i -= blks; 385091d81d1SSam Leffler 386091d81d1SSam Leffler /* Could be done... */ 387091d81d1SSam Leffler if (i == 0) 388091d81d1SSam Leffler break; 389091d81d1SSam Leffler } 390091d81d1SSam Leffler 391091d81d1SSam Leffler /* 392091d81d1SSam Leffler * Warning: idat may point to garbage here, but 393091d81d1SSam Leffler * we only use it in the while() loop, only if 394091d81d1SSam Leffler * there are indeed enough data. 395091d81d1SSam Leffler */ 3962b7f24d2SMike Barcroft idat = (char *)iov->iov_base + k; 397091d81d1SSam Leffler 398091d81d1SSam Leffler while (iov->iov_len >= k + blks && i > 0) { 399091d81d1SSam Leffler if (crd->crd_flags & CRD_F_ENCRYPT) { 400091d81d1SSam Leffler /* XOR with previous block/IV */ 401091d81d1SSam Leffler for (j = 0; j < blks; j++) 402091d81d1SSam Leffler idat[j] ^= ivp[j]; 403091d81d1SSam Leffler 404091d81d1SSam Leffler exf->encrypt(sw->sw_kschedule, idat); 405091d81d1SSam Leffler ivp = idat; 406091d81d1SSam Leffler } else { /* decrypt */ 407091d81d1SSam Leffler /* 408091d81d1SSam Leffler * Keep encrypted block to be used 409091d81d1SSam Leffler * in next block's processing. 410091d81d1SSam Leffler */ 411091d81d1SSam Leffler if (ivp == iv) 412091d81d1SSam Leffler bcopy(idat, piv, blks); 413091d81d1SSam Leffler else 414091d81d1SSam Leffler bcopy(idat, iv, blks); 415091d81d1SSam Leffler 416091d81d1SSam Leffler exf->decrypt(sw->sw_kschedule, idat); 417091d81d1SSam Leffler 418091d81d1SSam Leffler /* XOR with previous block/IV */ 419091d81d1SSam Leffler for (j = 0; j < blks; j++) 420091d81d1SSam Leffler idat[j] ^= ivp[j]; 421091d81d1SSam Leffler 422091d81d1SSam Leffler if (ivp == iv) 423091d81d1SSam Leffler bcopy(piv, iv, blks); 424091d81d1SSam Leffler else 425091d81d1SSam Leffler ivp = iv; 426091d81d1SSam Leffler } 427091d81d1SSam Leffler 428091d81d1SSam Leffler idat += blks; 429091d81d1SSam Leffler k += blks; 430091d81d1SSam Leffler i -= blks; 431091d81d1SSam Leffler } 432091d81d1SSam Leffler } 433091d81d1SSam Leffler 434091d81d1SSam Leffler return 0; /* Done with mbuf encryption/decryption */ 435091d81d1SSam Leffler } 436091d81d1SSam Leffler 437091d81d1SSam Leffler /* Unreachable */ 438091d81d1SSam Leffler return EINVAL; 439091d81d1SSam Leffler } 440091d81d1SSam Leffler 441091d81d1SSam Leffler /* 442091d81d1SSam Leffler * Compute keyed-hash authenticator. 443091d81d1SSam Leffler */ 444091d81d1SSam Leffler static int 445091d81d1SSam Leffler swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd, 446091d81d1SSam Leffler struct swcr_data *sw, caddr_t buf, int outtype) 447091d81d1SSam Leffler { 448091d81d1SSam Leffler unsigned char aalg[AALG_MAX_RESULT_LEN]; 449091d81d1SSam Leffler struct auth_hash *axf; 450091d81d1SSam Leffler union authctx ctx; 451091d81d1SSam Leffler int err; 452091d81d1SSam Leffler 453091d81d1SSam Leffler if (sw->sw_ictx == 0) 454091d81d1SSam Leffler return EINVAL; 455091d81d1SSam Leffler 456091d81d1SSam Leffler axf = sw->sw_axf; 457091d81d1SSam Leffler 458091d81d1SSam Leffler bcopy(sw->sw_ictx, &ctx, axf->ctxsize); 459091d81d1SSam Leffler 460091d81d1SSam Leffler switch (outtype) { 461091d81d1SSam Leffler case CRYPTO_BUF_CONTIG: 462091d81d1SSam Leffler axf->Update(&ctx, buf + crd->crd_skip, crd->crd_len); 463091d81d1SSam Leffler break; 464091d81d1SSam Leffler case CRYPTO_BUF_MBUF: 465091d81d1SSam Leffler err = m_apply((struct mbuf *) buf, crd->crd_skip, crd->crd_len, 46654065297SBruce M Simpson (int (*)(void *, void *, unsigned int)) axf->Update, 467091d81d1SSam Leffler (caddr_t) &ctx); 468091d81d1SSam Leffler if (err) 469091d81d1SSam Leffler return err; 470091d81d1SSam Leffler break; 471091d81d1SSam Leffler case CRYPTO_BUF_IOV: 472091d81d1SSam Leffler default: 473091d81d1SSam Leffler return EINVAL; 474091d81d1SSam Leffler } 475091d81d1SSam Leffler 476091d81d1SSam Leffler switch (sw->sw_alg) { 477091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 478091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 479091d81d1SSam Leffler case CRYPTO_SHA2_HMAC: 480091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 481091d81d1SSam Leffler if (sw->sw_octx == NULL) 482091d81d1SSam Leffler return EINVAL; 483091d81d1SSam Leffler 484091d81d1SSam Leffler axf->Final(aalg, &ctx); 485091d81d1SSam Leffler bcopy(sw->sw_octx, &ctx, axf->ctxsize); 486091d81d1SSam Leffler axf->Update(&ctx, aalg, axf->hashsize); 487091d81d1SSam Leffler axf->Final(aalg, &ctx); 488091d81d1SSam Leffler break; 489091d81d1SSam Leffler 490091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 491091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 492091d81d1SSam Leffler if (sw->sw_octx == NULL) 493091d81d1SSam Leffler return EINVAL; 494091d81d1SSam Leffler 495091d81d1SSam Leffler axf->Update(&ctx, sw->sw_octx, sw->sw_klen); 496091d81d1SSam Leffler axf->Final(aalg, &ctx); 497091d81d1SSam Leffler break; 498091d81d1SSam Leffler 499091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 500091d81d1SSam Leffler axf->Final(aalg, &ctx); 501091d81d1SSam Leffler break; 502091d81d1SSam Leffler } 503091d81d1SSam Leffler 504091d81d1SSam Leffler /* Inject the authentication data */ 505091d81d1SSam Leffler if (outtype == CRYPTO_BUF_CONTIG) 506091d81d1SSam Leffler bcopy(aalg, buf + crd->crd_inject, axf->authsize); 507091d81d1SSam Leffler else 508091d81d1SSam Leffler m_copyback((struct mbuf *) buf, crd->crd_inject, 509091d81d1SSam Leffler axf->authsize, aalg); 510091d81d1SSam Leffler return 0; 511091d81d1SSam Leffler } 512091d81d1SSam Leffler 513091d81d1SSam Leffler /* 514091d81d1SSam Leffler * Apply a compression/decompression algorithm 515091d81d1SSam Leffler */ 516091d81d1SSam Leffler static int 517091d81d1SSam Leffler swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw, 518091d81d1SSam Leffler caddr_t buf, int outtype) 519091d81d1SSam Leffler { 520091d81d1SSam Leffler u_int8_t *data, *out; 521091d81d1SSam Leffler struct comp_algo *cxf; 522091d81d1SSam Leffler int adj; 523091d81d1SSam Leffler u_int32_t result; 524091d81d1SSam Leffler 525091d81d1SSam Leffler cxf = sw->sw_cxf; 526091d81d1SSam Leffler 527091d81d1SSam Leffler /* We must handle the whole buffer of data in one time 528091d81d1SSam Leffler * then if there is not all the data in the mbuf, we must 529091d81d1SSam Leffler * copy in a buffer. 530091d81d1SSam Leffler */ 531091d81d1SSam Leffler 532091d81d1SSam Leffler MALLOC(data, u_int8_t *, crd->crd_len, M_CRYPTO_DATA, M_NOWAIT); 533091d81d1SSam Leffler if (data == NULL) 534091d81d1SSam Leffler return (EINVAL); 535091d81d1SSam Leffler COPYDATA(outtype, buf, crd->crd_skip, crd->crd_len, data); 536091d81d1SSam Leffler 537091d81d1SSam Leffler if (crd->crd_flags & CRD_F_COMP) 538091d81d1SSam Leffler result = cxf->compress(data, crd->crd_len, &out); 539091d81d1SSam Leffler else 540091d81d1SSam Leffler result = cxf->decompress(data, crd->crd_len, &out); 541091d81d1SSam Leffler 542091d81d1SSam Leffler FREE(data, M_CRYPTO_DATA); 543091d81d1SSam Leffler if (result == 0) 544091d81d1SSam Leffler return EINVAL; 545091d81d1SSam Leffler 546091d81d1SSam Leffler /* Copy back the (de)compressed data. m_copyback is 547091d81d1SSam Leffler * extending the mbuf as necessary. 548091d81d1SSam Leffler */ 549091d81d1SSam Leffler sw->sw_size = result; 550091d81d1SSam Leffler /* Check the compressed size when doing compression */ 551091d81d1SSam Leffler if (crd->crd_flags & CRD_F_COMP) { 552091d81d1SSam Leffler if (result > crd->crd_len) { 553091d81d1SSam Leffler /* Compression was useless, we lost time */ 554091d81d1SSam Leffler FREE(out, M_CRYPTO_DATA); 555091d81d1SSam Leffler return 0; 556091d81d1SSam Leffler } 557091d81d1SSam Leffler } 558091d81d1SSam Leffler 559091d81d1SSam Leffler COPYBACK(outtype, buf, crd->crd_skip, result, out); 560091d81d1SSam Leffler if (result < crd->crd_len) { 561091d81d1SSam Leffler adj = result - crd->crd_len; 562091d81d1SSam Leffler if (outtype == CRYPTO_BUF_MBUF) { 563091d81d1SSam Leffler adj = result - crd->crd_len; 564091d81d1SSam Leffler m_adj((struct mbuf *)buf, adj); 565091d81d1SSam Leffler } else { 566091d81d1SSam Leffler struct uio *uio = (struct uio *)buf; 567091d81d1SSam Leffler int ind; 568091d81d1SSam Leffler 569091d81d1SSam Leffler adj = crd->crd_len - result; 570091d81d1SSam Leffler ind = uio->uio_iovcnt - 1; 571091d81d1SSam Leffler 572091d81d1SSam Leffler while (adj > 0 && ind >= 0) { 573091d81d1SSam Leffler if (adj < uio->uio_iov[ind].iov_len) { 574091d81d1SSam Leffler uio->uio_iov[ind].iov_len -= adj; 575091d81d1SSam Leffler break; 576091d81d1SSam Leffler } 577091d81d1SSam Leffler 578091d81d1SSam Leffler adj -= uio->uio_iov[ind].iov_len; 579091d81d1SSam Leffler uio->uio_iov[ind].iov_len = 0; 580091d81d1SSam Leffler ind--; 581091d81d1SSam Leffler uio->uio_iovcnt--; 582091d81d1SSam Leffler } 583091d81d1SSam Leffler } 584091d81d1SSam Leffler } 585091d81d1SSam Leffler FREE(out, M_CRYPTO_DATA); 586091d81d1SSam Leffler return 0; 587091d81d1SSam Leffler } 588091d81d1SSam Leffler 589091d81d1SSam Leffler /* 590091d81d1SSam Leffler * Generate a new software session. 591091d81d1SSam Leffler */ 592091d81d1SSam Leffler static int 593091d81d1SSam Leffler swcr_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri) 594091d81d1SSam Leffler { 595091d81d1SSam Leffler struct swcr_data **swd; 596091d81d1SSam Leffler struct auth_hash *axf; 597091d81d1SSam Leffler struct enc_xform *txf; 598091d81d1SSam Leffler struct comp_algo *cxf; 599091d81d1SSam Leffler u_int32_t i; 600091d81d1SSam Leffler int k, error; 601091d81d1SSam Leffler 602091d81d1SSam Leffler if (sid == NULL || cri == NULL) 603091d81d1SSam Leffler return EINVAL; 604091d81d1SSam Leffler 605091d81d1SSam Leffler if (swcr_sessions) { 606091d81d1SSam Leffler for (i = 1; i < swcr_sesnum; i++) 607091d81d1SSam Leffler if (swcr_sessions[i] == NULL) 608091d81d1SSam Leffler break; 609091d81d1SSam Leffler } else 610091d81d1SSam Leffler i = 1; /* NB: to silence compiler warning */ 611091d81d1SSam Leffler 612091d81d1SSam Leffler if (swcr_sessions == NULL || i == swcr_sesnum) { 613091d81d1SSam Leffler if (swcr_sessions == NULL) { 614091d81d1SSam Leffler i = 1; /* We leave swcr_sessions[0] empty */ 615091d81d1SSam Leffler swcr_sesnum = CRYPTO_SW_SESSIONS; 616091d81d1SSam Leffler } else 617091d81d1SSam Leffler swcr_sesnum *= 2; 618091d81d1SSam Leffler 619091d81d1SSam Leffler swd = malloc(swcr_sesnum * sizeof(struct swcr_data *), 620091d81d1SSam Leffler M_CRYPTO_DATA, M_NOWAIT|M_ZERO); 621091d81d1SSam Leffler if (swd == NULL) { 622091d81d1SSam Leffler /* Reset session number */ 623091d81d1SSam Leffler if (swcr_sesnum == CRYPTO_SW_SESSIONS) 624091d81d1SSam Leffler swcr_sesnum = 0; 625091d81d1SSam Leffler else 626091d81d1SSam Leffler swcr_sesnum /= 2; 627091d81d1SSam Leffler return ENOBUFS; 628091d81d1SSam Leffler } 629091d81d1SSam Leffler 630091d81d1SSam Leffler /* Copy existing sessions */ 631091d81d1SSam Leffler if (swcr_sessions) { 632091d81d1SSam Leffler bcopy(swcr_sessions, swd, 633091d81d1SSam Leffler (swcr_sesnum / 2) * sizeof(struct swcr_data *)); 634091d81d1SSam Leffler free(swcr_sessions, M_CRYPTO_DATA); 635091d81d1SSam Leffler } 636091d81d1SSam Leffler 637091d81d1SSam Leffler swcr_sessions = swd; 638091d81d1SSam Leffler } 639091d81d1SSam Leffler 640091d81d1SSam Leffler swd = &swcr_sessions[i]; 641091d81d1SSam Leffler *sid = i; 642091d81d1SSam Leffler 643091d81d1SSam Leffler while (cri) { 644091d81d1SSam Leffler MALLOC(*swd, struct swcr_data *, sizeof(struct swcr_data), 645091d81d1SSam Leffler M_CRYPTO_DATA, M_NOWAIT|M_ZERO); 646091d81d1SSam Leffler if (*swd == NULL) { 647091d81d1SSam Leffler swcr_freesession(NULL, i); 648091d81d1SSam Leffler return ENOBUFS; 649091d81d1SSam Leffler } 650091d81d1SSam Leffler 651091d81d1SSam Leffler switch (cri->cri_alg) { 652091d81d1SSam Leffler case CRYPTO_DES_CBC: 653091d81d1SSam Leffler txf = &enc_xform_des; 654091d81d1SSam Leffler goto enccommon; 655091d81d1SSam Leffler case CRYPTO_3DES_CBC: 656091d81d1SSam Leffler txf = &enc_xform_3des; 657091d81d1SSam Leffler goto enccommon; 658091d81d1SSam Leffler case CRYPTO_BLF_CBC: 659091d81d1SSam Leffler txf = &enc_xform_blf; 660091d81d1SSam Leffler goto enccommon; 661091d81d1SSam Leffler case CRYPTO_CAST_CBC: 662091d81d1SSam Leffler txf = &enc_xform_cast5; 663091d81d1SSam Leffler goto enccommon; 664091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 665091d81d1SSam Leffler txf = &enc_xform_skipjack; 666091d81d1SSam Leffler goto enccommon; 667091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 668091d81d1SSam Leffler txf = &enc_xform_rijndael128; 669091d81d1SSam Leffler goto enccommon; 670091d81d1SSam Leffler case CRYPTO_NULL_CBC: 671091d81d1SSam Leffler txf = &enc_xform_null; 672091d81d1SSam Leffler goto enccommon; 673091d81d1SSam Leffler enccommon: 674091d81d1SSam Leffler error = txf->setkey(&((*swd)->sw_kschedule), 675091d81d1SSam Leffler cri->cri_key, cri->cri_klen / 8); 676091d81d1SSam Leffler if (error) { 677091d81d1SSam Leffler swcr_freesession(NULL, i); 678091d81d1SSam Leffler return error; 679091d81d1SSam Leffler } 680091d81d1SSam Leffler (*swd)->sw_exf = txf; 681091d81d1SSam Leffler break; 682091d81d1SSam Leffler 683091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 684091d81d1SSam Leffler axf = &auth_hash_hmac_md5_96; 685091d81d1SSam Leffler goto authcommon; 686091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 687091d81d1SSam Leffler axf = &auth_hash_hmac_sha1_96; 688091d81d1SSam Leffler goto authcommon; 689091d81d1SSam Leffler case CRYPTO_SHA2_HMAC: 690091d81d1SSam Leffler if (cri->cri_klen == 256) 691091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_256; 692091d81d1SSam Leffler else if (cri->cri_klen == 384) 693091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_384; 694091d81d1SSam Leffler else if (cri->cri_klen == 512) 695091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_512; 696091d81d1SSam Leffler else { 697091d81d1SSam Leffler swcr_freesession(NULL, i); 698091d81d1SSam Leffler return EINVAL; 699091d81d1SSam Leffler } 700091d81d1SSam Leffler goto authcommon; 701091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 702091d81d1SSam Leffler axf = &auth_hash_null; 703091d81d1SSam Leffler goto authcommon; 704091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 705091d81d1SSam Leffler axf = &auth_hash_hmac_ripemd_160_96; 706091d81d1SSam Leffler authcommon: 707091d81d1SSam Leffler (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 708091d81d1SSam Leffler M_NOWAIT); 709091d81d1SSam Leffler if ((*swd)->sw_ictx == NULL) { 710091d81d1SSam Leffler swcr_freesession(NULL, i); 711091d81d1SSam Leffler return ENOBUFS; 712091d81d1SSam Leffler } 713091d81d1SSam Leffler 714091d81d1SSam Leffler (*swd)->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA, 715091d81d1SSam Leffler M_NOWAIT); 716091d81d1SSam Leffler if ((*swd)->sw_octx == NULL) { 717091d81d1SSam Leffler swcr_freesession(NULL, i); 718091d81d1SSam Leffler return ENOBUFS; 719091d81d1SSam Leffler } 720091d81d1SSam Leffler 721091d81d1SSam Leffler for (k = 0; k < cri->cri_klen / 8; k++) 722091d81d1SSam Leffler cri->cri_key[k] ^= HMAC_IPAD_VAL; 723091d81d1SSam Leffler 724091d81d1SSam Leffler axf->Init((*swd)->sw_ictx); 725091d81d1SSam Leffler axf->Update((*swd)->sw_ictx, cri->cri_key, 726091d81d1SSam Leffler cri->cri_klen / 8); 727091d81d1SSam Leffler axf->Update((*swd)->sw_ictx, hmac_ipad_buffer, 728091d81d1SSam Leffler HMAC_BLOCK_LEN - (cri->cri_klen / 8)); 729091d81d1SSam Leffler 730091d81d1SSam Leffler for (k = 0; k < cri->cri_klen / 8; k++) 731091d81d1SSam Leffler cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); 732091d81d1SSam Leffler 733091d81d1SSam Leffler axf->Init((*swd)->sw_octx); 734091d81d1SSam Leffler axf->Update((*swd)->sw_octx, cri->cri_key, 735091d81d1SSam Leffler cri->cri_klen / 8); 736091d81d1SSam Leffler axf->Update((*swd)->sw_octx, hmac_opad_buffer, 737091d81d1SSam Leffler HMAC_BLOCK_LEN - (cri->cri_klen / 8)); 738091d81d1SSam Leffler 739091d81d1SSam Leffler for (k = 0; k < cri->cri_klen / 8; k++) 740091d81d1SSam Leffler cri->cri_key[k] ^= HMAC_OPAD_VAL; 741091d81d1SSam Leffler (*swd)->sw_axf = axf; 742091d81d1SSam Leffler break; 743091d81d1SSam Leffler 744091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 745091d81d1SSam Leffler axf = &auth_hash_key_md5; 746091d81d1SSam Leffler goto auth2common; 747091d81d1SSam Leffler 748091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 749091d81d1SSam Leffler axf = &auth_hash_key_sha1; 750091d81d1SSam Leffler auth2common: 751091d81d1SSam Leffler (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 752091d81d1SSam Leffler M_NOWAIT); 753091d81d1SSam Leffler if ((*swd)->sw_ictx == NULL) { 754091d81d1SSam Leffler swcr_freesession(NULL, i); 755091d81d1SSam Leffler return ENOBUFS; 756091d81d1SSam Leffler } 757091d81d1SSam Leffler 758091d81d1SSam Leffler /* Store the key so we can "append" it to the payload */ 759091d81d1SSam Leffler (*swd)->sw_octx = malloc(cri->cri_klen / 8, M_CRYPTO_DATA, 760091d81d1SSam Leffler M_NOWAIT); 761091d81d1SSam Leffler if ((*swd)->sw_octx == NULL) { 762091d81d1SSam Leffler swcr_freesession(NULL, i); 763091d81d1SSam Leffler return ENOBUFS; 764091d81d1SSam Leffler } 765091d81d1SSam Leffler 766091d81d1SSam Leffler (*swd)->sw_klen = cri->cri_klen / 8; 767091d81d1SSam Leffler bcopy(cri->cri_key, (*swd)->sw_octx, cri->cri_klen / 8); 768091d81d1SSam Leffler axf->Init((*swd)->sw_ictx); 769091d81d1SSam Leffler axf->Update((*swd)->sw_ictx, cri->cri_key, 770091d81d1SSam Leffler cri->cri_klen / 8); 771091d81d1SSam Leffler axf->Final(NULL, (*swd)->sw_ictx); 772091d81d1SSam Leffler (*swd)->sw_axf = axf; 773091d81d1SSam Leffler break; 774091d81d1SSam Leffler #ifdef notdef 775091d81d1SSam Leffler case CRYPTO_MD5: 776091d81d1SSam Leffler axf = &auth_hash_md5; 777091d81d1SSam Leffler goto auth3common; 778091d81d1SSam Leffler 779091d81d1SSam Leffler case CRYPTO_SHA1: 780091d81d1SSam Leffler axf = &auth_hash_sha1; 781091d81d1SSam Leffler auth3common: 782091d81d1SSam Leffler (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 783091d81d1SSam Leffler M_NOWAIT); 784091d81d1SSam Leffler if ((*swd)->sw_ictx == NULL) { 785091d81d1SSam Leffler swcr_freesession(NULL, i); 786091d81d1SSam Leffler return ENOBUFS; 787091d81d1SSam Leffler } 788091d81d1SSam Leffler 789091d81d1SSam Leffler axf->Init((*swd)->sw_ictx); 790091d81d1SSam Leffler (*swd)->sw_axf = axf; 791091d81d1SSam Leffler break; 792091d81d1SSam Leffler #endif 793091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 794091d81d1SSam Leffler cxf = &comp_algo_deflate; 795091d81d1SSam Leffler (*swd)->sw_cxf = cxf; 796091d81d1SSam Leffler break; 797091d81d1SSam Leffler default: 798091d81d1SSam Leffler swcr_freesession(NULL, i); 799091d81d1SSam Leffler return EINVAL; 800091d81d1SSam Leffler } 801091d81d1SSam Leffler 802091d81d1SSam Leffler (*swd)->sw_alg = cri->cri_alg; 803091d81d1SSam Leffler cri = cri->cri_next; 804091d81d1SSam Leffler swd = &((*swd)->sw_next); 805091d81d1SSam Leffler } 806091d81d1SSam Leffler return 0; 807091d81d1SSam Leffler } 808091d81d1SSam Leffler 809091d81d1SSam Leffler /* 810091d81d1SSam Leffler * Free a session. 811091d81d1SSam Leffler */ 812091d81d1SSam Leffler static int 813091d81d1SSam Leffler swcr_freesession(void *arg, u_int64_t tid) 814091d81d1SSam Leffler { 815091d81d1SSam Leffler struct swcr_data *swd; 816091d81d1SSam Leffler struct enc_xform *txf; 817091d81d1SSam Leffler struct auth_hash *axf; 818091d81d1SSam Leffler struct comp_algo *cxf; 81907d0c94aSSam Leffler u_int32_t sid = CRYPTO_SESID2LID(tid); 820091d81d1SSam Leffler 821091d81d1SSam Leffler if (sid > swcr_sesnum || swcr_sessions == NULL || 822091d81d1SSam Leffler swcr_sessions[sid] == NULL) 823091d81d1SSam Leffler return EINVAL; 824091d81d1SSam Leffler 825091d81d1SSam Leffler /* Silently accept and return */ 826091d81d1SSam Leffler if (sid == 0) 827091d81d1SSam Leffler return 0; 828091d81d1SSam Leffler 829091d81d1SSam Leffler while ((swd = swcr_sessions[sid]) != NULL) { 830091d81d1SSam Leffler swcr_sessions[sid] = swd->sw_next; 831091d81d1SSam Leffler 832091d81d1SSam Leffler switch (swd->sw_alg) { 833091d81d1SSam Leffler case CRYPTO_DES_CBC: 834091d81d1SSam Leffler case CRYPTO_3DES_CBC: 835091d81d1SSam Leffler case CRYPTO_BLF_CBC: 836091d81d1SSam Leffler case CRYPTO_CAST_CBC: 837091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 838091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 839091d81d1SSam Leffler case CRYPTO_NULL_CBC: 840091d81d1SSam Leffler txf = swd->sw_exf; 841091d81d1SSam Leffler 842091d81d1SSam Leffler if (swd->sw_kschedule) 843091d81d1SSam Leffler txf->zerokey(&(swd->sw_kschedule)); 844091d81d1SSam Leffler break; 845091d81d1SSam Leffler 846091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 847091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 848091d81d1SSam Leffler case CRYPTO_SHA2_HMAC: 849091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 850091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 851091d81d1SSam Leffler axf = swd->sw_axf; 852091d81d1SSam Leffler 853091d81d1SSam Leffler if (swd->sw_ictx) { 854091d81d1SSam Leffler bzero(swd->sw_ictx, axf->ctxsize); 855091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 856091d81d1SSam Leffler } 857091d81d1SSam Leffler if (swd->sw_octx) { 858091d81d1SSam Leffler bzero(swd->sw_octx, axf->ctxsize); 859091d81d1SSam Leffler free(swd->sw_octx, M_CRYPTO_DATA); 860091d81d1SSam Leffler } 861091d81d1SSam Leffler break; 862091d81d1SSam Leffler 863091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 864091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 865091d81d1SSam Leffler axf = swd->sw_axf; 866091d81d1SSam Leffler 867091d81d1SSam Leffler if (swd->sw_ictx) { 868091d81d1SSam Leffler bzero(swd->sw_ictx, axf->ctxsize); 869091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 870091d81d1SSam Leffler } 871091d81d1SSam Leffler if (swd->sw_octx) { 872091d81d1SSam Leffler bzero(swd->sw_octx, swd->sw_klen); 873091d81d1SSam Leffler free(swd->sw_octx, M_CRYPTO_DATA); 874091d81d1SSam Leffler } 875091d81d1SSam Leffler break; 876091d81d1SSam Leffler 877091d81d1SSam Leffler case CRYPTO_MD5: 878091d81d1SSam Leffler case CRYPTO_SHA1: 879091d81d1SSam Leffler axf = swd->sw_axf; 880091d81d1SSam Leffler 881091d81d1SSam Leffler if (swd->sw_ictx) 882091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 883091d81d1SSam Leffler break; 884091d81d1SSam Leffler 885091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 886091d81d1SSam Leffler cxf = swd->sw_cxf; 887091d81d1SSam Leffler break; 888091d81d1SSam Leffler } 889091d81d1SSam Leffler 890091d81d1SSam Leffler FREE(swd, M_CRYPTO_DATA); 891091d81d1SSam Leffler } 892091d81d1SSam Leffler return 0; 893091d81d1SSam Leffler } 894091d81d1SSam Leffler 895091d81d1SSam Leffler /* 896091d81d1SSam Leffler * Process a software request. 897091d81d1SSam Leffler */ 898091d81d1SSam Leffler static int 899091d81d1SSam Leffler swcr_process(void *arg, struct cryptop *crp, int hint) 900091d81d1SSam Leffler { 901091d81d1SSam Leffler struct cryptodesc *crd; 902091d81d1SSam Leffler struct swcr_data *sw; 903091d81d1SSam Leffler u_int32_t lid; 904091d81d1SSam Leffler int type; 905091d81d1SSam Leffler 906091d81d1SSam Leffler /* Sanity check */ 907091d81d1SSam Leffler if (crp == NULL) 908091d81d1SSam Leffler return EINVAL; 909091d81d1SSam Leffler 910091d81d1SSam Leffler if (crp->crp_desc == NULL || crp->crp_buf == NULL) { 911091d81d1SSam Leffler crp->crp_etype = EINVAL; 912091d81d1SSam Leffler goto done; 913091d81d1SSam Leffler } 914091d81d1SSam Leffler 915091d81d1SSam Leffler lid = crp->crp_sid & 0xffffffff; 916091d81d1SSam Leffler if (lid >= swcr_sesnum || lid == 0 || swcr_sessions[lid] == NULL) { 917091d81d1SSam Leffler crp->crp_etype = ENOENT; 918091d81d1SSam Leffler goto done; 919091d81d1SSam Leffler } 920091d81d1SSam Leffler 921091d81d1SSam Leffler if (crp->crp_flags & CRYPTO_F_IMBUF) { 922091d81d1SSam Leffler type = CRYPTO_BUF_MBUF; 923091d81d1SSam Leffler } else if (crp->crp_flags & CRYPTO_F_IOV) { 924091d81d1SSam Leffler type = CRYPTO_BUF_IOV; 925091d81d1SSam Leffler } else { 926091d81d1SSam Leffler type = CRYPTO_BUF_CONTIG; 927091d81d1SSam Leffler } 928091d81d1SSam Leffler 929091d81d1SSam Leffler /* Go through crypto descriptors, processing as we go */ 930091d81d1SSam Leffler for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 931091d81d1SSam Leffler /* 932091d81d1SSam Leffler * Find the crypto context. 933091d81d1SSam Leffler * 934091d81d1SSam Leffler * XXX Note that the logic here prevents us from having 935091d81d1SSam Leffler * XXX the same algorithm multiple times in a session 936091d81d1SSam Leffler * XXX (or rather, we can but it won't give us the right 937091d81d1SSam Leffler * XXX results). To do that, we'd need some way of differentiating 938091d81d1SSam Leffler * XXX between the various instances of an algorithm (so we can 939091d81d1SSam Leffler * XXX locate the correct crypto context). 940091d81d1SSam Leffler */ 941091d81d1SSam Leffler for (sw = swcr_sessions[lid]; 942091d81d1SSam Leffler sw && sw->sw_alg != crd->crd_alg; 943091d81d1SSam Leffler sw = sw->sw_next) 944091d81d1SSam Leffler ; 945091d81d1SSam Leffler 946091d81d1SSam Leffler /* No such context ? */ 947091d81d1SSam Leffler if (sw == NULL) { 948091d81d1SSam Leffler crp->crp_etype = EINVAL; 949091d81d1SSam Leffler goto done; 950091d81d1SSam Leffler } 951091d81d1SSam Leffler switch (sw->sw_alg) { 952091d81d1SSam Leffler case CRYPTO_DES_CBC: 953091d81d1SSam Leffler case CRYPTO_3DES_CBC: 954091d81d1SSam Leffler case CRYPTO_BLF_CBC: 955091d81d1SSam Leffler case CRYPTO_CAST_CBC: 956091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 957091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 958091d81d1SSam Leffler if ((crp->crp_etype = swcr_encdec(crd, sw, 959091d81d1SSam Leffler crp->crp_buf, type)) != 0) 960091d81d1SSam Leffler goto done; 961091d81d1SSam Leffler break; 962091d81d1SSam Leffler case CRYPTO_NULL_CBC: 963091d81d1SSam Leffler crp->crp_etype = 0; 964091d81d1SSam Leffler break; 965091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 966091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 967091d81d1SSam Leffler case CRYPTO_SHA2_HMAC: 968091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 969091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 970091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 971091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 972091d81d1SSam Leffler case CRYPTO_MD5: 973091d81d1SSam Leffler case CRYPTO_SHA1: 974091d81d1SSam Leffler if ((crp->crp_etype = swcr_authcompute(crp, crd, sw, 975091d81d1SSam Leffler crp->crp_buf, type)) != 0) 976091d81d1SSam Leffler goto done; 977091d81d1SSam Leffler break; 978091d81d1SSam Leffler 979091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 980091d81d1SSam Leffler if ((crp->crp_etype = swcr_compdec(crd, sw, 981091d81d1SSam Leffler crp->crp_buf, type)) != 0) 982091d81d1SSam Leffler goto done; 983091d81d1SSam Leffler else 984091d81d1SSam Leffler crp->crp_olen = (int)sw->sw_size; 985091d81d1SSam Leffler break; 986091d81d1SSam Leffler 987091d81d1SSam Leffler default: 988091d81d1SSam Leffler /* Unknown/unsupported algorithm */ 989091d81d1SSam Leffler crp->crp_etype = EINVAL; 990091d81d1SSam Leffler goto done; 991091d81d1SSam Leffler } 992091d81d1SSam Leffler } 993091d81d1SSam Leffler 994091d81d1SSam Leffler done: 995091d81d1SSam Leffler crypto_done(crp); 996091d81d1SSam Leffler return 0; 997091d81d1SSam Leffler } 998091d81d1SSam Leffler 999091d81d1SSam Leffler /* 1000091d81d1SSam Leffler * Initialize the driver, called from the kernel main(). 1001091d81d1SSam Leffler */ 1002091d81d1SSam Leffler static void 1003091d81d1SSam Leffler swcr_init(void) 1004091d81d1SSam Leffler { 100507d0c94aSSam Leffler swcr_id = crypto_get_driverid(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC); 1006091d81d1SSam Leffler if (swcr_id < 0) 1007091d81d1SSam Leffler panic("Software crypto device cannot initialize!"); 1008091d81d1SSam Leffler crypto_register(swcr_id, CRYPTO_DES_CBC, 1009091d81d1SSam Leffler 0, 0, swcr_newsession, swcr_freesession, swcr_process, NULL); 1010091d81d1SSam Leffler #define REGISTER(alg) \ 1011091d81d1SSam Leffler crypto_register(swcr_id, alg, 0,0,NULL,NULL,NULL,NULL) 1012091d81d1SSam Leffler REGISTER(CRYPTO_3DES_CBC); 1013091d81d1SSam Leffler REGISTER(CRYPTO_BLF_CBC); 1014091d81d1SSam Leffler REGISTER(CRYPTO_CAST_CBC); 1015091d81d1SSam Leffler REGISTER(CRYPTO_SKIPJACK_CBC); 1016091d81d1SSam Leffler REGISTER(CRYPTO_NULL_CBC); 1017091d81d1SSam Leffler REGISTER(CRYPTO_MD5_HMAC); 1018091d81d1SSam Leffler REGISTER(CRYPTO_SHA1_HMAC); 1019091d81d1SSam Leffler REGISTER(CRYPTO_SHA2_HMAC); 1020091d81d1SSam Leffler REGISTER(CRYPTO_RIPEMD160_HMAC); 1021091d81d1SSam Leffler REGISTER(CRYPTO_NULL_HMAC); 1022091d81d1SSam Leffler REGISTER(CRYPTO_MD5_KPDK); 1023091d81d1SSam Leffler REGISTER(CRYPTO_SHA1_KPDK); 1024091d81d1SSam Leffler REGISTER(CRYPTO_MD5); 1025091d81d1SSam Leffler REGISTER(CRYPTO_SHA1); 1026091d81d1SSam Leffler REGISTER(CRYPTO_RIJNDAEL128_CBC); 1027091d81d1SSam Leffler REGISTER(CRYPTO_DEFLATE_COMP); 1028091d81d1SSam Leffler #undef REGISTER 1029091d81d1SSam Leffler } 1030091d81d1SSam Leffler SYSINIT(cryptosoft_init, SI_SUB_PSEUDO, SI_ORDER_ANY, swcr_init, NULL) 1031