xref: /freebsd/sys/opencrypto/cryptosoft.c (revision 60727d8b)
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