xref: /openbsd-src/sys/crypto/cryptosoft.c (revision 0cd0a70e4ce0c8e826455a0a4a676c68b67ec75d)
1*0cd0a70eSpatrick /*	$OpenBSD: cryptosoft.c,v 1.91 2021/10/24 10:26:22 patrick Exp $	*/
2bde475f4Sderaadt 
35b6944e5Sderaadt /*
45b6944e5Sderaadt  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
55b6944e5Sderaadt  *
65b6944e5Sderaadt  * This code was written by Angelos D. Keromytis in Athens, Greece, in
75b6944e5Sderaadt  * February 2000. Network Security Technologies Inc. (NSTI) kindly
85b6944e5Sderaadt  * supported the development of this code.
95b6944e5Sderaadt  *
109d566f6dSangelos  * Copyright (c) 2000, 2001 Angelos D. Keromytis
115b6944e5Sderaadt  *
129d566f6dSangelos  * Permission to use, copy, and modify this software with or without fee
135b6944e5Sderaadt  * is hereby granted, provided that this entire notice is included in
145b6944e5Sderaadt  * all source code copies of any software which is or includes a copy or
155b6944e5Sderaadt  * modification of this software.
165b6944e5Sderaadt  *
175b6944e5Sderaadt  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
185b6944e5Sderaadt  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
195b6944e5Sderaadt  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
205b6944e5Sderaadt  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
215b6944e5Sderaadt  * PURPOSE.
225b6944e5Sderaadt  */
235b6944e5Sderaadt 
245b6944e5Sderaadt #include <sys/param.h>
255b6944e5Sderaadt #include <sys/systm.h>
265b6944e5Sderaadt #include <sys/malloc.h>
275b6944e5Sderaadt #include <sys/mbuf.h>
285b6944e5Sderaadt #include <sys/errno.h>
290f25121dSmillert #include <crypto/md5.h>
305b6944e5Sderaadt #include <crypto/sha1.h>
315b6944e5Sderaadt #include <crypto/rmd160.h>
325b6944e5Sderaadt #include <crypto/cast.h>
3382eb8fdeSderaadt #include <crypto/cryptodev.h>
34aa93ee0aSderaadt #include <crypto/cryptosoft.h>
355b6944e5Sderaadt #include <crypto/xform.h>
365b6944e5Sderaadt 
378688c78cSmarkus const u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN] = {
388688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
398688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
408688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
418688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
428688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
438688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
448688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
458688c78cSmarkus 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
465b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
475b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
485b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
495b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
505b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
515b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
525b6944e5Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
538a4e6689Sderaadt 	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
548a4e6689Sderaadt };
555b6944e5Sderaadt 
568688c78cSmarkus const u_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN] = {
578688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
588688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
598688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
608688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
618688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
628688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
638688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
648688c78cSmarkus 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
655b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
665b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
675b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
685b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
695b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
705b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
715b6944e5Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
728a4e6689Sderaadt 	0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C
738a4e6689Sderaadt };
745b6944e5Sderaadt 
755b6944e5Sderaadt 
76a986bd3bSbluhm struct swcr_list *swcr_sessions = NULL;
775b6944e5Sderaadt u_int32_t swcr_sesnum = 0;
785b6944e5Sderaadt int32_t swcr_id = -1;
795b6944e5Sderaadt 
80f89a9693Sprovos #define COPYBACK(x, a, b, c, d) \
812898430aSderaadt 	do { \
822898430aSderaadt 		if ((x) == CRYPTO_BUF_MBUF) \
832898430aSderaadt 			m_copyback((struct mbuf *)a,b,c,d,M_NOWAIT); \
842898430aSderaadt 		else \
852898430aSderaadt 			cuio_copyback((struct uio *)a,b,c,d); \
862898430aSderaadt 	} while (0)
87f89a9693Sprovos #define COPYDATA(x, a, b, c, d) \
882898430aSderaadt 	do { \
892898430aSderaadt 		if ((x) == CRYPTO_BUF_MBUF) \
902898430aSderaadt 			m_copydata((struct mbuf *)a,b,c,d); \
912898430aSderaadt 		else \
922898430aSderaadt 			cuio_copydata((struct uio *)a,b,c,d); \
932898430aSderaadt 	} while (0)
94f89a9693Sprovos 
955b6944e5Sderaadt /*
965b6944e5Sderaadt  * Apply a symmetric encryption/decryption algorithm.
975b6944e5Sderaadt  */
985b6944e5Sderaadt int
swcr_encdec(struct cryptodesc * crd,struct swcr_data * sw,caddr_t buf,int outtype)995b6944e5Sderaadt swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
1005b6944e5Sderaadt     int outtype)
1015b6944e5Sderaadt {
1025b6944e5Sderaadt 	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
10309b14fccSmarkus 	unsigned char *ivp, *nivp, iv2[EALG_MAX_BLOCK_LEN];
1044d13edafSbluhm 	const struct enc_xform *exf;
1058264d0c5Smarkus 	int i, k, j, blks, ind, count, ivlen;
106f89a9693Sprovos 	struct mbuf *m = NULL;
107f89a9693Sprovos 	struct uio *uio = NULL;
108f89a9693Sprovos 
1095b6944e5Sderaadt 	exf = sw->sw_exf;
1105b6944e5Sderaadt 	blks = exf->blocksize;
1118264d0c5Smarkus 	ivlen = exf->ivsize;
1125b6944e5Sderaadt 
1135b6944e5Sderaadt 	/* Check for non-padded data */
1145b6944e5Sderaadt 	if (crd->crd_len % blks)
1155b6944e5Sderaadt 		return EINVAL;
1165b6944e5Sderaadt 
117f89a9693Sprovos 	if (outtype == CRYPTO_BUF_MBUF)
1185b6944e5Sderaadt 		m = (struct mbuf *) buf;
119f89a9693Sprovos 	else
120f89a9693Sprovos 		uio = (struct uio *) buf;
1215b6944e5Sderaadt 
1225b6944e5Sderaadt 	/* Initialize the IV */
1238a4e6689Sderaadt 	if (crd->crd_flags & CRD_F_ENCRYPT) {
1246ed40079Sangelos 		/* IV explicitly provided ? */
1256ed40079Sangelos 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1268264d0c5Smarkus 			bcopy(crd->crd_iv, iv, ivlen);
127326c7981Smarkus 		else
128780f39a5Sdjm 			arc4random_buf(iv, ivlen);
1295b6944e5Sderaadt 
1306ed40079Sangelos 		/* Do we need to write the IV */
1312898430aSderaadt 		if (!(crd->crd_flags & CRD_F_IV_PRESENT))
1328264d0c5Smarkus 			COPYBACK(outtype, buf, crd->crd_inject, ivlen, iv);
1338a4e6689Sderaadt 
1348a4e6689Sderaadt 	} else {	/* Decryption */
1356ed40079Sangelos 			/* IV explicitly provided ? */
1366ed40079Sangelos 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1378264d0c5Smarkus 			bcopy(crd->crd_iv, iv, ivlen);
1388a4e6689Sderaadt 		else {
139f89a9693Sprovos 			/* Get IV off buf */
1408264d0c5Smarkus 			COPYDATA(outtype, buf, crd->crd_inject, ivlen, iv);
1418a4e6689Sderaadt 		}
1425b6944e5Sderaadt 	}
1435b6944e5Sderaadt 
1445b6944e5Sderaadt 	ivp = iv;
1455b6944e5Sderaadt 
146e2ed96e1Sdjm 	/*
147e2ed96e1Sdjm 	 * xforms that provide a reinit method perform all IV
148e2ed96e1Sdjm 	 * handling themselves.
149e2ed96e1Sdjm 	 */
1508264d0c5Smarkus 	if (exf->reinit)
1518264d0c5Smarkus 		exf->reinit(sw->sw_kschedule, iv);
1528264d0c5Smarkus 
153f89a9693Sprovos 	if (outtype == CRYPTO_BUF_MBUF) {
1545b6944e5Sderaadt 		/* Find beginning of data */
1555b6944e5Sderaadt 		m = m_getptr(m, crd->crd_skip, &k);
1565b6944e5Sderaadt 		if (m == NULL)
1575b6944e5Sderaadt 			return EINVAL;
1585b6944e5Sderaadt 
1595b6944e5Sderaadt 		i = crd->crd_len;
1605b6944e5Sderaadt 
1618a4e6689Sderaadt 		while (i > 0) {
1625b6944e5Sderaadt 			/*
1638a4e6689Sderaadt 			 * If there's insufficient data at the end of
1648a4e6689Sderaadt 			 * an mbuf, we have to do some copying.
1655b6944e5Sderaadt 			 */
1668a4e6689Sderaadt 			if (m->m_len < k + blks && m->m_len != k) {
1675b6944e5Sderaadt 				m_copydata(m, k, blks, blk);
1685b6944e5Sderaadt 
1695b6944e5Sderaadt 				/* Actual encryption/decryption */
1708264d0c5Smarkus 				if (exf->reinit) {
171e2ed96e1Sdjm 					if (crd->crd_flags & CRD_F_ENCRYPT) {
172e2ed96e1Sdjm 						exf->encrypt(sw->sw_kschedule,
173e2ed96e1Sdjm 						    blk);
174e2ed96e1Sdjm 					} else {
175e2ed96e1Sdjm 						exf->decrypt(sw->sw_kschedule,
176e2ed96e1Sdjm 						    blk);
177e2ed96e1Sdjm 					}
1788264d0c5Smarkus 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
1795b6944e5Sderaadt 					/* XOR with previous block */
1805b6944e5Sderaadt 					for (j = 0; j < blks; j++)
1815b6944e5Sderaadt 						blk[j] ^= ivp[j];
1825b6944e5Sderaadt 
1835b6944e5Sderaadt 					exf->encrypt(sw->sw_kschedule, blk);
1845b6944e5Sderaadt 
1858a4e6689Sderaadt 					/*
1868a4e6689Sderaadt 					 * Keep encrypted block for XOR'ing
1878a4e6689Sderaadt 					 * with next block
1888a4e6689Sderaadt 					 */
1895b6944e5Sderaadt 					bcopy(blk, iv, blks);
1905b6944e5Sderaadt 					ivp = iv;
1918a4e6689Sderaadt 				} else {	/* decrypt */
1928a4e6689Sderaadt 					/*
1938a4e6689Sderaadt 					 * Keep encrypted block for XOR'ing
1948a4e6689Sderaadt 					 * with next block
1958a4e6689Sderaadt 					 */
19609b14fccSmarkus 					nivp = (ivp == iv) ? iv2 : iv;
19709b14fccSmarkus 					bcopy(blk, nivp, blks);
1985b6944e5Sderaadt 
1995b6944e5Sderaadt 					exf->decrypt(sw->sw_kschedule, blk);
2005b6944e5Sderaadt 
2015b6944e5Sderaadt 					/* XOR with previous block */
2025b6944e5Sderaadt 					for (j = 0; j < blks; j++)
2035b6944e5Sderaadt 						blk[j] ^= ivp[j];
20409b14fccSmarkus 					ivp = nivp;
2055b6944e5Sderaadt 				}
2065b6944e5Sderaadt 
2075b6944e5Sderaadt 				/* Copy back decrypted block */
20841b18b7eSblambert 				m_copyback(m, k, blks, blk, M_NOWAIT);
2095b6944e5Sderaadt 
2105b6944e5Sderaadt 				/* Advance pointer */
2115b6944e5Sderaadt 				m = m_getptr(m, k + blks, &k);
2125b6944e5Sderaadt 				if (m == NULL)
2135b6944e5Sderaadt 					return EINVAL;
2145b6944e5Sderaadt 
2155b6944e5Sderaadt 				i -= blks;
2165b6944e5Sderaadt 
2175b6944e5Sderaadt 				/* Could be done... */
2185b6944e5Sderaadt 				if (i == 0)
2195b6944e5Sderaadt 					break;
2205b6944e5Sderaadt 			}
2215b6944e5Sderaadt 
2225b6944e5Sderaadt 			/* Skip possibly empty mbufs */
2238a4e6689Sderaadt 			if (k == m->m_len) {
2248a4e6689Sderaadt 				for (m = m->m_next; m && m->m_len == 0;
2258a4e6689Sderaadt 				    m = m->m_next)
2265b6944e5Sderaadt 					;
2275b6944e5Sderaadt 				k = 0;
2285b6944e5Sderaadt 			}
2295b6944e5Sderaadt 
2305b6944e5Sderaadt 			/* Sanity check */
2315b6944e5Sderaadt 			if (m == NULL)
2325b6944e5Sderaadt 				return EINVAL;
2335b6944e5Sderaadt 
2345b6944e5Sderaadt 			/*
2358a4e6689Sderaadt 			 * Warning: idat may point to garbage here, but
2368a4e6689Sderaadt 			 * we only use it in the while() loop, only if
2378a4e6689Sderaadt 			 * there are indeed enough data.
2385b6944e5Sderaadt 			 */
2395b6944e5Sderaadt 			idat = mtod(m, unsigned char *) + k;
2405b6944e5Sderaadt 
2418a4e6689Sderaadt 			while (m->m_len >= k + blks && i > 0) {
2428264d0c5Smarkus 				if (exf->reinit) {
243e2ed96e1Sdjm 					if (crd->crd_flags & CRD_F_ENCRYPT) {
244e2ed96e1Sdjm 						exf->encrypt(sw->sw_kschedule,
245e2ed96e1Sdjm 						    idat);
246e2ed96e1Sdjm 					} else {
247e2ed96e1Sdjm 						exf->decrypt(sw->sw_kschedule,
248e2ed96e1Sdjm 						    idat);
249e2ed96e1Sdjm 					}
2508264d0c5Smarkus 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
2515b6944e5Sderaadt 					/* XOR with previous block/IV */
2525b6944e5Sderaadt 					for (j = 0; j < blks; j++)
2535b6944e5Sderaadt 						idat[j] ^= ivp[j];
2545b6944e5Sderaadt 
2555b6944e5Sderaadt 					exf->encrypt(sw->sw_kschedule, idat);
2565b6944e5Sderaadt 					ivp = idat;
2578a4e6689Sderaadt 				} else {	/* decrypt */
2585b6944e5Sderaadt 					/*
2598a4e6689Sderaadt 					 * Keep encrypted block to be used
2608a4e6689Sderaadt 					 * in next block's processing.
2615b6944e5Sderaadt 					 */
26209b14fccSmarkus 					nivp = (ivp == iv) ? iv2 : iv;
26309b14fccSmarkus 					bcopy(idat, nivp, blks);
2645b6944e5Sderaadt 
2655b6944e5Sderaadt 					exf->decrypt(sw->sw_kschedule, idat);
2665b6944e5Sderaadt 
2675b6944e5Sderaadt 					/* XOR with previous block/IV */
2685b6944e5Sderaadt 					for (j = 0; j < blks; j++)
2695b6944e5Sderaadt 						idat[j] ^= ivp[j];
27009b14fccSmarkus 					ivp = nivp;
2715b6944e5Sderaadt 				}
2725b6944e5Sderaadt 
2735b6944e5Sderaadt 				idat += blks;
2745b6944e5Sderaadt 				k += blks;
2755b6944e5Sderaadt 				i -= blks;
2765b6944e5Sderaadt 			}
2775b6944e5Sderaadt 		}
278f89a9693Sprovos 	} else {
279f89a9693Sprovos 		/* Find beginning of data */
280f89a9693Sprovos 		count = crd->crd_skip;
281f89a9693Sprovos 		ind = cuio_getptr(uio, count, &k);
282f89a9693Sprovos 		if (ind == -1)
283f89a9693Sprovos 			return EINVAL;
284f89a9693Sprovos 
285f89a9693Sprovos 		i = crd->crd_len;
286f89a9693Sprovos 
287f89a9693Sprovos 		while (i > 0) {
288f89a9693Sprovos 			/*
289f89a9693Sprovos 			 * If there's insufficient data at the end,
290f89a9693Sprovos 			 * we have to do some copying.
291f89a9693Sprovos 			 */
292f89a9693Sprovos 			if (uio->uio_iov[ind].iov_len < k + blks &&
293f89a9693Sprovos 			    uio->uio_iov[ind].iov_len != k) {
29477f4dc4eSmarkus 				cuio_copydata(uio, count, blks, blk);
295f89a9693Sprovos 
296f89a9693Sprovos 				/* Actual encryption/decryption */
2978264d0c5Smarkus 				if (exf->reinit) {
298e2ed96e1Sdjm 					if (crd->crd_flags & CRD_F_ENCRYPT) {
299e2ed96e1Sdjm 						exf->encrypt(sw->sw_kschedule,
300e2ed96e1Sdjm 						    blk);
301e2ed96e1Sdjm 					} else {
302e2ed96e1Sdjm 						exf->decrypt(sw->sw_kschedule,
303e2ed96e1Sdjm 						    blk);
304e2ed96e1Sdjm 					}
3058264d0c5Smarkus 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
306f89a9693Sprovos 					/* XOR with previous block */
307f89a9693Sprovos 					for (j = 0; j < blks; j++)
308f89a9693Sprovos 						blk[j] ^= ivp[j];
309f89a9693Sprovos 
310f89a9693Sprovos 					exf->encrypt(sw->sw_kschedule, blk);
311f89a9693Sprovos 
312f89a9693Sprovos 					/*
313f89a9693Sprovos 					 * Keep encrypted block for XOR'ing
314f89a9693Sprovos 					 * with next block
315f89a9693Sprovos 					 */
316f89a9693Sprovos 					bcopy(blk, iv, blks);
317f89a9693Sprovos 					ivp = iv;
318f89a9693Sprovos 				} else {	/* decrypt */
319f89a9693Sprovos 					/*
320f89a9693Sprovos 					 * Keep encrypted block for XOR'ing
321f89a9693Sprovos 					 * with next block
322f89a9693Sprovos 					 */
32309b14fccSmarkus 					nivp = (ivp == iv) ? iv2 : iv;
32409b14fccSmarkus 					bcopy(blk, nivp, blks);
325f89a9693Sprovos 
326f89a9693Sprovos 					exf->decrypt(sw->sw_kschedule, blk);
327f89a9693Sprovos 
328f89a9693Sprovos 					/* XOR with previous block */
329f89a9693Sprovos 					for (j = 0; j < blks; j++)
330f89a9693Sprovos 						blk[j] ^= ivp[j];
33109b14fccSmarkus 					ivp = nivp;
332f89a9693Sprovos 				}
333f89a9693Sprovos 
334f89a9693Sprovos 				/* Copy back decrypted block */
33577f4dc4eSmarkus 				cuio_copyback(uio, count, blks, blk);
336f89a9693Sprovos 
337f89a9693Sprovos 				count += blks;
338f89a9693Sprovos 
339f89a9693Sprovos 				/* Advance pointer */
340f89a9693Sprovos 				ind = cuio_getptr(uio, count, &k);
341f89a9693Sprovos 				if (ind == -1)
342f89a9693Sprovos 					return (EINVAL);
343f89a9693Sprovos 
344f89a9693Sprovos 				i -= blks;
345f89a9693Sprovos 
346f89a9693Sprovos 				/* Could be done... */
347f89a9693Sprovos 				if (i == 0)
348f89a9693Sprovos 					break;
349f89a9693Sprovos 			}
350f89a9693Sprovos 
351f89a9693Sprovos 			/*
352f89a9693Sprovos 			 * Warning: idat may point to garbage here, but
353f89a9693Sprovos 			 * we only use it in the while() loop, only if
354f89a9693Sprovos 			 * there are indeed enough data.
355f89a9693Sprovos 			 */
3563957c1c0Spedro 			idat = (char *)uio->uio_iov[ind].iov_base + k;
357f89a9693Sprovos 
358f89a9693Sprovos 			while (uio->uio_iov[ind].iov_len >= k + blks &&
359f89a9693Sprovos 			    i > 0) {
3608264d0c5Smarkus 				if (exf->reinit) {
361e2ed96e1Sdjm 					if (crd->crd_flags & CRD_F_ENCRYPT) {
362e2ed96e1Sdjm 						exf->encrypt(sw->sw_kschedule,
363e2ed96e1Sdjm 						    idat);
364e2ed96e1Sdjm 					} else {
365e2ed96e1Sdjm 						exf->decrypt(sw->sw_kschedule,
366e2ed96e1Sdjm 						    idat);
367e2ed96e1Sdjm 					}
3688264d0c5Smarkus 				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
369f89a9693Sprovos 					/* XOR with previous block/IV */
370f89a9693Sprovos 					for (j = 0; j < blks; j++)
371f89a9693Sprovos 						idat[j] ^= ivp[j];
372f89a9693Sprovos 
373f89a9693Sprovos 					exf->encrypt(sw->sw_kschedule, idat);
374f89a9693Sprovos 					ivp = idat;
375f89a9693Sprovos 				} else {	/* decrypt */
376f89a9693Sprovos 					/*
377f89a9693Sprovos 					 * Keep encrypted block to be used
378f89a9693Sprovos 					 * in next block's processing.
379f89a9693Sprovos 					 */
38009b14fccSmarkus 					nivp = (ivp == iv) ? iv2 : iv;
38109b14fccSmarkus 					bcopy(idat, nivp, blks);
382f89a9693Sprovos 
383f89a9693Sprovos 					exf->decrypt(sw->sw_kschedule, idat);
384f89a9693Sprovos 
385f89a9693Sprovos 					/* XOR with previous block/IV */
386f89a9693Sprovos 					for (j = 0; j < blks; j++)
387f89a9693Sprovos 						idat[j] ^= ivp[j];
38809b14fccSmarkus 					ivp = nivp;
389f89a9693Sprovos 				}
390f89a9693Sprovos 
391f89a9693Sprovos 				idat += blks;
392f89a9693Sprovos 				count += blks;
393f89a9693Sprovos 				k += blks;
394f89a9693Sprovos 				i -= blks;
395f89a9693Sprovos 			}
39677f4dc4eSmarkus 
39777f4dc4eSmarkus 			/*
39877f4dc4eSmarkus 			 * Advance to the next iov if the end of the current iov
39977f4dc4eSmarkus 			 * is aligned with the end of a cipher block.
40077f4dc4eSmarkus 			 * Note that the code is equivalent to calling:
40177f4dc4eSmarkus 			 *	ind = cuio_getptr(uio, count, &k);
40277f4dc4eSmarkus 			 */
40377f4dc4eSmarkus 			if (i > 0 && k == uio->uio_iov[ind].iov_len) {
40477f4dc4eSmarkus 				k = 0;
40577f4dc4eSmarkus 				ind++;
40677f4dc4eSmarkus 				if (ind >= uio->uio_iovcnt)
40777f4dc4eSmarkus 					return (EINVAL);
40877f4dc4eSmarkus 			}
409f89a9693Sprovos 		}
410f89a9693Sprovos 	}
4115b6944e5Sderaadt 
412f89a9693Sprovos 	return 0; /* Done with encryption/decryption */
4135b6944e5Sderaadt }
4145b6944e5Sderaadt 
4155b6944e5Sderaadt /*
4165b6944e5Sderaadt  * Compute keyed-hash authenticator.
4175b6944e5Sderaadt  */
4185b6944e5Sderaadt int
swcr_authcompute(struct cryptop * crp,struct cryptodesc * crd,struct swcr_data * sw,caddr_t buf,int outtype)419649dc2d9Smarkus swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd,
420649dc2d9Smarkus     struct swcr_data *sw, caddr_t buf, int outtype)
4215b6944e5Sderaadt {
4225b6944e5Sderaadt 	unsigned char aalg[AALG_MAX_RESULT_LEN];
4234d13edafSbluhm 	const struct auth_hash *axf;
4245b6944e5Sderaadt 	union authctx ctx;
4255b6944e5Sderaadt 	int err;
4265b6944e5Sderaadt 
4275b6944e5Sderaadt 	if (sw->sw_ictx == 0)
4285b6944e5Sderaadt 		return EINVAL;
4295b6944e5Sderaadt 
4305b6944e5Sderaadt 	axf = sw->sw_axf;
4315b6944e5Sderaadt 
4325b6944e5Sderaadt 	bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
4335b6944e5Sderaadt 
434f89a9693Sprovos 	if (outtype == CRYPTO_BUF_MBUF)
4358a4e6689Sderaadt 		err = m_apply((struct mbuf *) buf, crd->crd_skip, crd->crd_len,
4365b6944e5Sderaadt 		    (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
4375b6944e5Sderaadt 		    (caddr_t) &ctx);
438f89a9693Sprovos 	else
439f89a9693Sprovos 		err = cuio_apply((struct uio *) buf, crd->crd_skip,
440f89a9693Sprovos 		    crd->crd_len,
441f89a9693Sprovos 		    (int (*)(caddr_t, caddr_t, unsigned int)) axf->Update,
442f89a9693Sprovos 		    (caddr_t) &ctx);
443f89a9693Sprovos 
4445b6944e5Sderaadt 	if (err)
4455b6944e5Sderaadt 		return err;
4465b6944e5Sderaadt 
4476b4cbaf1Smikeb 	if (crd->crd_flags & CRD_F_ESN)
4486b4cbaf1Smikeb 		axf->Update(&ctx, crd->crd_esn, 4);
4496b4cbaf1Smikeb 
4508a4e6689Sderaadt 	switch (sw->sw_alg) {
4514177b255Sangelos 	case CRYPTO_MD5_HMAC:
4524177b255Sangelos 	case CRYPTO_SHA1_HMAC:
4534177b255Sangelos 	case CRYPTO_RIPEMD160_HMAC:
4548dc8abfbSitojun 	case CRYPTO_SHA2_256_HMAC:
4558dc8abfbSitojun 	case CRYPTO_SHA2_384_HMAC:
4568dc8abfbSitojun 	case CRYPTO_SHA2_512_HMAC:
4575b6944e5Sderaadt 		if (sw->sw_octx == NULL)
4585b6944e5Sderaadt 			return EINVAL;
4595b6944e5Sderaadt 
460e26e8293Sangelos 		axf->Final(aalg, &ctx);
4615b6944e5Sderaadt 		bcopy(sw->sw_octx, &ctx, axf->ctxsize);
4625b6944e5Sderaadt 		axf->Update(&ctx, aalg, axf->hashsize);
4635b6944e5Sderaadt 		axf->Final(aalg, &ctx);
4645b6944e5Sderaadt 		break;
4655b6944e5Sderaadt 	}
4665b6944e5Sderaadt 
4675b6944e5Sderaadt 	/* Inject the authentication data */
468649dc2d9Smarkus 	if (outtype == CRYPTO_BUF_MBUF)
469f89a9693Sprovos 		COPYBACK(outtype, buf, crd->crd_inject, axf->authsize, aalg);
470649dc2d9Smarkus 	else
471649dc2d9Smarkus 		bcopy(aalg, crp->crp_mac, axf->authsize);
472649dc2d9Smarkus 
4735b6944e5Sderaadt 	return 0;
4745b6944e5Sderaadt }
4755b6944e5Sderaadt 
4765b6944e5Sderaadt /*
477112808b6Smikeb  * Apply a combined encryption-authentication transformation
478112808b6Smikeb  */
479112808b6Smikeb int
swcr_authenc(struct cryptop * crp)480e3c3ea0bSmikeb swcr_authenc(struct cryptop *crp)
481112808b6Smikeb {
482112808b6Smikeb 	uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
483112808b6Smikeb 	u_char *blk = (u_char *)blkbuf;
484112808b6Smikeb 	u_char aalg[AALG_MAX_RESULT_LEN];
485112808b6Smikeb 	u_char iv[EALG_MAX_BLOCK_LEN];
486112808b6Smikeb 	union authctx ctx;
487112808b6Smikeb 	struct cryptodesc *crd, *crda = NULL, *crde = NULL;
488a986bd3bSbluhm 	struct swcr_list *session;
48991274d44Shaesbaert 	struct swcr_data *sw, *swa, *swe = NULL;
4904d13edafSbluhm 	const struct auth_hash *axf = NULL;
4914d13edafSbluhm 	const struct enc_xform *exf = NULL;
492112808b6Smikeb 	caddr_t buf = (caddr_t)crp->crp_buf;
493112808b6Smikeb 	uint32_t *blkp;
4944d136a9dSmikeb 	int aadlen, blksz, i, ivlen, outtype, len, iskip, oskip;
495112808b6Smikeb 
4964d136a9dSmikeb 	ivlen = blksz = iskip = oskip = 0;
49791274d44Shaesbaert 
498a986bd3bSbluhm 	session = &swcr_sessions[crp->crp_sid & 0xffffffff];
499e410e70dSpatrick 	for (i = 0; i < crp->crp_ndesc; i++) {
500e410e70dSpatrick 		crd = &crp->crp_desc[i];
501a986bd3bSbluhm 		SLIST_FOREACH(sw, session, sw_next) {
502a986bd3bSbluhm 			if (sw->sw_alg == crd->crd_alg)
503a986bd3bSbluhm 				break;
504a986bd3bSbluhm 		}
505112808b6Smikeb 		if (sw == NULL)
506112808b6Smikeb 			return (EINVAL);
507112808b6Smikeb 
508112808b6Smikeb 		switch (sw->sw_alg) {
509112808b6Smikeb 		case CRYPTO_AES_GCM_16:
510112808b6Smikeb 		case CRYPTO_AES_GMAC:
5114ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305:
512112808b6Smikeb 			swe = sw;
513112808b6Smikeb 			crde = crd;
514112808b6Smikeb 			exf = swe->sw_exf;
515112808b6Smikeb 			ivlen = exf->ivsize;
516112808b6Smikeb 			break;
517112808b6Smikeb 		case CRYPTO_AES_128_GMAC:
518112808b6Smikeb 		case CRYPTO_AES_192_GMAC:
519112808b6Smikeb 		case CRYPTO_AES_256_GMAC:
5204ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305_MAC:
521112808b6Smikeb 			swa = sw;
522112808b6Smikeb 			crda = crd;
523112808b6Smikeb 			axf = swa->sw_axf;
524112808b6Smikeb 			if (swa->sw_ictx == 0)
525112808b6Smikeb 				return (EINVAL);
526112808b6Smikeb 			bcopy(swa->sw_ictx, &ctx, axf->ctxsize);
527112808b6Smikeb 			blksz = axf->blocksize;
528112808b6Smikeb 			break;
529112808b6Smikeb 		default:
530112808b6Smikeb 			return (EINVAL);
531112808b6Smikeb 		}
532112808b6Smikeb 	}
533112808b6Smikeb 	if (crde == NULL || crda == NULL)
534112808b6Smikeb 		return (EINVAL);
535112808b6Smikeb 
536112808b6Smikeb 	if (crp->crp_flags & CRYPTO_F_IMBUF) {
537112808b6Smikeb 		outtype = CRYPTO_BUF_MBUF;
538112808b6Smikeb 	} else {
539112808b6Smikeb 		outtype = CRYPTO_BUF_IOV;
540112808b6Smikeb 	}
541112808b6Smikeb 
542112808b6Smikeb 	/* Initialize the IV */
543112808b6Smikeb 	if (crde->crd_flags & CRD_F_ENCRYPT) {
544112808b6Smikeb 		/* IV explicitly provided ? */
545112808b6Smikeb 		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
546112808b6Smikeb 			bcopy(crde->crd_iv, iv, ivlen);
547112808b6Smikeb 		else
548112808b6Smikeb 			arc4random_buf(iv, ivlen);
549112808b6Smikeb 
550112808b6Smikeb 		/* Do we need to write the IV */
5512898430aSderaadt 		if (!(crde->crd_flags & CRD_F_IV_PRESENT))
552112808b6Smikeb 			COPYBACK(outtype, buf, crde->crd_inject, ivlen, iv);
553112808b6Smikeb 
554112808b6Smikeb 	} else {	/* Decryption */
555112808b6Smikeb 			/* IV explicitly provided ? */
556112808b6Smikeb 		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
557112808b6Smikeb 			bcopy(crde->crd_iv, iv, ivlen);
558112808b6Smikeb 		else {
559112808b6Smikeb 			/* Get IV off buf */
560112808b6Smikeb 			COPYDATA(outtype, buf, crde->crd_inject, ivlen, iv);
561112808b6Smikeb 		}
562112808b6Smikeb 	}
563112808b6Smikeb 
564112808b6Smikeb 	/* Supply MAC with IV */
565112808b6Smikeb 	if (axf->Reinit)
566112808b6Smikeb 		axf->Reinit(&ctx, iv, ivlen);
567112808b6Smikeb 
568112808b6Smikeb 	/* Supply MAC with AAD */
5696b4cbaf1Smikeb 	aadlen = crda->crd_len;
5704d136a9dSmikeb 	/*
5714d136a9dSmikeb 	 * Section 5 of RFC 4106 specifies that AAD construction consists of
5724d136a9dSmikeb 	 * {SPI, ESN, SN} whereas the real packet contains only {SPI, SN}.
5734d136a9dSmikeb 	 * Unfortunately it doesn't follow a good example set in the Section
5744d136a9dSmikeb 	 * 3.3.2.1 of RFC 4303 where upper part of the ESN, located in the
5754d136a9dSmikeb 	 * external (to the packet) memory buffer, is processed by the hash
5764d136a9dSmikeb 	 * function in the end thus allowing to retain simple programming
5774d136a9dSmikeb 	 * interfaces and avoid kludges like the one below.
5784d136a9dSmikeb 	 */
5794d136a9dSmikeb 	if (crda->crd_flags & CRD_F_ESN) {
5806b4cbaf1Smikeb 		aadlen += 4;
5814d136a9dSmikeb 		/* SPI */
5824d136a9dSmikeb 		COPYDATA(outtype, buf, crda->crd_skip, 4, blk);
5834d136a9dSmikeb 		iskip = 4; /* loop below will start with an offset of 4 */
5844d136a9dSmikeb 		/* ESN */
5854d136a9dSmikeb 		bcopy(crda->crd_esn, blk + 4, 4);
5864d136a9dSmikeb 		oskip = iskip + 4; /* offset output buffer blk by 8 */
5876b4cbaf1Smikeb 	}
588bdab7913Smikeb 	for (i = iskip; i < crda->crd_len; i += axf->hashsize) {
589bdab7913Smikeb 		len = MIN(crda->crd_len - i, axf->hashsize - oskip);
5904d136a9dSmikeb 		COPYDATA(outtype, buf, crda->crd_skip + i, len, blk + oskip);
591bdab7913Smikeb 		bzero(blk + len + oskip, axf->hashsize - len - oskip);
592bdab7913Smikeb 		axf->Update(&ctx, blk, axf->hashsize);
5934d136a9dSmikeb 		oskip = 0; /* reset initial output offset */
594112808b6Smikeb 	}
595112808b6Smikeb 
596112808b6Smikeb 	if (exf->reinit)
597112808b6Smikeb 		exf->reinit(swe->sw_kschedule, iv);
598112808b6Smikeb 
599112808b6Smikeb 	/* Do encryption/decryption with MAC */
600112808b6Smikeb 	for (i = 0; i < crde->crd_len; i += blksz) {
601112808b6Smikeb 		len = MIN(crde->crd_len - i, blksz);
602112808b6Smikeb 		if (len < blksz)
603112808b6Smikeb 			bzero(blk, blksz);
604112808b6Smikeb 		COPYDATA(outtype, buf, crde->crd_skip + i, len, blk);
605112808b6Smikeb 		if (crde->crd_flags & CRD_F_ENCRYPT) {
606112808b6Smikeb 			exf->encrypt(swe->sw_kschedule, blk);
607112808b6Smikeb 			axf->Update(&ctx, blk, len);
608112808b6Smikeb 		} else {
609112808b6Smikeb 			axf->Update(&ctx, blk, len);
610112808b6Smikeb 			exf->decrypt(swe->sw_kschedule, blk);
611112808b6Smikeb 		}
612112808b6Smikeb 		COPYBACK(outtype, buf, crde->crd_skip + i, len, blk);
613112808b6Smikeb 	}
614112808b6Smikeb 
615112808b6Smikeb 	/* Do any required special finalization */
616112808b6Smikeb 	switch (crda->crd_alg) {
617112808b6Smikeb 		case CRYPTO_AES_128_GMAC:
618112808b6Smikeb 		case CRYPTO_AES_192_GMAC:
619112808b6Smikeb 		case CRYPTO_AES_256_GMAC:
620112808b6Smikeb 			/* length block */
621bdab7913Smikeb 			bzero(blk, axf->hashsize);
622112808b6Smikeb 			blkp = (uint32_t *)blk + 1;
623e3c3ea0bSmikeb 			*blkp = htobe32(aadlen * 8);
624112808b6Smikeb 			blkp = (uint32_t *)blk + 3;
625112808b6Smikeb 			*blkp = htobe32(crde->crd_len * 8);
626bdab7913Smikeb 			axf->Update(&ctx, blk, axf->hashsize);
627112808b6Smikeb 			break;
6284ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305_MAC:
6294ad2b35cSmikeb 			/* length block */
6304ad2b35cSmikeb 			bzero(blk, axf->hashsize);
6314ad2b35cSmikeb 			blkp = (uint32_t *)blk;
6324ad2b35cSmikeb 			*blkp = htole32(aadlen);
6334ad2b35cSmikeb 			blkp = (uint32_t *)blk + 2;
6344ad2b35cSmikeb 			*blkp = htole32(crde->crd_len);
6354ad2b35cSmikeb 			axf->Update(&ctx, blk, axf->hashsize);
6364ad2b35cSmikeb 			break;
637112808b6Smikeb 	}
638112808b6Smikeb 
639112808b6Smikeb 	/* Finalize MAC */
640112808b6Smikeb 	axf->Final(aalg, &ctx);
641112808b6Smikeb 
642112808b6Smikeb 	/* Inject the authentication data */
643112808b6Smikeb 	if (outtype == CRYPTO_BUF_MBUF)
644112808b6Smikeb 		COPYBACK(outtype, buf, crda->crd_inject, axf->authsize, aalg);
645112808b6Smikeb 	else
646112808b6Smikeb 		bcopy(aalg, crp->crp_mac, axf->authsize);
647112808b6Smikeb 
648112808b6Smikeb 	return (0);
649112808b6Smikeb }
650112808b6Smikeb 
651112808b6Smikeb /*
6525f32815eSjjbg  * Apply a compression/decompression algorithm
6535f32815eSjjbg  */
6545f32815eSjjbg int
swcr_compdec(struct cryptodesc * crd,struct swcr_data * sw,caddr_t buf,int outtype)6555f32815eSjjbg swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw,
6565f32815eSjjbg     caddr_t buf, int outtype)
6575f32815eSjjbg {
6585f32815eSjjbg 	u_int8_t *data, *out;
6594d13edafSbluhm 	const struct comp_algo *cxf;
660f89a9693Sprovos 	int adj;
6615f32815eSjjbg 	u_int32_t result;
6625f32815eSjjbg 
6635f32815eSjjbg 	cxf = sw->sw_cxf;
6645f32815eSjjbg 
6655f32815eSjjbg 	/* We must handle the whole buffer of data in one time
6665f32815eSjjbg 	 * then if there is not all the data in the mbuf, we must
6675f32815eSjjbg 	 * copy in a buffer.
6685f32815eSjjbg 	 */
6695f32815eSjjbg 
67081cec227Shshoexer 	data = malloc(crd->crd_len, M_CRYPTO_DATA, M_NOWAIT);
6715f32815eSjjbg 	if (data == NULL)
672f89a9693Sprovos 		return (EINVAL);
673f89a9693Sprovos 	COPYDATA(outtype, buf, crd->crd_skip, crd->crd_len, data);
6745f32815eSjjbg 
6755f32815eSjjbg 	if (crd->crd_flags & CRD_F_COMP)
6765f32815eSjjbg 		result = cxf->compress(data, crd->crd_len, &out);
6775f32815eSjjbg 	else
6785f32815eSjjbg 		result = cxf->decompress(data, crd->crd_len, &out);
6795f32815eSjjbg 
680ce8cce3eSderaadt 	free(data, M_CRYPTO_DATA, crd->crd_len);
6815f32815eSjjbg 	if (result == 0)
6825f32815eSjjbg 		return EINVAL;
683f89a9693Sprovos 
6845f32815eSjjbg 	/* Copy back the (de)compressed data. m_copyback is
6855f32815eSjjbg 	 * extending the mbuf as necessary.
6865f32815eSjjbg 	 */
6875f32815eSjjbg 	sw->sw_size = result;
6885f32815eSjjbg 	/* Check the compressed size when doing compression */
6895f32815eSjjbg 	if (crd->crd_flags & CRD_F_COMP) {
6905f32815eSjjbg 		if (result > crd->crd_len) {
6915f32815eSjjbg 			/* Compression was useless, we lost time */
692319dd5c3Smpi 			free(out, M_CRYPTO_DATA, result);
6935f32815eSjjbg 			return 0;
6945f32815eSjjbg 		}
6955f32815eSjjbg 	}
696f89a9693Sprovos 
697f89a9693Sprovos 	COPYBACK(outtype, buf, crd->crd_skip, result, out);
6985f32815eSjjbg 	if (result < crd->crd_len) {
6995f32815eSjjbg 		adj = result - crd->crd_len;
700f89a9693Sprovos 		if (outtype == CRYPTO_BUF_MBUF) {
701f89a9693Sprovos 			adj = result - crd->crd_len;
702f89a9693Sprovos 			m_adj((struct mbuf *)buf, adj);
703f89a9693Sprovos 		} else {
704f89a9693Sprovos 			struct uio *uio = (struct uio *)buf;
705f89a9693Sprovos 			int ind;
706f89a9693Sprovos 
707f89a9693Sprovos 			adj = crd->crd_len - result;
708f89a9693Sprovos 			ind = uio->uio_iovcnt - 1;
709f89a9693Sprovos 
710f89a9693Sprovos 			while (adj > 0 && ind >= 0) {
711f89a9693Sprovos 				if (adj < uio->uio_iov[ind].iov_len) {
712f89a9693Sprovos 					uio->uio_iov[ind].iov_len -= adj;
713f89a9693Sprovos 					break;
714f89a9693Sprovos 				}
715f89a9693Sprovos 
716f89a9693Sprovos 				adj -= uio->uio_iov[ind].iov_len;
717f89a9693Sprovos 				uio->uio_iov[ind].iov_len = 0;
718f89a9693Sprovos 				ind--;
719f89a9693Sprovos 				uio->uio_iovcnt--;
720f89a9693Sprovos 			}
721f89a9693Sprovos 		}
7225f32815eSjjbg 	}
723319dd5c3Smpi 	free(out, M_CRYPTO_DATA, result);
7245f32815eSjjbg 	return 0;
7255f32815eSjjbg }
7265f32815eSjjbg 
7275f32815eSjjbg /*
7285b6944e5Sderaadt  * Generate a new software session.
7295b6944e5Sderaadt  */
7305b6944e5Sderaadt int
swcr_newsession(u_int32_t * sid,struct cryptoini * cri)7315b6944e5Sderaadt swcr_newsession(u_int32_t *sid, struct cryptoini *cri)
7325b6944e5Sderaadt {
733a986bd3bSbluhm 	struct swcr_list *session;
734a986bd3bSbluhm 	struct swcr_data *swd, *prev;
7354d13edafSbluhm 	const struct auth_hash *axf;
7364d13edafSbluhm 	const struct enc_xform *txf;
7374d13edafSbluhm 	const struct comp_algo *cxf;
7385b6944e5Sderaadt 	u_int32_t i;
7395b6944e5Sderaadt 	int k;
7405b6944e5Sderaadt 
7418a4e6689Sderaadt 	if (sid == NULL || cri == NULL)
7425b6944e5Sderaadt 		return EINVAL;
7435b6944e5Sderaadt 
744a986bd3bSbluhm 	if (swcr_sessions != NULL) {
7455b6944e5Sderaadt 		for (i = 1; i < swcr_sesnum; i++)
746a986bd3bSbluhm 			if (SLIST_EMPTY(&swcr_sessions[i]))
7475b6944e5Sderaadt 				break;
7488a4e6689Sderaadt 	}
7495b6944e5Sderaadt 
7508a4e6689Sderaadt 	if (swcr_sessions == NULL || i == swcr_sesnum) {
7518a4e6689Sderaadt 		if (swcr_sessions == NULL) {
7525b6944e5Sderaadt 			i = 1; /* We leave swcr_sessions[0] empty */
7535b6944e5Sderaadt 			swcr_sesnum = CRYPTO_SW_SESSIONS;
7548a4e6689Sderaadt 		} else
7555b6944e5Sderaadt 			swcr_sesnum *= 2;
7565b6944e5Sderaadt 
757a986bd3bSbluhm 		session = mallocarray(swcr_sesnum, sizeof(struct swcr_list),
75881cec227Shshoexer 		    M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
759a986bd3bSbluhm 		if (session == NULL) {
7605b6944e5Sderaadt 			/* Reset session number */
7615b6944e5Sderaadt 			if (swcr_sesnum == CRYPTO_SW_SESSIONS)
7625b6944e5Sderaadt 				swcr_sesnum = 0;
7635b6944e5Sderaadt 			else
7645b6944e5Sderaadt 				swcr_sesnum /= 2;
7655b6944e5Sderaadt 			return ENOBUFS;
7665b6944e5Sderaadt 		}
7675b6944e5Sderaadt 
7685b6944e5Sderaadt 		/* Copy existing sessions */
7698a4e6689Sderaadt 		if (swcr_sessions) {
770a986bd3bSbluhm 			bcopy(swcr_sessions, session,
771a986bd3bSbluhm 			    (swcr_sesnum / 2) * sizeof(struct swcr_list));
772ce8cce3eSderaadt 			free(swcr_sessions, M_CRYPTO_DATA,
773a986bd3bSbluhm 			    (swcr_sesnum / 2) * sizeof(struct swcr_list));
7745b6944e5Sderaadt 		}
7755b6944e5Sderaadt 
776a986bd3bSbluhm 		swcr_sessions = session;
7775b6944e5Sderaadt 	}
7785b6944e5Sderaadt 
779a986bd3bSbluhm 	session = &swcr_sessions[i];
7805b6944e5Sderaadt 	*sid = i;
781a986bd3bSbluhm 	prev = NULL;
7825b6944e5Sderaadt 
7838a4e6689Sderaadt 	while (cri) {
784a986bd3bSbluhm 		swd = malloc(sizeof(struct swcr_data), M_CRYPTO_DATA,
78581cec227Shshoexer 		    M_NOWAIT | M_ZERO);
786a986bd3bSbluhm 		if (swd == NULL) {
7875b6944e5Sderaadt 			swcr_freesession(i);
7885b6944e5Sderaadt 			return ENOBUFS;
7895b6944e5Sderaadt 		}
790a986bd3bSbluhm 		if (prev == NULL)
791a986bd3bSbluhm 			SLIST_INSERT_HEAD(session, swd, sw_next);
792a986bd3bSbluhm 		else
793a986bd3bSbluhm 			SLIST_INSERT_AFTER(prev, swd, sw_next);
7945b6944e5Sderaadt 
7958a4e6689Sderaadt 		switch (cri->cri_alg) {
7965b6944e5Sderaadt 		case CRYPTO_3DES_CBC:
7975b6944e5Sderaadt 			txf = &enc_xform_3des;
7985b6944e5Sderaadt 			goto enccommon;
7995b6944e5Sderaadt 		case CRYPTO_BLF_CBC:
8005b6944e5Sderaadt 			txf = &enc_xform_blf;
8015b6944e5Sderaadt 			goto enccommon;
8025b6944e5Sderaadt 		case CRYPTO_CAST_CBC:
8035b6944e5Sderaadt 			txf = &enc_xform_cast5;
8045b6944e5Sderaadt 			goto enccommon;
805d223d7cbSmikeb 		case CRYPTO_AES_CBC:
806d223d7cbSmikeb 			txf = &enc_xform_aes;
807013a1d61Sangelos 			goto enccommon;
8088264d0c5Smarkus 		case CRYPTO_AES_CTR:
8098264d0c5Smarkus 			txf = &enc_xform_aes_ctr;
8108264d0c5Smarkus 			goto enccommon;
811e2ed96e1Sdjm 		case CRYPTO_AES_XTS:
812e2ed96e1Sdjm 			txf = &enc_xform_aes_xts;
813e2ed96e1Sdjm 			goto enccommon;
814112808b6Smikeb 		case CRYPTO_AES_GCM_16:
815112808b6Smikeb 			txf = &enc_xform_aes_gcm;
816112808b6Smikeb 			goto enccommon;
817112808b6Smikeb 		case CRYPTO_AES_GMAC:
818112808b6Smikeb 			txf = &enc_xform_aes_gmac;
819a986bd3bSbluhm 			swd->sw_exf = txf;
820112808b6Smikeb 			break;
8214ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305:
8224ad2b35cSmikeb 			txf = &enc_xform_chacha20_poly1305;
8234ad2b35cSmikeb 			goto enccommon;
824363be32cSjason 		case CRYPTO_NULL:
825363be32cSjason 			txf = &enc_xform_null;
826363be32cSjason 			goto enccommon;
8275b6944e5Sderaadt 		enccommon:
8282dbd8e13Sjsing 			if (txf->ctxsize > 0) {
829a986bd3bSbluhm 				swd->sw_kschedule = malloc(txf->ctxsize,
8302dbd8e13Sjsing 				    M_CRYPTO_DATA, M_NOWAIT | M_ZERO);
831a986bd3bSbluhm 				if (swd->sw_kschedule == NULL) {
8322dbd8e13Sjsing 					swcr_freesession(i);
8332dbd8e13Sjsing 					return EINVAL;
8342dbd8e13Sjsing 				}
8352dbd8e13Sjsing 			}
836a986bd3bSbluhm 			if (txf->setkey(swd->sw_kschedule, cri->cri_key,
837650747f9Shshoexer 			    cri->cri_klen / 8) < 0) {
838650747f9Shshoexer 				swcr_freesession(i);
839650747f9Shshoexer 				return EINVAL;
840650747f9Shshoexer 			}
841a986bd3bSbluhm 			swd->sw_exf = txf;
8425b6944e5Sderaadt 			break;
8435b6944e5Sderaadt 
8444177b255Sangelos 		case CRYPTO_MD5_HMAC:
8455b6944e5Sderaadt 			axf = &auth_hash_hmac_md5_96;
8465b6944e5Sderaadt 			goto authcommon;
8474177b255Sangelos 		case CRYPTO_SHA1_HMAC:
8485b6944e5Sderaadt 			axf = &auth_hash_hmac_sha1_96;
8495b6944e5Sderaadt 			goto authcommon;
8504177b255Sangelos 		case CRYPTO_RIPEMD160_HMAC:
8515b6944e5Sderaadt 			axf = &auth_hash_hmac_ripemd_160_96;
8528dc8abfbSitojun 			goto authcommon;
8538dc8abfbSitojun 		case CRYPTO_SHA2_256_HMAC:
8548688c78cSmarkus 			axf = &auth_hash_hmac_sha2_256_128;
8558dc8abfbSitojun 			goto authcommon;
8568dc8abfbSitojun 		case CRYPTO_SHA2_384_HMAC:
8578688c78cSmarkus 			axf = &auth_hash_hmac_sha2_384_192;
8588dc8abfbSitojun 			goto authcommon;
8598dc8abfbSitojun 		case CRYPTO_SHA2_512_HMAC:
8608688c78cSmarkus 			axf = &auth_hash_hmac_sha2_512_256;
861a2394253Smikeb 			goto authcommon;
8625b6944e5Sderaadt 		authcommon:
863a986bd3bSbluhm 			swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
864b25a4da8Sangelos 			    M_NOWAIT);
865a986bd3bSbluhm 			if (swd->sw_ictx == NULL) {
8665b6944e5Sderaadt 				swcr_freesession(i);
8675b6944e5Sderaadt 				return ENOBUFS;
8685b6944e5Sderaadt 			}
8695b6944e5Sderaadt 
870a986bd3bSbluhm 			swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
871b25a4da8Sangelos 			    M_NOWAIT);
872a986bd3bSbluhm 			if (swd->sw_octx == NULL) {
8735b6944e5Sderaadt 				swcr_freesession(i);
8745b6944e5Sderaadt 				return ENOBUFS;
8755b6944e5Sderaadt 			}
8765b6944e5Sderaadt 
8775b6944e5Sderaadt 			for (k = 0; k < cri->cri_klen / 8; k++)
8785b6944e5Sderaadt 				cri->cri_key[k] ^= HMAC_IPAD_VAL;
8795b6944e5Sderaadt 
880a986bd3bSbluhm 			axf->Init(swd->sw_ictx);
881a986bd3bSbluhm 			axf->Update(swd->sw_ictx, cri->cri_key,
8825b6944e5Sderaadt 			    cri->cri_klen / 8);
883a986bd3bSbluhm 			axf->Update(swd->sw_ictx, hmac_ipad_buffer,
8848688c78cSmarkus 			    axf->blocksize - (cri->cri_klen / 8));
8855b6944e5Sderaadt 
8865b6944e5Sderaadt 			for (k = 0; k < cri->cri_klen / 8; k++)
8875b6944e5Sderaadt 				cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
8885b6944e5Sderaadt 
889a986bd3bSbluhm 			axf->Init(swd->sw_octx);
890a986bd3bSbluhm 			axf->Update(swd->sw_octx, cri->cri_key,
8915b6944e5Sderaadt 			    cri->cri_klen / 8);
892a986bd3bSbluhm 			axf->Update(swd->sw_octx, hmac_opad_buffer,
8938688c78cSmarkus 			    axf->blocksize - (cri->cri_klen / 8));
8945b6944e5Sderaadt 
8955b6944e5Sderaadt 			for (k = 0; k < cri->cri_klen / 8; k++)
8965b6944e5Sderaadt 				cri->cri_key[k] ^= HMAC_OPAD_VAL;
897a986bd3bSbluhm 			swd->sw_axf = axf;
8985b6944e5Sderaadt 			break;
8995b6944e5Sderaadt 
900112808b6Smikeb 		case CRYPTO_AES_128_GMAC:
901112808b6Smikeb 			axf = &auth_hash_gmac_aes_128;
902a2394253Smikeb 			goto authenccommon;
903112808b6Smikeb 		case CRYPTO_AES_192_GMAC:
904112808b6Smikeb 			axf = &auth_hash_gmac_aes_192;
905a2394253Smikeb 			goto authenccommon;
906112808b6Smikeb 		case CRYPTO_AES_256_GMAC:
907112808b6Smikeb 			axf = &auth_hash_gmac_aes_256;
908a2394253Smikeb 			goto authenccommon;
9094ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305_MAC:
9104ad2b35cSmikeb 			axf = &auth_hash_chacha20_poly1305;
911a2394253Smikeb 			goto authenccommon;
912a2394253Smikeb 		authenccommon:
913a986bd3bSbluhm 			swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
914112808b6Smikeb 			    M_NOWAIT);
915a986bd3bSbluhm 			if (swd->sw_ictx == NULL) {
916112808b6Smikeb 				swcr_freesession(i);
917112808b6Smikeb 				return ENOBUFS;
918112808b6Smikeb 			}
919a986bd3bSbluhm 			axf->Init(swd->sw_ictx);
920a986bd3bSbluhm 			axf->Setkey(swd->sw_ictx, cri->cri_key,
921112808b6Smikeb 			    cri->cri_klen / 8);
922a986bd3bSbluhm 			swd->sw_axf = axf;
923112808b6Smikeb 			break;
924112808b6Smikeb 
9255f32815eSjjbg 		case CRYPTO_DEFLATE_COMP:
9265f32815eSjjbg 			cxf = &comp_algo_deflate;
927a986bd3bSbluhm 			swd->sw_cxf = cxf;
9285f32815eSjjbg 			break;
9296b4cbaf1Smikeb 		case CRYPTO_ESN:
9306b4cbaf1Smikeb 			/* nothing to do */
9316b4cbaf1Smikeb 			break;
9325b6944e5Sderaadt 		default:
9335b6944e5Sderaadt 			swcr_freesession(i);
9345b6944e5Sderaadt 			return EINVAL;
9355b6944e5Sderaadt 		}
9365b6944e5Sderaadt 
937a986bd3bSbluhm 		swd->sw_alg = cri->cri_alg;
9385b6944e5Sderaadt 		cri = cri->cri_next;
939a986bd3bSbluhm 		prev = swd;
9405b6944e5Sderaadt 	}
9415b6944e5Sderaadt 	return 0;
9425b6944e5Sderaadt }
9435b6944e5Sderaadt 
9445b6944e5Sderaadt /*
9455b6944e5Sderaadt  * Free a session.
9465b6944e5Sderaadt  */
9475b6944e5Sderaadt int
swcr_freesession(u_int64_t tid)948bcf5c14bSangelos swcr_freesession(u_int64_t tid)
9495b6944e5Sderaadt {
950a986bd3bSbluhm 	struct swcr_list *session;
9515b6944e5Sderaadt 	struct swcr_data *swd;
9524d13edafSbluhm 	const struct enc_xform *txf;
9534d13edafSbluhm 	const struct auth_hash *axf;
9541c455194Sderaadt 	u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
9555b6944e5Sderaadt 
9568a4e6689Sderaadt 	if (sid > swcr_sesnum || swcr_sessions == NULL ||
957a986bd3bSbluhm 	    SLIST_EMPTY(&swcr_sessions[sid]))
9585b6944e5Sderaadt 		return EINVAL;
9595b6944e5Sderaadt 
9605b6944e5Sderaadt 	/* Silently accept and return */
9615b6944e5Sderaadt 	if (sid == 0)
9625b6944e5Sderaadt 		return 0;
9635b6944e5Sderaadt 
964a986bd3bSbluhm 	session = &swcr_sessions[sid];
965a986bd3bSbluhm 	while (!SLIST_EMPTY(session)) {
966a986bd3bSbluhm 		swd = SLIST_FIRST(session);
967a986bd3bSbluhm 		SLIST_REMOVE_HEAD(session, sw_next);
9685b6944e5Sderaadt 
9698a4e6689Sderaadt 		switch (swd->sw_alg) {
9705b6944e5Sderaadt 		case CRYPTO_3DES_CBC:
9715b6944e5Sderaadt 		case CRYPTO_BLF_CBC:
9725b6944e5Sderaadt 		case CRYPTO_CAST_CBC:
973d223d7cbSmikeb 		case CRYPTO_AES_CBC:
9748264d0c5Smarkus 		case CRYPTO_AES_CTR:
975e2ed96e1Sdjm 		case CRYPTO_AES_XTS:
976112808b6Smikeb 		case CRYPTO_AES_GCM_16:
977112808b6Smikeb 		case CRYPTO_AES_GMAC:
9784ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305:
979363be32cSjason 		case CRYPTO_NULL:
9805b6944e5Sderaadt 			txf = swd->sw_exf;
9815b6944e5Sderaadt 
9822dbd8e13Sjsing 			if (swd->sw_kschedule) {
9832dbd8e13Sjsing 				explicit_bzero(swd->sw_kschedule, txf->ctxsize);
9841b7e8b2dSfcambus 				free(swd->sw_kschedule, M_CRYPTO_DATA,
9851b7e8b2dSfcambus 				    txf->ctxsize);
9862dbd8e13Sjsing 			}
9875b6944e5Sderaadt 			break;
9885b6944e5Sderaadt 
9894177b255Sangelos 		case CRYPTO_MD5_HMAC:
9904177b255Sangelos 		case CRYPTO_SHA1_HMAC:
9914177b255Sangelos 		case CRYPTO_RIPEMD160_HMAC:
9929c4fb132Smarkus 		case CRYPTO_SHA2_256_HMAC:
9939c4fb132Smarkus 		case CRYPTO_SHA2_384_HMAC:
9949c4fb132Smarkus 		case CRYPTO_SHA2_512_HMAC:
995e26e8293Sangelos 			axf = swd->sw_axf;
996e26e8293Sangelos 
9978a4e6689Sderaadt 			if (swd->sw_ictx) {
998a0bea05aSderaadt 				explicit_bzero(swd->sw_ictx, axf->ctxsize);
9991b7e8b2dSfcambus 				free(swd->sw_ictx, M_CRYPTO_DATA, axf->ctxsize);
1000e26e8293Sangelos 			}
10018a4e6689Sderaadt 			if (swd->sw_octx) {
1002a0bea05aSderaadt 				explicit_bzero(swd->sw_octx, axf->ctxsize);
10031b7e8b2dSfcambus 				free(swd->sw_octx, M_CRYPTO_DATA, axf->ctxsize);
1004e26e8293Sangelos 			}
1005e26e8293Sangelos 			break;
1006e26e8293Sangelos 
1007112808b6Smikeb 		case CRYPTO_AES_128_GMAC:
1008112808b6Smikeb 		case CRYPTO_AES_192_GMAC:
1009112808b6Smikeb 		case CRYPTO_AES_256_GMAC:
10104ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305_MAC:
1011649dc2d9Smarkus 			axf = swd->sw_axf;
1012649dc2d9Smarkus 
10130badd83aSmikeb 			if (swd->sw_ictx) {
1014a0bea05aSderaadt 				explicit_bzero(swd->sw_ictx, axf->ctxsize);
10151b7e8b2dSfcambus 				free(swd->sw_ictx, M_CRYPTO_DATA, axf->ctxsize);
10160badd83aSmikeb 			}
1017649dc2d9Smarkus 			break;
10185b6944e5Sderaadt 		}
10195b6944e5Sderaadt 
10201b7e8b2dSfcambus 		free(swd, M_CRYPTO_DATA, sizeof(*swd));
10215b6944e5Sderaadt 	}
10225b6944e5Sderaadt 	return 0;
10235b6944e5Sderaadt }
10245b6944e5Sderaadt 
10255b6944e5Sderaadt /*
10265b6944e5Sderaadt  * Process a software request.
10275b6944e5Sderaadt  */
10285b6944e5Sderaadt int
swcr_process(struct cryptop * crp)10295b6944e5Sderaadt swcr_process(struct cryptop *crp)
10305b6944e5Sderaadt {
10315b6944e5Sderaadt 	struct cryptodesc *crd;
1032a986bd3bSbluhm 	struct swcr_list *session;
10335b6944e5Sderaadt 	struct swcr_data *sw;
10345b6944e5Sderaadt 	u_int32_t lid;
1035*0cd0a70eSpatrick 	int err = 0;
10365b6944e5Sderaadt 	int type;
1037e410e70dSpatrick 	int i;
10385b6944e5Sderaadt 
10393877526aSbluhm 	KASSERT(crp->crp_ndesc >= 1);
10405b6944e5Sderaadt 
10413877526aSbluhm 	if (crp->crp_buf == NULL) {
1042*0cd0a70eSpatrick 		err = EINVAL;
10435b6944e5Sderaadt 		goto done;
10445b6944e5Sderaadt 	}
10455b6944e5Sderaadt 
10465b6944e5Sderaadt 	lid = crp->crp_sid & 0xffffffff;
1047a986bd3bSbluhm 	if (lid >= swcr_sesnum || lid == 0 ||
1048a986bd3bSbluhm 	    SLIST_EMPTY(&swcr_sessions[lid])) {
1049*0cd0a70eSpatrick 		err = ENOENT;
10505b6944e5Sderaadt 		goto done;
10515b6944e5Sderaadt 	}
10525b6944e5Sderaadt 
10535b6944e5Sderaadt 	if (crp->crp_flags & CRYPTO_F_IMBUF)
10545b6944e5Sderaadt 		type = CRYPTO_BUF_MBUF;
10555b6944e5Sderaadt 	else
1056f89a9693Sprovos 		type = CRYPTO_BUF_IOV;
10575b6944e5Sderaadt 
10585b6944e5Sderaadt 	/* Go through crypto descriptors, processing as we go */
1059a986bd3bSbluhm 	session = &swcr_sessions[lid];
1060e410e70dSpatrick 	for (i = 0; i < crp->crp_ndesc; i++) {
1061e410e70dSpatrick 		crd = &crp->crp_desc[i];
10625b6944e5Sderaadt 		/*
10635b6944e5Sderaadt 		 * Find the crypto context.
10645b6944e5Sderaadt 		 *
10655b6944e5Sderaadt 		 * XXX Note that the logic here prevents us from having
10665b6944e5Sderaadt 		 * XXX the same algorithm multiple times in a session
10675b6944e5Sderaadt 		 * XXX (or rather, we can but it won't give us the right
10685b6944e5Sderaadt 		 * XXX results). To do that, we'd need some way of differentiating
10695b6944e5Sderaadt 		 * XXX between the various instances of an algorithm (so we can
10705b6944e5Sderaadt 		 * XXX locate the correct crypto context).
10715b6944e5Sderaadt 		 */
1072a986bd3bSbluhm 		SLIST_FOREACH(sw, session, sw_next) {
1073a986bd3bSbluhm 			if (sw->sw_alg == crd->crd_alg)
1074a986bd3bSbluhm 				break;
1075a986bd3bSbluhm 		}
10765b6944e5Sderaadt 
10775b6944e5Sderaadt 		/* No such context ? */
10788a4e6689Sderaadt 		if (sw == NULL) {
1079*0cd0a70eSpatrick 			err = EINVAL;
10805b6944e5Sderaadt 			goto done;
10815b6944e5Sderaadt 		}
10825b6944e5Sderaadt 
10838a4e6689Sderaadt 		switch (sw->sw_alg) {
10848264d0c5Smarkus 		case CRYPTO_NULL:
10858264d0c5Smarkus 			break;
10865b6944e5Sderaadt 		case CRYPTO_3DES_CBC:
10875b6944e5Sderaadt 		case CRYPTO_BLF_CBC:
10885b6944e5Sderaadt 		case CRYPTO_CAST_CBC:
1089013a1d61Sangelos 		case CRYPTO_RIJNDAEL128_CBC:
10908264d0c5Smarkus 		case CRYPTO_AES_CTR:
1091e2ed96e1Sdjm 		case CRYPTO_AES_XTS:
1092*0cd0a70eSpatrick 			if ((err = swcr_encdec(crd, sw,
10938a4e6689Sderaadt 			    crp->crp_buf, type)) != 0)
10945b6944e5Sderaadt 				goto done;
10955b6944e5Sderaadt 			break;
10964177b255Sangelos 		case CRYPTO_MD5_HMAC:
10974177b255Sangelos 		case CRYPTO_SHA1_HMAC:
10984177b255Sangelos 		case CRYPTO_RIPEMD160_HMAC:
10998dc8abfbSitojun 		case CRYPTO_SHA2_256_HMAC:
11008dc8abfbSitojun 		case CRYPTO_SHA2_384_HMAC:
11018dc8abfbSitojun 		case CRYPTO_SHA2_512_HMAC:
1102*0cd0a70eSpatrick 			if ((err = swcr_authcompute(crp, crd, sw,
11038a4e6689Sderaadt 			    crp->crp_buf, type)) != 0)
11045b6944e5Sderaadt 				goto done;
11055b6944e5Sderaadt 			break;
11065b6944e5Sderaadt 
1107112808b6Smikeb 		case CRYPTO_AES_GCM_16:
1108112808b6Smikeb 		case CRYPTO_AES_GMAC:
1109112808b6Smikeb 		case CRYPTO_AES_128_GMAC:
1110112808b6Smikeb 		case CRYPTO_AES_192_GMAC:
1111112808b6Smikeb 		case CRYPTO_AES_256_GMAC:
11124ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305:
11134ad2b35cSmikeb 		case CRYPTO_CHACHA20_POLY1305_MAC:
1114*0cd0a70eSpatrick 			err = swcr_authenc(crp);
1115112808b6Smikeb 			goto done;
1116112808b6Smikeb 
11175f32815eSjjbg 		case CRYPTO_DEFLATE_COMP:
1118*0cd0a70eSpatrick 			if ((err = swcr_compdec(crd, sw,
11195f32815eSjjbg 			    crp->crp_buf, type)) != 0)
11205f32815eSjjbg 				goto done;
11215f32815eSjjbg 			else
11225f32815eSjjbg 				crp->crp_olen = (int)sw->sw_size;
11235f32815eSjjbg 			break;
11245f32815eSjjbg 
11258a4e6689Sderaadt 		default:
11268a4e6689Sderaadt 			/* Unknown/unsupported algorithm */
1127*0cd0a70eSpatrick 			err = EINVAL;
11285b6944e5Sderaadt 			goto done;
11295b6944e5Sderaadt 		}
11305b6944e5Sderaadt 	}
11315b6944e5Sderaadt 
11325b6944e5Sderaadt done:
1133*0cd0a70eSpatrick 	return err;
11345b6944e5Sderaadt }
11355b6944e5Sderaadt 
11365b6944e5Sderaadt /*
11375b6944e5Sderaadt  * Initialize the driver, called from the kernel main().
11385b6944e5Sderaadt  */
11395b6944e5Sderaadt void
swcr_init(void)11405b6944e5Sderaadt swcr_init(void)
11415b6944e5Sderaadt {
1142fc652f68Sjason 	int algs[CRYPTO_ALGORITHM_MAX + 1];
1143c70638b7Smikeb 	int flags = CRYPTOCAP_F_SOFTWARE;
1144fc652f68Sjason 
1145fc652f68Sjason 	swcr_id = crypto_get_driverid(flags);
1146607b5998Sderaadt 	if (swcr_id < 0) {
1147607b5998Sderaadt 		/* This should never happen */
1148607b5998Sderaadt 		panic("Software crypto device cannot initialize!");
1149607b5998Sderaadt 	}
1150607b5998Sderaadt 
1151fc652f68Sjason 	bzero(algs, sizeof(algs));
1152fc652f68Sjason 
1153fc652f68Sjason 	algs[CRYPTO_3DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
1154fc652f68Sjason 	algs[CRYPTO_BLF_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
1155fc652f68Sjason 	algs[CRYPTO_CAST_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
1156fc652f68Sjason 	algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1157fc652f68Sjason 	algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1158fc652f68Sjason 	algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1159d223d7cbSmikeb 	algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
11608264d0c5Smarkus 	algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED;
1161e2ed96e1Sdjm 	algs[CRYPTO_AES_XTS] = CRYPTO_ALG_FLAG_SUPPORTED;
1162112808b6Smikeb 	algs[CRYPTO_AES_GCM_16] = CRYPTO_ALG_FLAG_SUPPORTED;
1163112808b6Smikeb 	algs[CRYPTO_AES_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1164fc652f68Sjason 	algs[CRYPTO_DEFLATE_COMP] = CRYPTO_ALG_FLAG_SUPPORTED;
1165fc652f68Sjason 	algs[CRYPTO_NULL] = CRYPTO_ALG_FLAG_SUPPORTED;
11668dc8abfbSitojun 	algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
11678dc8abfbSitojun 	algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
11688dc8abfbSitojun 	algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1169112808b6Smikeb 	algs[CRYPTO_AES_128_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1170112808b6Smikeb 	algs[CRYPTO_AES_192_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
1171112808b6Smikeb 	algs[CRYPTO_AES_256_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
11724ad2b35cSmikeb 	algs[CRYPTO_CHACHA20_POLY1305] = CRYPTO_ALG_FLAG_SUPPORTED;
11734ad2b35cSmikeb 	algs[CRYPTO_CHACHA20_POLY1305_MAC] = CRYPTO_ALG_FLAG_SUPPORTED;
11746b4cbaf1Smikeb 	algs[CRYPTO_ESN] = CRYPTO_ALG_FLAG_SUPPORTED;
1175fc652f68Sjason 
1176fc652f68Sjason 	crypto_register(swcr_id, algs, swcr_newsession,
11775b6944e5Sderaadt 	    swcr_freesession, swcr_process);
11785b6944e5Sderaadt }
1179