xref: /freebsd/sys/opencrypto/cryptosoft.c (revision 1b0909d51a8aa8b5ec5a61c2dc1a69642976a732)
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)
56810ad6fSSam Leffler  * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
6091d81d1SSam Leffler  *
7091d81d1SSam Leffler  * This code was written by Angelos D. Keromytis in Athens, Greece, in
8091d81d1SSam Leffler  * February 2000. Network Security Technologies Inc. (NSTI) kindly
9091d81d1SSam Leffler  * supported the development of this code.
10091d81d1SSam Leffler  *
11091d81d1SSam Leffler  * Copyright (c) 2000, 2001 Angelos D. Keromytis
1208fca7a5SJohn-Mark Gurney  * Copyright (c) 2014 The FreeBSD Foundation
1308fca7a5SJohn-Mark Gurney  * All rights reserved.
1408fca7a5SJohn-Mark Gurney  *
1508fca7a5SJohn-Mark Gurney  * Portions of this software were developed by John-Mark Gurney
1608fca7a5SJohn-Mark Gurney  * under sponsorship of the FreeBSD Foundation and
1708fca7a5SJohn-Mark Gurney  * Rubicon Communications, LLC (Netgate).
18091d81d1SSam Leffler  *
19091d81d1SSam Leffler  * Permission to use, copy, and modify this software with or without fee
20091d81d1SSam Leffler  * is hereby granted, provided that this entire notice is included in
21091d81d1SSam Leffler  * all source code copies of any software which is or includes a copy or
22091d81d1SSam Leffler  * modification of this software.
23091d81d1SSam Leffler  *
24091d81d1SSam Leffler  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
25091d81d1SSam Leffler  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
26091d81d1SSam Leffler  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
27091d81d1SSam Leffler  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
28091d81d1SSam Leffler  * PURPOSE.
29091d81d1SSam Leffler  */
30091d81d1SSam Leffler 
312c446514SDavid E. O'Brien #include <sys/cdefs.h>
322c446514SDavid E. O'Brien __FBSDID("$FreeBSD$");
332c446514SDavid E. O'Brien 
34091d81d1SSam Leffler #include <sys/param.h>
35091d81d1SSam Leffler #include <sys/systm.h>
36091d81d1SSam Leffler #include <sys/malloc.h>
37091d81d1SSam Leffler #include <sys/mbuf.h>
386810ad6fSSam Leffler #include <sys/module.h>
39091d81d1SSam Leffler #include <sys/sysctl.h>
40091d81d1SSam Leffler #include <sys/errno.h>
41091d81d1SSam Leffler #include <sys/random.h>
42091d81d1SSam Leffler #include <sys/kernel.h>
43091d81d1SSam Leffler #include <sys/uio.h>
44109919c6SBenno Rice #include <sys/lock.h>
45109919c6SBenno Rice #include <sys/rwlock.h>
4608fca7a5SJohn-Mark Gurney #include <sys/endian.h>
4708fca7a5SJohn-Mark Gurney #include <sys/limits.h>
48091d81d1SSam Leffler 
49091d81d1SSam Leffler #include <crypto/blowfish/blowfish.h>
50091d81d1SSam Leffler #include <crypto/sha1.h>
51091d81d1SSam Leffler #include <opencrypto/rmd160.h>
529f65b10bSHajimu UMEMOTO #include <opencrypto/cast.h>
53091d81d1SSam Leffler #include <opencrypto/skipjack.h>
54091d81d1SSam Leffler #include <sys/md5.h>
55091d81d1SSam Leffler 
56091d81d1SSam Leffler #include <opencrypto/cryptodev.h>
57091d81d1SSam Leffler #include <opencrypto/cryptosoft.h>
58091d81d1SSam Leffler #include <opencrypto/xform.h>
59091d81d1SSam Leffler 
606810ad6fSSam Leffler #include <sys/kobj.h>
616810ad6fSSam Leffler #include <sys/bus.h>
626810ad6fSSam Leffler #include "cryptodev_if.h"
63091d81d1SSam Leffler 
646810ad6fSSam Leffler static	int32_t swcr_id;
656810ad6fSSam Leffler 
666810ad6fSSam Leffler u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
676810ad6fSSam Leffler u_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN];
68091d81d1SSam Leffler 
69091d81d1SSam Leffler static	int swcr_encdec(struct cryptodesc *, struct swcr_data *, caddr_t, int);
70f34a967bSPawel Jakub Dawidek static	int swcr_authcompute(struct cryptodesc *, struct swcr_data *, caddr_t, int);
7108fca7a5SJohn-Mark Gurney static	int swcr_authenc(struct cryptop *crp);
72091d81d1SSam Leffler static	int swcr_compdec(struct cryptodesc *, struct swcr_data *, caddr_t, int);
73*1b0909d5SConrad Meyer static	void swcr_freesession(device_t dev, crypto_session_t cses);
74091d81d1SSam Leffler 
75091d81d1SSam Leffler /*
76091d81d1SSam Leffler  * Apply a symmetric encryption/decryption algorithm.
77091d81d1SSam Leffler  */
78091d81d1SSam Leffler static int
79091d81d1SSam Leffler swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
80f34a967bSPawel Jakub Dawidek     int flags)
81091d81d1SSam Leffler {
825d7ae54aSConrad Meyer 	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN];
8308fca7a5SJohn-Mark Gurney 	unsigned char *ivp, *nivp, iv2[EALG_MAX_BLOCK_LEN];
84091d81d1SSam Leffler 	struct enc_xform *exf;
8508fca7a5SJohn-Mark Gurney 	int i, j, k, blks, ind, count, ivlen;
8608fca7a5SJohn-Mark Gurney 	struct uio *uio, uiolcl;
8708fca7a5SJohn-Mark Gurney 	struct iovec iovlcl[4];
8808fca7a5SJohn-Mark Gurney 	struct iovec *iov;
8908fca7a5SJohn-Mark Gurney 	int iovcnt, iovalloc;
9008fca7a5SJohn-Mark Gurney 	int error;
9108fca7a5SJohn-Mark Gurney 
9208fca7a5SJohn-Mark Gurney 	error = 0;
93091d81d1SSam Leffler 
94091d81d1SSam Leffler 	exf = sw->sw_exf;
95091d81d1SSam Leffler 	blks = exf->blocksize;
9608fca7a5SJohn-Mark Gurney 	ivlen = exf->ivsize;
97091d81d1SSam Leffler 
98091d81d1SSam Leffler 	/* Check for non-padded data */
99091d81d1SSam Leffler 	if (crd->crd_len % blks)
100091d81d1SSam Leffler 		return EINVAL;
101091d81d1SSam Leffler 
10208fca7a5SJohn-Mark Gurney 	if (crd->crd_alg == CRYPTO_AES_ICM &&
10308fca7a5SJohn-Mark Gurney 	    (crd->crd_flags & CRD_F_IV_EXPLICIT) == 0)
10408fca7a5SJohn-Mark Gurney 		return (EINVAL);
10508fca7a5SJohn-Mark Gurney 
106091d81d1SSam Leffler 	/* Initialize the IV */
107091d81d1SSam Leffler 	if (crd->crd_flags & CRD_F_ENCRYPT) {
108091d81d1SSam Leffler 		/* IV explicitly provided ? */
109091d81d1SSam Leffler 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
11008fca7a5SJohn-Mark Gurney 			bcopy(crd->crd_iv, iv, ivlen);
11148b0f2e1SPawel Jakub Dawidek 		else
11208fca7a5SJohn-Mark Gurney 			arc4rand(iv, ivlen, 0);
113091d81d1SSam Leffler 
114091d81d1SSam Leffler 		/* Do we need to write the IV */
115f34a967bSPawel Jakub Dawidek 		if (!(crd->crd_flags & CRD_F_IV_PRESENT))
11608fca7a5SJohn-Mark Gurney 			crypto_copyback(flags, buf, crd->crd_inject, ivlen, iv);
117091d81d1SSam Leffler 
118091d81d1SSam Leffler 	} else {	/* Decryption */
119091d81d1SSam Leffler 		/* IV explicitly provided ? */
120091d81d1SSam Leffler 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
12108fca7a5SJohn-Mark Gurney 			bcopy(crd->crd_iv, iv, ivlen);
122091d81d1SSam Leffler 		else {
123091d81d1SSam Leffler 			/* Get IV off buf */
12408fca7a5SJohn-Mark Gurney 			crypto_copydata(flags, buf, crd->crd_inject, ivlen, iv);
125091d81d1SSam Leffler 		}
126091d81d1SSam Leffler 	}
127091d81d1SSam Leffler 
128c740ae4bSPoul-Henning Kamp 	if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
129c740ae4bSPoul-Henning Kamp 		int error;
130c740ae4bSPoul-Henning Kamp 
131c740ae4bSPoul-Henning Kamp 		if (sw->sw_kschedule)
132c740ae4bSPoul-Henning Kamp 			exf->zerokey(&(sw->sw_kschedule));
13308fca7a5SJohn-Mark Gurney 
134c740ae4bSPoul-Henning Kamp 		error = exf->setkey(&sw->sw_kschedule,
135c740ae4bSPoul-Henning Kamp 				crd->crd_key, crd->crd_klen / 8);
136c740ae4bSPoul-Henning Kamp 		if (error)
137c740ae4bSPoul-Henning Kamp 			return (error);
138c740ae4bSPoul-Henning Kamp 	}
139d295bdeeSPawel Jakub Dawidek 
14008fca7a5SJohn-Mark Gurney 	iov = iovlcl;
14108fca7a5SJohn-Mark Gurney 	iovcnt = nitems(iovlcl);
14208fca7a5SJohn-Mark Gurney 	iovalloc = 0;
14308fca7a5SJohn-Mark Gurney 	uio = &uiolcl;
14408fca7a5SJohn-Mark Gurney 	if ((flags & CRYPTO_F_IMBUF) != 0) {
145748a12e2SJohn-Mark Gurney 		error = crypto_mbuftoiov((struct mbuf *)buf, &iov, &iovcnt,
14608fca7a5SJohn-Mark Gurney 		    &iovalloc);
147748a12e2SJohn-Mark Gurney 		if (error)
148748a12e2SJohn-Mark Gurney 			return (error);
14908fca7a5SJohn-Mark Gurney 		uio->uio_iov = iov;
15008fca7a5SJohn-Mark Gurney 		uio->uio_iovcnt = iovcnt;
15108fca7a5SJohn-Mark Gurney 	} else if ((flags & CRYPTO_F_IOV) != 0)
15208fca7a5SJohn-Mark Gurney 		uio = (struct uio *)buf;
15308fca7a5SJohn-Mark Gurney 	else {
15408fca7a5SJohn-Mark Gurney 		iov[0].iov_base = buf;
15508fca7a5SJohn-Mark Gurney 		iov[0].iov_len = crd->crd_skip + crd->crd_len;
15608fca7a5SJohn-Mark Gurney 		uio->uio_iov = iov;
15708fca7a5SJohn-Mark Gurney 		uio->uio_iovcnt = 1;
15808fca7a5SJohn-Mark Gurney 	}
15908fca7a5SJohn-Mark Gurney 
160091d81d1SSam Leffler 	ivp = iv;
161091d81d1SSam Leffler 
16208fca7a5SJohn-Mark Gurney 	if (exf->reinit) {
163d295bdeeSPawel Jakub Dawidek 		/*
164d295bdeeSPawel Jakub Dawidek 		 * xforms that provide a reinit method perform all IV
165d295bdeeSPawel Jakub Dawidek 		 * handling themselves.
166d295bdeeSPawel Jakub Dawidek 		 */
167d295bdeeSPawel Jakub Dawidek 		exf->reinit(sw->sw_kschedule, iv);
168091d81d1SSam Leffler 	}
169091d81d1SSam Leffler 
17008fca7a5SJohn-Mark Gurney 	count = crd->crd_skip;
17108fca7a5SJohn-Mark Gurney 	ind = cuio_getptr(uio, count, &k);
17208fca7a5SJohn-Mark Gurney 	if (ind == -1) {
17308fca7a5SJohn-Mark Gurney 		error = EINVAL;
17408fca7a5SJohn-Mark Gurney 		goto out;
175091d81d1SSam Leffler 	}
176091d81d1SSam Leffler 
177091d81d1SSam Leffler 	i = crd->crd_len;
178091d81d1SSam Leffler 
179091d81d1SSam Leffler 	while (i > 0) {
180091d81d1SSam Leffler 		/*
181091d81d1SSam Leffler 		 * If there's insufficient data at the end of
182091d81d1SSam Leffler 		 * an iovec, we have to do some copying.
183091d81d1SSam Leffler 		 */
18408fca7a5SJohn-Mark Gurney 		if (uio->uio_iov[ind].iov_len < k + blks &&
18508fca7a5SJohn-Mark Gurney 		    uio->uio_iov[ind].iov_len != k) {
18608fca7a5SJohn-Mark Gurney 			cuio_copydata(uio, count, blks, blk);
187091d81d1SSam Leffler 
188091d81d1SSam Leffler 			/* Actual encryption/decryption */
189d295bdeeSPawel Jakub Dawidek 			if (exf->reinit) {
190091d81d1SSam Leffler 				if (crd->crd_flags & CRD_F_ENCRYPT) {
191d295bdeeSPawel Jakub Dawidek 					exf->encrypt(sw->sw_kschedule,
192d295bdeeSPawel Jakub Dawidek 					    blk);
193d295bdeeSPawel Jakub Dawidek 				} else {
194d295bdeeSPawel Jakub Dawidek 					exf->decrypt(sw->sw_kschedule,
195d295bdeeSPawel Jakub Dawidek 					    blk);
196d295bdeeSPawel Jakub Dawidek 				}
197d295bdeeSPawel Jakub Dawidek 			} else if (crd->crd_flags & CRD_F_ENCRYPT) {
198091d81d1SSam Leffler 				/* XOR with previous block */
199091d81d1SSam Leffler 				for (j = 0; j < blks; j++)
200091d81d1SSam Leffler 					blk[j] ^= ivp[j];
201091d81d1SSam Leffler 
202091d81d1SSam Leffler 				exf->encrypt(sw->sw_kschedule, blk);
203091d81d1SSam Leffler 
204091d81d1SSam Leffler 				/*
205091d81d1SSam Leffler 				 * Keep encrypted block for XOR'ing
206091d81d1SSam Leffler 				 * with next block
207091d81d1SSam Leffler 				 */
208091d81d1SSam Leffler 				bcopy(blk, iv, blks);
209091d81d1SSam Leffler 				ivp = iv;
210091d81d1SSam Leffler 			} else {	/* decrypt */
211091d81d1SSam Leffler 				/*
212091d81d1SSam Leffler 				 * Keep encrypted block for XOR'ing
213091d81d1SSam Leffler 				 * with next block
214091d81d1SSam Leffler 				 */
21508fca7a5SJohn-Mark Gurney 				nivp = (ivp == iv) ? iv2 : iv;
21608fca7a5SJohn-Mark Gurney 				bcopy(blk, nivp, blks);
217091d81d1SSam Leffler 
218091d81d1SSam Leffler 				exf->decrypt(sw->sw_kschedule, blk);
219091d81d1SSam Leffler 
220091d81d1SSam Leffler 				/* XOR with previous block */
221091d81d1SSam Leffler 				for (j = 0; j < blks; j++)
222091d81d1SSam Leffler 					blk[j] ^= ivp[j];
223091d81d1SSam Leffler 
22408fca7a5SJohn-Mark Gurney 				ivp = nivp;
225091d81d1SSam Leffler 			}
226091d81d1SSam Leffler 
227091d81d1SSam Leffler 			/* Copy back decrypted block */
22808fca7a5SJohn-Mark Gurney 			cuio_copyback(uio, count, blks, blk);
22908fca7a5SJohn-Mark Gurney 
23008fca7a5SJohn-Mark Gurney 			count += blks;
231091d81d1SSam Leffler 
232091d81d1SSam Leffler 			/* Advance pointer */
23308fca7a5SJohn-Mark Gurney 			ind = cuio_getptr(uio, count, &k);
23408fca7a5SJohn-Mark Gurney 			if (ind == -1) {
23508fca7a5SJohn-Mark Gurney 				error = EINVAL;
23608fca7a5SJohn-Mark Gurney 				goto out;
23708fca7a5SJohn-Mark Gurney 			}
238091d81d1SSam Leffler 
239091d81d1SSam Leffler 			i -= blks;
240091d81d1SSam Leffler 
241091d81d1SSam Leffler 			/* Could be done... */
242091d81d1SSam Leffler 			if (i == 0)
243091d81d1SSam Leffler 				break;
244091d81d1SSam Leffler 		}
245091d81d1SSam Leffler 
2462f1f9cceSConrad Meyer 		while (uio->uio_iov[ind].iov_len >= k + blks && i > 0) {
2475d7ae54aSConrad Meyer 			uint8_t *idat;
2482f1f9cceSConrad Meyer 			size_t nb, rem;
2492f1f9cceSConrad Meyer 
2502f1f9cceSConrad Meyer 			nb = blks;
251179b21e8SConrad Meyer 			rem = MIN((size_t)i,
252179b21e8SConrad Meyer 			    uio->uio_iov[ind].iov_len - (size_t)k);
2535d7ae54aSConrad Meyer 			idat = (uint8_t *)uio->uio_iov[ind].iov_base + k;
254091d81d1SSam Leffler 
255d295bdeeSPawel Jakub Dawidek 			if (exf->reinit) {
2562f1f9cceSConrad Meyer 				if ((crd->crd_flags & CRD_F_ENCRYPT) != 0 &&
2572f1f9cceSConrad Meyer 				    exf->encrypt_multi == NULL)
258d295bdeeSPawel Jakub Dawidek 					exf->encrypt(sw->sw_kschedule,
259d295bdeeSPawel Jakub Dawidek 					    idat);
2602f1f9cceSConrad Meyer 				else if ((crd->crd_flags & CRD_F_ENCRYPT) != 0) {
2612f1f9cceSConrad Meyer 					nb = rounddown(rem, blks);
2622f1f9cceSConrad Meyer 					exf->encrypt_multi(sw->sw_kschedule,
2632f1f9cceSConrad Meyer 					    idat, nb);
2642f1f9cceSConrad Meyer 				} else if (exf->decrypt_multi == NULL)
265d295bdeeSPawel Jakub Dawidek 					exf->decrypt(sw->sw_kschedule,
266d295bdeeSPawel Jakub Dawidek 					    idat);
2672f1f9cceSConrad Meyer 				else {
2682f1f9cceSConrad Meyer 					nb = rounddown(rem, blks);
2692f1f9cceSConrad Meyer 					exf->decrypt_multi(sw->sw_kschedule,
2702f1f9cceSConrad Meyer 					    idat, nb);
271d295bdeeSPawel Jakub Dawidek 				}
272d295bdeeSPawel Jakub Dawidek 			} else if (crd->crd_flags & CRD_F_ENCRYPT) {
273091d81d1SSam Leffler 				/* XOR with previous block/IV */
274091d81d1SSam Leffler 				for (j = 0; j < blks; j++)
275091d81d1SSam Leffler 					idat[j] ^= ivp[j];
276091d81d1SSam Leffler 
277091d81d1SSam Leffler 				exf->encrypt(sw->sw_kschedule, idat);
278091d81d1SSam Leffler 				ivp = idat;
279091d81d1SSam Leffler 			} else {	/* decrypt */
280091d81d1SSam Leffler 				/*
281091d81d1SSam Leffler 				 * Keep encrypted block to be used
282091d81d1SSam Leffler 				 * in next block's processing.
283091d81d1SSam Leffler 				 */
28408fca7a5SJohn-Mark Gurney 				nivp = (ivp == iv) ? iv2 : iv;
28508fca7a5SJohn-Mark Gurney 				bcopy(idat, nivp, blks);
286091d81d1SSam Leffler 
287091d81d1SSam Leffler 				exf->decrypt(sw->sw_kschedule, idat);
288091d81d1SSam Leffler 
289091d81d1SSam Leffler 				/* XOR with previous block/IV */
290091d81d1SSam Leffler 				for (j = 0; j < blks; j++)
291091d81d1SSam Leffler 					idat[j] ^= ivp[j];
292091d81d1SSam Leffler 
29308fca7a5SJohn-Mark Gurney 				ivp = nivp;
294091d81d1SSam Leffler 			}
295091d81d1SSam Leffler 
2962f1f9cceSConrad Meyer 			count += nb;
2972f1f9cceSConrad Meyer 			k += nb;
2982f1f9cceSConrad Meyer 			i -= nb;
299091d81d1SSam Leffler 		}
300091d81d1SSam Leffler 
301f34a967bSPawel Jakub Dawidek 		/*
30208fca7a5SJohn-Mark Gurney 		 * Advance to the next iov if the end of the current iov
30308fca7a5SJohn-Mark Gurney 		 * is aligned with the end of a cipher block.
30408fca7a5SJohn-Mark Gurney 		 * Note that the code is equivalent to calling:
30508fca7a5SJohn-Mark Gurney 		 *      ind = cuio_getptr(uio, count, &k);
306f34a967bSPawel Jakub Dawidek 		 */
30708fca7a5SJohn-Mark Gurney 		if (i > 0 && k == uio->uio_iov[ind].iov_len) {
30808fca7a5SJohn-Mark Gurney 			k = 0;
30908fca7a5SJohn-Mark Gurney 			ind++;
31008fca7a5SJohn-Mark Gurney 			if (ind >= uio->uio_iovcnt) {
31108fca7a5SJohn-Mark Gurney 				error = EINVAL;
31208fca7a5SJohn-Mark Gurney 				goto out;
31308fca7a5SJohn-Mark Gurney 			}
314f34a967bSPawel Jakub Dawidek 		}
315f34a967bSPawel Jakub Dawidek 	}
316f34a967bSPawel Jakub Dawidek 
31708fca7a5SJohn-Mark Gurney out:
31808fca7a5SJohn-Mark Gurney 	if (iovalloc)
31908fca7a5SJohn-Mark Gurney 		free(iov, M_CRYPTO_DATA);
320091d81d1SSam Leffler 
32108fca7a5SJohn-Mark Gurney 	return (error);
322091d81d1SSam Leffler }
323091d81d1SSam Leffler 
324f6c4bc3bSPawel Jakub Dawidek static void
325f6c4bc3bSPawel Jakub Dawidek swcr_authprepare(struct auth_hash *axf, struct swcr_data *sw, u_char *key,
326f6c4bc3bSPawel Jakub Dawidek     int klen)
327f6c4bc3bSPawel Jakub Dawidek {
328f6c4bc3bSPawel Jakub Dawidek 	int k;
329f6c4bc3bSPawel Jakub Dawidek 
330f6c4bc3bSPawel Jakub Dawidek 	klen /= 8;
331f6c4bc3bSPawel Jakub Dawidek 
332f6c4bc3bSPawel Jakub Dawidek 	switch (axf->type) {
333f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_MD5_HMAC:
334f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA1_HMAC:
335c97f39ceSConrad Meyer 	case CRYPTO_SHA2_224_HMAC:
336f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_256_HMAC:
337f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_384_HMAC:
338f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_512_HMAC:
339f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_NULL_HMAC:
340f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_RIPEMD160_HMAC:
341f6c4bc3bSPawel Jakub Dawidek 		for (k = 0; k < klen; k++)
342f6c4bc3bSPawel Jakub Dawidek 			key[k] ^= HMAC_IPAD_VAL;
343f6c4bc3bSPawel Jakub Dawidek 
344f6c4bc3bSPawel Jakub Dawidek 		axf->Init(sw->sw_ictx);
345f6c4bc3bSPawel Jakub Dawidek 		axf->Update(sw->sw_ictx, key, klen);
346f6c4bc3bSPawel Jakub Dawidek 		axf->Update(sw->sw_ictx, hmac_ipad_buffer, axf->blocksize - klen);
347f6c4bc3bSPawel Jakub Dawidek 
348f6c4bc3bSPawel Jakub Dawidek 		for (k = 0; k < klen; k++)
349f6c4bc3bSPawel Jakub Dawidek 			key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
350f6c4bc3bSPawel Jakub Dawidek 
351f6c4bc3bSPawel Jakub Dawidek 		axf->Init(sw->sw_octx);
352f6c4bc3bSPawel Jakub Dawidek 		axf->Update(sw->sw_octx, key, klen);
353f6c4bc3bSPawel Jakub Dawidek 		axf->Update(sw->sw_octx, hmac_opad_buffer, axf->blocksize - klen);
354f6c4bc3bSPawel Jakub Dawidek 
355f6c4bc3bSPawel Jakub Dawidek 		for (k = 0; k < klen; k++)
356f6c4bc3bSPawel Jakub Dawidek 			key[k] ^= HMAC_OPAD_VAL;
357f6c4bc3bSPawel Jakub Dawidek 		break;
358f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_MD5_KPDK:
359f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA1_KPDK:
3601f4990a6SBjoern A. Zeeb 	{
36177680d96SBjoern A. Zeeb 		/*
36277680d96SBjoern A. Zeeb 		 * We need a buffer that can hold an md5 and a sha1 result
36377680d96SBjoern A. Zeeb 		 * just to throw it away.
36477680d96SBjoern A. Zeeb 		 * What we do here is the initial part of:
36577680d96SBjoern A. Zeeb 		 *   ALGO( key, keyfill, .. )
36677680d96SBjoern A. Zeeb 		 * adding the key to sw_ictx and abusing Final() to get the
36777680d96SBjoern A. Zeeb 		 * "keyfill" padding.
36877680d96SBjoern A. Zeeb 		 * In addition we abuse the sw_octx to save the key to have
36977680d96SBjoern A. Zeeb 		 * it to be able to append it at the end in swcr_authcompute().
37077680d96SBjoern A. Zeeb 		 */
3711f4990a6SBjoern A. Zeeb 		u_char buf[SHA1_RESULTLEN];
3721f4990a6SBjoern A. Zeeb 
373f6c4bc3bSPawel Jakub Dawidek 		sw->sw_klen = klen;
374f6c4bc3bSPawel Jakub Dawidek 		bcopy(key, sw->sw_octx, klen);
375f6c4bc3bSPawel Jakub Dawidek 		axf->Init(sw->sw_ictx);
376f6c4bc3bSPawel Jakub Dawidek 		axf->Update(sw->sw_ictx, key, klen);
3771f4990a6SBjoern A. Zeeb 		axf->Final(buf, sw->sw_ictx);
378f6c4bc3bSPawel Jakub Dawidek 		break;
3791f4990a6SBjoern A. Zeeb 	}
3800e33efe4SConrad Meyer 	case CRYPTO_BLAKE2B:
3810e33efe4SConrad Meyer 	case CRYPTO_BLAKE2S:
3820e33efe4SConrad Meyer 		axf->Setkey(sw->sw_ictx, key, klen);
3830e33efe4SConrad Meyer 		axf->Init(sw->sw_ictx);
3840e33efe4SConrad Meyer 		break;
385f6c4bc3bSPawel Jakub Dawidek 	default:
386f6c4bc3bSPawel Jakub Dawidek 		printf("%s: CRD_F_KEY_EXPLICIT flag given, but algorithm %d "
387f6c4bc3bSPawel Jakub Dawidek 		    "doesn't use keys.\n", __func__, axf->type);
388f6c4bc3bSPawel Jakub Dawidek 	}
389f6c4bc3bSPawel Jakub Dawidek }
390f6c4bc3bSPawel Jakub Dawidek 
391091d81d1SSam Leffler /*
392091d81d1SSam Leffler  * Compute keyed-hash authenticator.
393091d81d1SSam Leffler  */
394091d81d1SSam Leffler static int
39538d2f8d6SPawel Jakub Dawidek swcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
396f34a967bSPawel Jakub Dawidek     int flags)
397091d81d1SSam Leffler {
3980bbc4bf9SPawel Jakub Dawidek 	unsigned char aalg[HASH_MAX_LEN];
399091d81d1SSam Leffler 	struct auth_hash *axf;
400091d81d1SSam Leffler 	union authctx ctx;
401091d81d1SSam Leffler 	int err;
402091d81d1SSam Leffler 
403091d81d1SSam Leffler 	if (sw->sw_ictx == 0)
404091d81d1SSam Leffler 		return EINVAL;
405091d81d1SSam Leffler 
406091d81d1SSam Leffler 	axf = sw->sw_axf;
407091d81d1SSam Leffler 
408f6c4bc3bSPawel Jakub Dawidek 	if (crd->crd_flags & CRD_F_KEY_EXPLICIT)
409f6c4bc3bSPawel Jakub Dawidek 		swcr_authprepare(axf, sw, crd->crd_key, crd->crd_klen);
410f6c4bc3bSPawel Jakub Dawidek 
411091d81d1SSam Leffler 	bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
412091d81d1SSam Leffler 
413f34a967bSPawel Jakub Dawidek 	err = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len,
414f34a967bSPawel Jakub Dawidek 	    (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx);
415091d81d1SSam Leffler 	if (err)
416091d81d1SSam Leffler 		return err;
417091d81d1SSam Leffler 
418091d81d1SSam Leffler 	switch (sw->sw_alg) {
419c4729f6eSConrad Meyer 	case CRYPTO_SHA1:
420c4729f6eSConrad Meyer 	case CRYPTO_SHA2_224:
421c4729f6eSConrad Meyer 	case CRYPTO_SHA2_256:
422c4729f6eSConrad Meyer 	case CRYPTO_SHA2_384:
423c4729f6eSConrad Meyer 	case CRYPTO_SHA2_512:
424c4729f6eSConrad Meyer 		axf->Final(aalg, &ctx);
425c4729f6eSConrad Meyer 		break;
426c4729f6eSConrad Meyer 
427091d81d1SSam Leffler 	case CRYPTO_MD5_HMAC:
428091d81d1SSam Leffler 	case CRYPTO_SHA1_HMAC:
429c97f39ceSConrad Meyer 	case CRYPTO_SHA2_224_HMAC:
430f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_256_HMAC:
431f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_384_HMAC:
432f6c4bc3bSPawel Jakub Dawidek 	case CRYPTO_SHA2_512_HMAC:
433091d81d1SSam Leffler 	case CRYPTO_RIPEMD160_HMAC:
434091d81d1SSam Leffler 		if (sw->sw_octx == NULL)
435091d81d1SSam Leffler 			return EINVAL;
436091d81d1SSam Leffler 
437091d81d1SSam Leffler 		axf->Final(aalg, &ctx);
438091d81d1SSam Leffler 		bcopy(sw->sw_octx, &ctx, axf->ctxsize);
439091d81d1SSam Leffler 		axf->Update(&ctx, aalg, axf->hashsize);
440091d81d1SSam Leffler 		axf->Final(aalg, &ctx);
441091d81d1SSam Leffler 		break;
442091d81d1SSam Leffler 
443091d81d1SSam Leffler 	case CRYPTO_MD5_KPDK:
444091d81d1SSam Leffler 	case CRYPTO_SHA1_KPDK:
44577680d96SBjoern A. Zeeb 		/* If we have no key saved, return error. */
446091d81d1SSam Leffler 		if (sw->sw_octx == NULL)
447091d81d1SSam Leffler 			return EINVAL;
448091d81d1SSam Leffler 
44977680d96SBjoern A. Zeeb 		/*
45077680d96SBjoern A. Zeeb 		 * Add the trailing copy of the key (see comment in
45177680d96SBjoern A. Zeeb 		 * swcr_authprepare()) after the data:
45277680d96SBjoern A. Zeeb 		 *   ALGO( .., key, algofill )
45377680d96SBjoern A. Zeeb 		 * and let Final() do the proper, natural "algofill"
45477680d96SBjoern A. Zeeb 		 * padding.
45577680d96SBjoern A. Zeeb 		 */
456091d81d1SSam Leffler 		axf->Update(&ctx, sw->sw_octx, sw->sw_klen);
457091d81d1SSam Leffler 		axf->Final(aalg, &ctx);
458091d81d1SSam Leffler 		break;
459091d81d1SSam Leffler 
4600e33efe4SConrad Meyer 	case CRYPTO_BLAKE2B:
4610e33efe4SConrad Meyer 	case CRYPTO_BLAKE2S:
462091d81d1SSam Leffler 	case CRYPTO_NULL_HMAC:
463091d81d1SSam Leffler 		axf->Final(aalg, &ctx);
464091d81d1SSam Leffler 		break;
465091d81d1SSam Leffler 	}
466091d81d1SSam Leffler 
467091d81d1SSam Leffler 	/* Inject the authentication data */
468f34a967bSPawel Jakub Dawidek 	crypto_copyback(flags, buf, crd->crd_inject,
469f6c4bc3bSPawel Jakub Dawidek 	    sw->sw_mlen == 0 ? axf->hashsize : sw->sw_mlen, aalg);
470091d81d1SSam Leffler 	return 0;
471091d81d1SSam Leffler }
472091d81d1SSam Leffler 
47308fca7a5SJohn-Mark Gurney CTASSERT(INT_MAX <= (1ll<<39) - 256);	/* GCM: plain text < 2^39-256 */
47408fca7a5SJohn-Mark Gurney CTASSERT(INT_MAX <= (uint64_t)-1);	/* GCM: associated data <= 2^64-1 */
47508fca7a5SJohn-Mark Gurney 
47608fca7a5SJohn-Mark Gurney /*
47708fca7a5SJohn-Mark Gurney  * Apply a combined encryption-authentication transformation
47808fca7a5SJohn-Mark Gurney  */
47908fca7a5SJohn-Mark Gurney static int
48008fca7a5SJohn-Mark Gurney swcr_authenc(struct cryptop *crp)
48108fca7a5SJohn-Mark Gurney {
48208fca7a5SJohn-Mark Gurney 	uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
48308fca7a5SJohn-Mark Gurney 	u_char *blk = (u_char *)blkbuf;
48408fca7a5SJohn-Mark Gurney 	u_char aalg[AALG_MAX_RESULT_LEN];
48508fca7a5SJohn-Mark Gurney 	u_char uaalg[AALG_MAX_RESULT_LEN];
48608fca7a5SJohn-Mark Gurney 	u_char iv[EALG_MAX_BLOCK_LEN];
48708fca7a5SJohn-Mark Gurney 	union authctx ctx;
48808fca7a5SJohn-Mark Gurney 	struct cryptodesc *crd, *crda = NULL, *crde = NULL;
48908fca7a5SJohn-Mark Gurney 	struct swcr_data *sw, *swa, *swe = NULL;
49008fca7a5SJohn-Mark Gurney 	struct auth_hash *axf = NULL;
49108fca7a5SJohn-Mark Gurney 	struct enc_xform *exf = NULL;
49208fca7a5SJohn-Mark Gurney 	caddr_t buf = (caddr_t)crp->crp_buf;
49308fca7a5SJohn-Mark Gurney 	uint32_t *blkp;
49408fca7a5SJohn-Mark Gurney 	int aadlen, blksz, i, ivlen, len, iskip, oskip, r;
49508fca7a5SJohn-Mark Gurney 
49608fca7a5SJohn-Mark Gurney 	ivlen = blksz = iskip = oskip = 0;
49708fca7a5SJohn-Mark Gurney 
49808fca7a5SJohn-Mark Gurney 	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
499*1b0909d5SConrad Meyer 		for (sw = crypto_get_driver_session(crp->crp_session);
50008fca7a5SJohn-Mark Gurney 		     sw && sw->sw_alg != crd->crd_alg;
50108fca7a5SJohn-Mark Gurney 		     sw = sw->sw_next)
50208fca7a5SJohn-Mark Gurney 			;
50308fca7a5SJohn-Mark Gurney 		if (sw == NULL)
50408fca7a5SJohn-Mark Gurney 			return (EINVAL);
50508fca7a5SJohn-Mark Gurney 
50608fca7a5SJohn-Mark Gurney 		switch (sw->sw_alg) {
50708fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GCM_16:
50808fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GMAC:
50908fca7a5SJohn-Mark Gurney 			swe = sw;
51008fca7a5SJohn-Mark Gurney 			crde = crd;
51108fca7a5SJohn-Mark Gurney 			exf = swe->sw_exf;
51208fca7a5SJohn-Mark Gurney 			ivlen = 12;
51308fca7a5SJohn-Mark Gurney 			break;
51408fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_128_NIST_GMAC:
51508fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_192_NIST_GMAC:
51608fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_256_NIST_GMAC:
51708fca7a5SJohn-Mark Gurney 			swa = sw;
51808fca7a5SJohn-Mark Gurney 			crda = crd;
51908fca7a5SJohn-Mark Gurney 			axf = swa->sw_axf;
52008fca7a5SJohn-Mark Gurney 			if (swa->sw_ictx == 0)
52108fca7a5SJohn-Mark Gurney 				return (EINVAL);
52208fca7a5SJohn-Mark Gurney 			bcopy(swa->sw_ictx, &ctx, axf->ctxsize);
52308fca7a5SJohn-Mark Gurney 			blksz = axf->blocksize;
52408fca7a5SJohn-Mark Gurney 			break;
52508fca7a5SJohn-Mark Gurney 		default:
52608fca7a5SJohn-Mark Gurney 			return (EINVAL);
52708fca7a5SJohn-Mark Gurney 		}
52808fca7a5SJohn-Mark Gurney 	}
52908fca7a5SJohn-Mark Gurney 	if (crde == NULL || crda == NULL)
53008fca7a5SJohn-Mark Gurney 		return (EINVAL);
53108fca7a5SJohn-Mark Gurney 
53208fca7a5SJohn-Mark Gurney 	if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 &&
53308fca7a5SJohn-Mark Gurney 	    (crde->crd_flags & CRD_F_IV_EXPLICIT) == 0)
53408fca7a5SJohn-Mark Gurney 		return (EINVAL);
53508fca7a5SJohn-Mark Gurney 
53608fca7a5SJohn-Mark Gurney 	if (crde->crd_klen != crda->crd_klen)
53708fca7a5SJohn-Mark Gurney 		return (EINVAL);
53808fca7a5SJohn-Mark Gurney 
53908fca7a5SJohn-Mark Gurney 	/* Initialize the IV */
54008fca7a5SJohn-Mark Gurney 	if (crde->crd_flags & CRD_F_ENCRYPT) {
54108fca7a5SJohn-Mark Gurney 		/* IV explicitly provided ? */
54208fca7a5SJohn-Mark Gurney 		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
54308fca7a5SJohn-Mark Gurney 			bcopy(crde->crd_iv, iv, ivlen);
54408fca7a5SJohn-Mark Gurney 		else
54508fca7a5SJohn-Mark Gurney 			arc4rand(iv, ivlen, 0);
54608fca7a5SJohn-Mark Gurney 
54708fca7a5SJohn-Mark Gurney 		/* Do we need to write the IV */
54808fca7a5SJohn-Mark Gurney 		if (!(crde->crd_flags & CRD_F_IV_PRESENT))
54908fca7a5SJohn-Mark Gurney 			crypto_copyback(crp->crp_flags, buf, crde->crd_inject,
55008fca7a5SJohn-Mark Gurney 			    ivlen, iv);
55108fca7a5SJohn-Mark Gurney 
55208fca7a5SJohn-Mark Gurney 	} else {	/* Decryption */
55308fca7a5SJohn-Mark Gurney 			/* IV explicitly provided ? */
55408fca7a5SJohn-Mark Gurney 		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
55508fca7a5SJohn-Mark Gurney 			bcopy(crde->crd_iv, iv, ivlen);
55608fca7a5SJohn-Mark Gurney 		else {
55708fca7a5SJohn-Mark Gurney 			/* Get IV off buf */
55808fca7a5SJohn-Mark Gurney 			crypto_copydata(crp->crp_flags, buf, crde->crd_inject,
55908fca7a5SJohn-Mark Gurney 			    ivlen, iv);
56008fca7a5SJohn-Mark Gurney 		}
56108fca7a5SJohn-Mark Gurney 	}
56208fca7a5SJohn-Mark Gurney 
56308fca7a5SJohn-Mark Gurney 	/* Supply MAC with IV */
56408fca7a5SJohn-Mark Gurney 	if (axf->Reinit)
56508fca7a5SJohn-Mark Gurney 		axf->Reinit(&ctx, iv, ivlen);
56608fca7a5SJohn-Mark Gurney 
56708fca7a5SJohn-Mark Gurney 	/* Supply MAC with AAD */
56808fca7a5SJohn-Mark Gurney 	aadlen = crda->crd_len;
56908fca7a5SJohn-Mark Gurney 
57008fca7a5SJohn-Mark Gurney 	for (i = iskip; i < crda->crd_len; i += blksz) {
57108fca7a5SJohn-Mark Gurney 		len = MIN(crda->crd_len - i, blksz - oskip);
57208fca7a5SJohn-Mark Gurney 		crypto_copydata(crp->crp_flags, buf, crda->crd_skip + i, len,
57308fca7a5SJohn-Mark Gurney 		    blk + oskip);
57408fca7a5SJohn-Mark Gurney 		bzero(blk + len + oskip, blksz - len - oskip);
57508fca7a5SJohn-Mark Gurney 		axf->Update(&ctx, blk, blksz);
57608fca7a5SJohn-Mark Gurney 		oskip = 0; /* reset initial output offset */
57708fca7a5SJohn-Mark Gurney 	}
57808fca7a5SJohn-Mark Gurney 
57908fca7a5SJohn-Mark Gurney 	if (exf->reinit)
58008fca7a5SJohn-Mark Gurney 		exf->reinit(swe->sw_kschedule, iv);
58108fca7a5SJohn-Mark Gurney 
58208fca7a5SJohn-Mark Gurney 	/* Do encryption/decryption with MAC */
5832f1f9cceSConrad Meyer 	for (i = 0; i < crde->crd_len; i += len) {
5842f1f9cceSConrad Meyer 		if (exf->encrypt_multi != NULL) {
5852f1f9cceSConrad Meyer 			len = rounddown(crde->crd_len - i, blksz);
5862f1f9cceSConrad Meyer 			if (len == 0)
5872f1f9cceSConrad Meyer 				len = blksz;
5882f1f9cceSConrad Meyer 			else
5892f1f9cceSConrad Meyer 				len = MIN(len, sizeof(blkbuf));
5902f1f9cceSConrad Meyer 		} else
5912f1f9cceSConrad Meyer 			len = blksz;
5922f1f9cceSConrad Meyer 		len = MIN(crde->crd_len - i, len);
59308fca7a5SJohn-Mark Gurney 		if (len < blksz)
59408fca7a5SJohn-Mark Gurney 			bzero(blk, blksz);
59508fca7a5SJohn-Mark Gurney 		crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len,
59608fca7a5SJohn-Mark Gurney 		    blk);
59708fca7a5SJohn-Mark Gurney 		if (crde->crd_flags & CRD_F_ENCRYPT) {
5982f1f9cceSConrad Meyer 			if (exf->encrypt_multi != NULL)
5992f1f9cceSConrad Meyer 				exf->encrypt_multi(swe->sw_kschedule, blk,
6002f1f9cceSConrad Meyer 				    len);
6012f1f9cceSConrad Meyer 			else
60208fca7a5SJohn-Mark Gurney 				exf->encrypt(swe->sw_kschedule, blk);
60308fca7a5SJohn-Mark Gurney 			axf->Update(&ctx, blk, len);
60408fca7a5SJohn-Mark Gurney 			crypto_copyback(crp->crp_flags, buf,
60508fca7a5SJohn-Mark Gurney 			    crde->crd_skip + i, len, blk);
60608fca7a5SJohn-Mark Gurney 		} else {
60708fca7a5SJohn-Mark Gurney 			axf->Update(&ctx, blk, len);
60808fca7a5SJohn-Mark Gurney 		}
60908fca7a5SJohn-Mark Gurney 	}
61008fca7a5SJohn-Mark Gurney 
61108fca7a5SJohn-Mark Gurney 	/* Do any required special finalization */
61208fca7a5SJohn-Mark Gurney 	switch (crda->crd_alg) {
61308fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_128_NIST_GMAC:
61408fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_192_NIST_GMAC:
61508fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_256_NIST_GMAC:
61608fca7a5SJohn-Mark Gurney 			/* length block */
61708fca7a5SJohn-Mark Gurney 			bzero(blk, blksz);
61808fca7a5SJohn-Mark Gurney 			blkp = (uint32_t *)blk + 1;
61908fca7a5SJohn-Mark Gurney 			*blkp = htobe32(aadlen * 8);
62008fca7a5SJohn-Mark Gurney 			blkp = (uint32_t *)blk + 3;
62108fca7a5SJohn-Mark Gurney 			*blkp = htobe32(crde->crd_len * 8);
62208fca7a5SJohn-Mark Gurney 			axf->Update(&ctx, blk, blksz);
62308fca7a5SJohn-Mark Gurney 			break;
62408fca7a5SJohn-Mark Gurney 	}
62508fca7a5SJohn-Mark Gurney 
62608fca7a5SJohn-Mark Gurney 	/* Finalize MAC */
62708fca7a5SJohn-Mark Gurney 	axf->Final(aalg, &ctx);
62808fca7a5SJohn-Mark Gurney 
62908fca7a5SJohn-Mark Gurney 	/* Validate tag */
63008fca7a5SJohn-Mark Gurney 	if (!(crde->crd_flags & CRD_F_ENCRYPT)) {
63108fca7a5SJohn-Mark Gurney 		crypto_copydata(crp->crp_flags, buf, crda->crd_inject,
63208fca7a5SJohn-Mark Gurney 		    axf->hashsize, uaalg);
63308fca7a5SJohn-Mark Gurney 
63408fca7a5SJohn-Mark Gurney 		r = timingsafe_bcmp(aalg, uaalg, axf->hashsize);
63508fca7a5SJohn-Mark Gurney 		if (r == 0) {
63608fca7a5SJohn-Mark Gurney 			/* tag matches, decrypt data */
63708fca7a5SJohn-Mark Gurney 			for (i = 0; i < crde->crd_len; i += blksz) {
63808fca7a5SJohn-Mark Gurney 				len = MIN(crde->crd_len - i, blksz);
63908fca7a5SJohn-Mark Gurney 				if (len < blksz)
64008fca7a5SJohn-Mark Gurney 					bzero(blk, blksz);
64108fca7a5SJohn-Mark Gurney 				crypto_copydata(crp->crp_flags, buf,
64208fca7a5SJohn-Mark Gurney 				    crde->crd_skip + i, len, blk);
64308fca7a5SJohn-Mark Gurney 				exf->decrypt(swe->sw_kschedule, blk);
64408fca7a5SJohn-Mark Gurney 				crypto_copyback(crp->crp_flags, buf,
64508fca7a5SJohn-Mark Gurney 				    crde->crd_skip + i, len, blk);
64608fca7a5SJohn-Mark Gurney 			}
64708fca7a5SJohn-Mark Gurney 		} else
64808fca7a5SJohn-Mark Gurney 			return (EBADMSG);
64908fca7a5SJohn-Mark Gurney 	} else {
65008fca7a5SJohn-Mark Gurney 		/* Inject the authentication data */
65108fca7a5SJohn-Mark Gurney 		crypto_copyback(crp->crp_flags, buf, crda->crd_inject,
65208fca7a5SJohn-Mark Gurney 		    axf->hashsize, aalg);
65308fca7a5SJohn-Mark Gurney 	}
65408fca7a5SJohn-Mark Gurney 
65508fca7a5SJohn-Mark Gurney 	return (0);
65608fca7a5SJohn-Mark Gurney }
65708fca7a5SJohn-Mark Gurney 
658091d81d1SSam Leffler /*
659091d81d1SSam Leffler  * Apply a compression/decompression algorithm
660091d81d1SSam Leffler  */
661091d81d1SSam Leffler static int
662091d81d1SSam Leffler swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw,
663f34a967bSPawel Jakub Dawidek     caddr_t buf, int flags)
664091d81d1SSam Leffler {
665091d81d1SSam Leffler 	u_int8_t *data, *out;
666091d81d1SSam Leffler 	struct comp_algo *cxf;
667091d81d1SSam Leffler 	int adj;
668091d81d1SSam Leffler 	u_int32_t result;
669091d81d1SSam Leffler 
670091d81d1SSam Leffler 	cxf = sw->sw_cxf;
671091d81d1SSam Leffler 
672091d81d1SSam Leffler 	/* We must handle the whole buffer of data in one time
673091d81d1SSam Leffler 	 * then if there is not all the data in the mbuf, we must
674091d81d1SSam Leffler 	 * copy in a buffer.
675091d81d1SSam Leffler 	 */
676091d81d1SSam Leffler 
6771ede983cSDag-Erling Smørgrav 	data = malloc(crd->crd_len, M_CRYPTO_DATA,  M_NOWAIT);
678091d81d1SSam Leffler 	if (data == NULL)
679091d81d1SSam Leffler 		return (EINVAL);
680f34a967bSPawel Jakub Dawidek 	crypto_copydata(flags, buf, crd->crd_skip, crd->crd_len, data);
681091d81d1SSam Leffler 
682091d81d1SSam Leffler 	if (crd->crd_flags & CRD_F_COMP)
683091d81d1SSam Leffler 		result = cxf->compress(data, crd->crd_len, &out);
684091d81d1SSam Leffler 	else
685091d81d1SSam Leffler 		result = cxf->decompress(data, crd->crd_len, &out);
686091d81d1SSam Leffler 
6871ede983cSDag-Erling Smørgrav 	free(data, M_CRYPTO_DATA);
688091d81d1SSam Leffler 	if (result == 0)
689091d81d1SSam Leffler 		return EINVAL;
690091d81d1SSam Leffler 
691091d81d1SSam Leffler 	/* Copy back the (de)compressed data. m_copyback is
692091d81d1SSam Leffler 	 * extending the mbuf as necessary.
693091d81d1SSam Leffler 	 */
694091d81d1SSam Leffler 	sw->sw_size = result;
695091d81d1SSam Leffler 	/* Check the compressed size when doing compression */
696091d81d1SSam Leffler 	if (crd->crd_flags & CRD_F_COMP) {
697df4dece1SBjoern A. Zeeb 		if (result >= crd->crd_len) {
698091d81d1SSam Leffler 			/* Compression was useless, we lost time */
6991ede983cSDag-Erling Smørgrav 			free(out, M_CRYPTO_DATA);
700091d81d1SSam Leffler 			return 0;
701091d81d1SSam Leffler 		}
702091d81d1SSam Leffler 	}
703091d81d1SSam Leffler 
704f34a967bSPawel Jakub Dawidek 	crypto_copyback(flags, buf, crd->crd_skip, result, out);
705091d81d1SSam Leffler 	if (result < crd->crd_len) {
706091d81d1SSam Leffler 		adj = result - crd->crd_len;
707f34a967bSPawel Jakub Dawidek 		if (flags & CRYPTO_F_IMBUF) {
708091d81d1SSam Leffler 			adj = result - crd->crd_len;
709091d81d1SSam Leffler 			m_adj((struct mbuf *)buf, adj);
710f34a967bSPawel Jakub Dawidek 		} else if (flags & CRYPTO_F_IOV) {
711091d81d1SSam Leffler 			struct uio *uio = (struct uio *)buf;
712091d81d1SSam Leffler 			int ind;
713091d81d1SSam Leffler 
714091d81d1SSam Leffler 			adj = crd->crd_len - result;
715091d81d1SSam Leffler 			ind = uio->uio_iovcnt - 1;
716091d81d1SSam Leffler 
717091d81d1SSam Leffler 			while (adj > 0 && ind >= 0) {
718091d81d1SSam Leffler 				if (adj < uio->uio_iov[ind].iov_len) {
719091d81d1SSam Leffler 					uio->uio_iov[ind].iov_len -= adj;
720091d81d1SSam Leffler 					break;
721091d81d1SSam Leffler 				}
722091d81d1SSam Leffler 
723091d81d1SSam Leffler 				adj -= uio->uio_iov[ind].iov_len;
724091d81d1SSam Leffler 				uio->uio_iov[ind].iov_len = 0;
725091d81d1SSam Leffler 				ind--;
726091d81d1SSam Leffler 				uio->uio_iovcnt--;
727091d81d1SSam Leffler 			}
728091d81d1SSam Leffler 		}
729091d81d1SSam Leffler 	}
7301ede983cSDag-Erling Smørgrav 	free(out, M_CRYPTO_DATA);
731091d81d1SSam Leffler 	return 0;
732091d81d1SSam Leffler }
733091d81d1SSam Leffler 
734091d81d1SSam Leffler /*
735091d81d1SSam Leffler  * Generate a new software session.
736091d81d1SSam Leffler  */
737091d81d1SSam Leffler static int
738*1b0909d5SConrad Meyer swcr_newsession(device_t dev, crypto_session_t cses, struct cryptoini *cri)
739091d81d1SSam Leffler {
740*1b0909d5SConrad Meyer 	struct swcr_data **swd, *ses;
741091d81d1SSam Leffler 	struct auth_hash *axf;
742091d81d1SSam Leffler 	struct enc_xform *txf;
743091d81d1SSam Leffler 	struct comp_algo *cxf;
744a2bc81bfSJohn-Mark Gurney 	int len;
745f6c4bc3bSPawel Jakub Dawidek 	int error;
746091d81d1SSam Leffler 
747*1b0909d5SConrad Meyer 	if (cses == NULL || cri == NULL)
748091d81d1SSam Leffler 		return EINVAL;
749091d81d1SSam Leffler 
750*1b0909d5SConrad Meyer 	ses = crypto_get_driver_session(cses);
751*1b0909d5SConrad Meyer 	swd = &ses;
752091d81d1SSam Leffler 
753091d81d1SSam Leffler 	while (cri) {
754*1b0909d5SConrad Meyer 		if (*swd == NULL)
7551ede983cSDag-Erling Smørgrav 			*swd = malloc(sizeof(struct swcr_data),
756*1b0909d5SConrad Meyer 			    M_CRYPTO_DATA, M_WAITOK | M_ZERO);
757091d81d1SSam Leffler 		if (*swd == NULL) {
758*1b0909d5SConrad Meyer 			swcr_freesession(dev, cses);
759091d81d1SSam Leffler 			return ENOBUFS;
760091d81d1SSam Leffler 		}
761091d81d1SSam Leffler 
762091d81d1SSam Leffler 		switch (cri->cri_alg) {
763091d81d1SSam Leffler 		case CRYPTO_DES_CBC:
764091d81d1SSam Leffler 			txf = &enc_xform_des;
765091d81d1SSam Leffler 			goto enccommon;
766091d81d1SSam Leffler 		case CRYPTO_3DES_CBC:
767091d81d1SSam Leffler 			txf = &enc_xform_3des;
768091d81d1SSam Leffler 			goto enccommon;
769091d81d1SSam Leffler 		case CRYPTO_BLF_CBC:
770091d81d1SSam Leffler 			txf = &enc_xform_blf;
771091d81d1SSam Leffler 			goto enccommon;
772091d81d1SSam Leffler 		case CRYPTO_CAST_CBC:
773091d81d1SSam Leffler 			txf = &enc_xform_cast5;
774091d81d1SSam Leffler 			goto enccommon;
775091d81d1SSam Leffler 		case CRYPTO_SKIPJACK_CBC:
776091d81d1SSam Leffler 			txf = &enc_xform_skipjack;
777091d81d1SSam Leffler 			goto enccommon;
778091d81d1SSam Leffler 		case CRYPTO_RIJNDAEL128_CBC:
779091d81d1SSam Leffler 			txf = &enc_xform_rijndael128;
780091d81d1SSam Leffler 			goto enccommon;
781d295bdeeSPawel Jakub Dawidek 		case CRYPTO_AES_XTS:
782d295bdeeSPawel Jakub Dawidek 			txf = &enc_xform_aes_xts;
783d295bdeeSPawel Jakub Dawidek 			goto enccommon;
78408fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_ICM:
78508fca7a5SJohn-Mark Gurney 			txf = &enc_xform_aes_icm;
78608fca7a5SJohn-Mark Gurney 			goto enccommon;
78708fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GCM_16:
78808fca7a5SJohn-Mark Gurney 			txf = &enc_xform_aes_nist_gcm;
78908fca7a5SJohn-Mark Gurney 			goto enccommon;
79008fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GMAC:
79108fca7a5SJohn-Mark Gurney 			txf = &enc_xform_aes_nist_gmac;
79208fca7a5SJohn-Mark Gurney 			(*swd)->sw_exf = txf;
79308fca7a5SJohn-Mark Gurney 			break;
794559d3390SGeorge V. Neville-Neil 		case CRYPTO_CAMELLIA_CBC:
795559d3390SGeorge V. Neville-Neil 			txf = &enc_xform_camellia;
796559d3390SGeorge V. Neville-Neil 			goto enccommon;
797091d81d1SSam Leffler 		case CRYPTO_NULL_CBC:
798091d81d1SSam Leffler 			txf = &enc_xform_null;
799091d81d1SSam Leffler 			goto enccommon;
80061590291SConrad Meyer 		case CRYPTO_CHACHA20:
80161590291SConrad Meyer 			txf = &enc_xform_chacha20;
80261590291SConrad Meyer 			goto enccommon;
803091d81d1SSam Leffler 		enccommon:
804f6c4bc3bSPawel Jakub Dawidek 			if (cri->cri_key != NULL) {
805091d81d1SSam Leffler 				error = txf->setkey(&((*swd)->sw_kschedule),
806091d81d1SSam Leffler 				    cri->cri_key, cri->cri_klen / 8);
807091d81d1SSam Leffler 				if (error) {
808*1b0909d5SConrad Meyer 					swcr_freesession(dev, cses);
809091d81d1SSam Leffler 					return error;
810091d81d1SSam Leffler 				}
811f6c4bc3bSPawel Jakub Dawidek 			}
812091d81d1SSam Leffler 			(*swd)->sw_exf = txf;
813091d81d1SSam Leffler 			break;
814091d81d1SSam Leffler 
815091d81d1SSam Leffler 		case CRYPTO_MD5_HMAC:
816f6c4bc3bSPawel Jakub Dawidek 			axf = &auth_hash_hmac_md5;
817091d81d1SSam Leffler 			goto authcommon;
818091d81d1SSam Leffler 		case CRYPTO_SHA1_HMAC:
819f6c4bc3bSPawel Jakub Dawidek 			axf = &auth_hash_hmac_sha1;
820091d81d1SSam Leffler 			goto authcommon;
821c97f39ceSConrad Meyer 		case CRYPTO_SHA2_224_HMAC:
822c97f39ceSConrad Meyer 			axf = &auth_hash_hmac_sha2_224;
823c97f39ceSConrad Meyer 			goto authcommon;
824f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_256_HMAC:
825091d81d1SSam Leffler 			axf = &auth_hash_hmac_sha2_256;
826f6c4bc3bSPawel Jakub Dawidek 			goto authcommon;
827f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_384_HMAC:
828091d81d1SSam Leffler 			axf = &auth_hash_hmac_sha2_384;
829f6c4bc3bSPawel Jakub Dawidek 			goto authcommon;
830f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_512_HMAC:
831091d81d1SSam Leffler 			axf = &auth_hash_hmac_sha2_512;
832091d81d1SSam Leffler 			goto authcommon;
833091d81d1SSam Leffler 		case CRYPTO_NULL_HMAC:
834091d81d1SSam Leffler 			axf = &auth_hash_null;
835091d81d1SSam Leffler 			goto authcommon;
836091d81d1SSam Leffler 		case CRYPTO_RIPEMD160_HMAC:
837f6c4bc3bSPawel Jakub Dawidek 			axf = &auth_hash_hmac_ripemd_160;
838091d81d1SSam Leffler 		authcommon:
839091d81d1SSam Leffler 			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
840091d81d1SSam Leffler 			    M_NOWAIT);
841091d81d1SSam Leffler 			if ((*swd)->sw_ictx == NULL) {
842*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
843091d81d1SSam Leffler 				return ENOBUFS;
844091d81d1SSam Leffler 			}
845091d81d1SSam Leffler 
846091d81d1SSam Leffler 			(*swd)->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
847091d81d1SSam Leffler 			    M_NOWAIT);
848091d81d1SSam Leffler 			if ((*swd)->sw_octx == NULL) {
849*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
850091d81d1SSam Leffler 				return ENOBUFS;
851091d81d1SSam Leffler 			}
852091d81d1SSam Leffler 
853f6c4bc3bSPawel Jakub Dawidek 			if (cri->cri_key != NULL) {
854f6c4bc3bSPawel Jakub Dawidek 				swcr_authprepare(axf, *swd, cri->cri_key,
855f6c4bc3bSPawel Jakub Dawidek 				    cri->cri_klen);
856f6c4bc3bSPawel Jakub Dawidek 			}
857091d81d1SSam Leffler 
858f6c4bc3bSPawel Jakub Dawidek 			(*swd)->sw_mlen = cri->cri_mlen;
859091d81d1SSam Leffler 			(*swd)->sw_axf = axf;
860091d81d1SSam Leffler 			break;
861091d81d1SSam Leffler 
862091d81d1SSam Leffler 		case CRYPTO_MD5_KPDK:
863091d81d1SSam Leffler 			axf = &auth_hash_key_md5;
864091d81d1SSam Leffler 			goto auth2common;
865091d81d1SSam Leffler 
866091d81d1SSam Leffler 		case CRYPTO_SHA1_KPDK:
867091d81d1SSam Leffler 			axf = &auth_hash_key_sha1;
868091d81d1SSam Leffler 		auth2common:
869091d81d1SSam Leffler 			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
870091d81d1SSam Leffler 			    M_NOWAIT);
871091d81d1SSam Leffler 			if ((*swd)->sw_ictx == NULL) {
872*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
873091d81d1SSam Leffler 				return ENOBUFS;
874091d81d1SSam Leffler 			}
875091d81d1SSam Leffler 
876f6c4bc3bSPawel Jakub Dawidek 			(*swd)->sw_octx = malloc(cri->cri_klen / 8,
877f6c4bc3bSPawel Jakub Dawidek 			    M_CRYPTO_DATA, M_NOWAIT);
878091d81d1SSam Leffler 			if ((*swd)->sw_octx == NULL) {
879*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
880091d81d1SSam Leffler 				return ENOBUFS;
881091d81d1SSam Leffler 			}
882091d81d1SSam Leffler 
883f6c4bc3bSPawel Jakub Dawidek 			/* Store the key so we can "append" it to the payload */
884f6c4bc3bSPawel Jakub Dawidek 			if (cri->cri_key != NULL) {
885f6c4bc3bSPawel Jakub Dawidek 				swcr_authprepare(axf, *swd, cri->cri_key,
886f6c4bc3bSPawel Jakub Dawidek 				    cri->cri_klen);
887f6c4bc3bSPawel Jakub Dawidek 			}
888f6c4bc3bSPawel Jakub Dawidek 
889f6c4bc3bSPawel Jakub Dawidek 			(*swd)->sw_mlen = cri->cri_mlen;
890091d81d1SSam Leffler 			(*swd)->sw_axf = axf;
891091d81d1SSam Leffler 			break;
892091d81d1SSam Leffler #ifdef notdef
893091d81d1SSam Leffler 		case CRYPTO_MD5:
894091d81d1SSam Leffler 			axf = &auth_hash_md5;
895091d81d1SSam Leffler 			goto auth3common;
896c4729f6eSConrad Meyer #endif
897091d81d1SSam Leffler 
898091d81d1SSam Leffler 		case CRYPTO_SHA1:
899091d81d1SSam Leffler 			axf = &auth_hash_sha1;
900c4729f6eSConrad Meyer 			goto auth3common;
901c4729f6eSConrad Meyer 		case CRYPTO_SHA2_224:
902c4729f6eSConrad Meyer 			axf = &auth_hash_sha2_224;
903c4729f6eSConrad Meyer 			goto auth3common;
904c4729f6eSConrad Meyer 		case CRYPTO_SHA2_256:
905c4729f6eSConrad Meyer 			axf = &auth_hash_sha2_256;
906c4729f6eSConrad Meyer 			goto auth3common;
907c4729f6eSConrad Meyer 		case CRYPTO_SHA2_384:
908c4729f6eSConrad Meyer 			axf = &auth_hash_sha2_384;
909c4729f6eSConrad Meyer 			goto auth3common;
910c4729f6eSConrad Meyer 		case CRYPTO_SHA2_512:
911c4729f6eSConrad Meyer 			axf = &auth_hash_sha2_512;
912c4729f6eSConrad Meyer 
913091d81d1SSam Leffler 		auth3common:
914091d81d1SSam Leffler 			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
915091d81d1SSam Leffler 			    M_NOWAIT);
916091d81d1SSam Leffler 			if ((*swd)->sw_ictx == NULL) {
917*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
918091d81d1SSam Leffler 				return ENOBUFS;
919091d81d1SSam Leffler 			}
920091d81d1SSam Leffler 
921091d81d1SSam Leffler 			axf->Init((*swd)->sw_ictx);
922f6c4bc3bSPawel Jakub Dawidek 			(*swd)->sw_mlen = cri->cri_mlen;
923091d81d1SSam Leffler 			(*swd)->sw_axf = axf;
924091d81d1SSam Leffler 			break;
92508fca7a5SJohn-Mark Gurney 
92608fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_128_NIST_GMAC:
92708fca7a5SJohn-Mark Gurney 			axf = &auth_hash_nist_gmac_aes_128;
92808fca7a5SJohn-Mark Gurney 			goto auth4common;
92908fca7a5SJohn-Mark Gurney 
93008fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_192_NIST_GMAC:
93108fca7a5SJohn-Mark Gurney 			axf = &auth_hash_nist_gmac_aes_192;
93208fca7a5SJohn-Mark Gurney 			goto auth4common;
93308fca7a5SJohn-Mark Gurney 
93408fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_256_NIST_GMAC:
93508fca7a5SJohn-Mark Gurney 			axf = &auth_hash_nist_gmac_aes_256;
93608fca7a5SJohn-Mark Gurney 		auth4common:
937a2bc81bfSJohn-Mark Gurney 			len = cri->cri_klen / 8;
9382e2e26d1SJohn Baldwin 			if (len != 16 && len != 24 && len != 32) {
939*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
940a2bc81bfSJohn-Mark Gurney 				return EINVAL;
9412e2e26d1SJohn Baldwin 			}
942a2bc81bfSJohn-Mark Gurney 
94308fca7a5SJohn-Mark Gurney 			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
94408fca7a5SJohn-Mark Gurney 			    M_NOWAIT);
94508fca7a5SJohn-Mark Gurney 			if ((*swd)->sw_ictx == NULL) {
946*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
94708fca7a5SJohn-Mark Gurney 				return ENOBUFS;
94808fca7a5SJohn-Mark Gurney 			}
94908fca7a5SJohn-Mark Gurney 			axf->Init((*swd)->sw_ictx);
950a2bc81bfSJohn-Mark Gurney 			axf->Setkey((*swd)->sw_ictx, cri->cri_key, len);
95108fca7a5SJohn-Mark Gurney 			(*swd)->sw_axf = axf;
95208fca7a5SJohn-Mark Gurney 			break;
95308fca7a5SJohn-Mark Gurney 
9540e33efe4SConrad Meyer 		case CRYPTO_BLAKE2B:
9550e33efe4SConrad Meyer 			axf = &auth_hash_blake2b;
9560e33efe4SConrad Meyer 			goto auth5common;
9570e33efe4SConrad Meyer 		case CRYPTO_BLAKE2S:
9580e33efe4SConrad Meyer 			axf = &auth_hash_blake2s;
9590e33efe4SConrad Meyer 		auth5common:
9600e33efe4SConrad Meyer 			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
9610e33efe4SConrad Meyer 			    M_NOWAIT);
9620e33efe4SConrad Meyer 			if ((*swd)->sw_ictx == NULL) {
963*1b0909d5SConrad Meyer 				swcr_freesession(dev, cses);
9640e33efe4SConrad Meyer 				return ENOBUFS;
9650e33efe4SConrad Meyer 			}
9660e33efe4SConrad Meyer 			axf->Setkey((*swd)->sw_ictx, cri->cri_key,
9670e33efe4SConrad Meyer 			    cri->cri_klen / 8);
9680e33efe4SConrad Meyer 			axf->Init((*swd)->sw_ictx);
9690e33efe4SConrad Meyer 			(*swd)->sw_axf = axf;
9700e33efe4SConrad Meyer 			break;
9710e33efe4SConrad Meyer 
972091d81d1SSam Leffler 		case CRYPTO_DEFLATE_COMP:
973091d81d1SSam Leffler 			cxf = &comp_algo_deflate;
974091d81d1SSam Leffler 			(*swd)->sw_cxf = cxf;
975091d81d1SSam Leffler 			break;
976091d81d1SSam Leffler 		default:
977*1b0909d5SConrad Meyer 			swcr_freesession(dev, cses);
978091d81d1SSam Leffler 			return EINVAL;
979091d81d1SSam Leffler 		}
980091d81d1SSam Leffler 
981091d81d1SSam Leffler 		(*swd)->sw_alg = cri->cri_alg;
982091d81d1SSam Leffler 		cri = cri->cri_next;
983091d81d1SSam Leffler 		swd = &((*swd)->sw_next);
984091d81d1SSam Leffler 	}
985091d81d1SSam Leffler 	return 0;
986091d81d1SSam Leffler }
987091d81d1SSam Leffler 
988*1b0909d5SConrad Meyer static void
989*1b0909d5SConrad Meyer swcr_freesession(device_t dev, crypto_session_t cses)
990109919c6SBenno Rice {
991*1b0909d5SConrad Meyer 	struct swcr_data *ses, *swd, *next;
992091d81d1SSam Leffler 	struct enc_xform *txf;
993091d81d1SSam Leffler 	struct auth_hash *axf;
994091d81d1SSam Leffler 
995*1b0909d5SConrad Meyer 	ses = crypto_get_driver_session(cses);
996091d81d1SSam Leffler 
997*1b0909d5SConrad Meyer 	for (swd = ses; swd != NULL; swd = next) {
998*1b0909d5SConrad Meyer 		next = swd->sw_next;
999091d81d1SSam Leffler 
1000091d81d1SSam Leffler 		switch (swd->sw_alg) {
1001091d81d1SSam Leffler 		case CRYPTO_DES_CBC:
1002091d81d1SSam Leffler 		case CRYPTO_3DES_CBC:
1003091d81d1SSam Leffler 		case CRYPTO_BLF_CBC:
1004091d81d1SSam Leffler 		case CRYPTO_CAST_CBC:
1005091d81d1SSam Leffler 		case CRYPTO_SKIPJACK_CBC:
1006091d81d1SSam Leffler 		case CRYPTO_RIJNDAEL128_CBC:
1007d295bdeeSPawel Jakub Dawidek 		case CRYPTO_AES_XTS:
100808fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_ICM:
100908fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GCM_16:
101008fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GMAC:
1011559d3390SGeorge V. Neville-Neil 		case CRYPTO_CAMELLIA_CBC:
1012091d81d1SSam Leffler 		case CRYPTO_NULL_CBC:
101361590291SConrad Meyer 		case CRYPTO_CHACHA20:
1014091d81d1SSam Leffler 			txf = swd->sw_exf;
1015091d81d1SSam Leffler 
1016091d81d1SSam Leffler 			if (swd->sw_kschedule)
1017091d81d1SSam Leffler 				txf->zerokey(&(swd->sw_kschedule));
1018091d81d1SSam Leffler 			break;
1019091d81d1SSam Leffler 
1020091d81d1SSam Leffler 		case CRYPTO_MD5_HMAC:
1021091d81d1SSam Leffler 		case CRYPTO_SHA1_HMAC:
1022c97f39ceSConrad Meyer 		case CRYPTO_SHA2_224_HMAC:
1023f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_256_HMAC:
1024f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_384_HMAC:
1025f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_512_HMAC:
1026091d81d1SSam Leffler 		case CRYPTO_RIPEMD160_HMAC:
1027091d81d1SSam Leffler 		case CRYPTO_NULL_HMAC:
1028091d81d1SSam Leffler 			axf = swd->sw_axf;
1029091d81d1SSam Leffler 
1030091d81d1SSam Leffler 			if (swd->sw_ictx) {
1031091d81d1SSam Leffler 				bzero(swd->sw_ictx, axf->ctxsize);
1032091d81d1SSam Leffler 				free(swd->sw_ictx, M_CRYPTO_DATA);
1033091d81d1SSam Leffler 			}
1034091d81d1SSam Leffler 			if (swd->sw_octx) {
1035091d81d1SSam Leffler 				bzero(swd->sw_octx, axf->ctxsize);
1036091d81d1SSam Leffler 				free(swd->sw_octx, M_CRYPTO_DATA);
1037091d81d1SSam Leffler 			}
1038091d81d1SSam Leffler 			break;
1039091d81d1SSam Leffler 
1040091d81d1SSam Leffler 		case CRYPTO_MD5_KPDK:
1041091d81d1SSam Leffler 		case CRYPTO_SHA1_KPDK:
1042091d81d1SSam Leffler 			axf = swd->sw_axf;
1043091d81d1SSam Leffler 
1044091d81d1SSam Leffler 			if (swd->sw_ictx) {
1045091d81d1SSam Leffler 				bzero(swd->sw_ictx, axf->ctxsize);
1046091d81d1SSam Leffler 				free(swd->sw_ictx, M_CRYPTO_DATA);
1047091d81d1SSam Leffler 			}
1048091d81d1SSam Leffler 			if (swd->sw_octx) {
1049091d81d1SSam Leffler 				bzero(swd->sw_octx, swd->sw_klen);
1050091d81d1SSam Leffler 				free(swd->sw_octx, M_CRYPTO_DATA);
1051091d81d1SSam Leffler 			}
1052091d81d1SSam Leffler 			break;
1053091d81d1SSam Leffler 
10540e33efe4SConrad Meyer 		case CRYPTO_BLAKE2B:
10550e33efe4SConrad Meyer 		case CRYPTO_BLAKE2S:
1056091d81d1SSam Leffler 		case CRYPTO_MD5:
1057091d81d1SSam Leffler 		case CRYPTO_SHA1:
1058c4729f6eSConrad Meyer 		case CRYPTO_SHA2_224:
1059c4729f6eSConrad Meyer 		case CRYPTO_SHA2_256:
1060c4729f6eSConrad Meyer 		case CRYPTO_SHA2_384:
1061c4729f6eSConrad Meyer 		case CRYPTO_SHA2_512:
1062091d81d1SSam Leffler 			axf = swd->sw_axf;
1063091d81d1SSam Leffler 
10645fbc5b5aSConrad Meyer 			if (swd->sw_ictx) {
10655fbc5b5aSConrad Meyer 				explicit_bzero(swd->sw_ictx, axf->ctxsize);
1066091d81d1SSam Leffler 				free(swd->sw_ictx, M_CRYPTO_DATA);
10675fbc5b5aSConrad Meyer 			}
1068091d81d1SSam Leffler 			break;
1069091d81d1SSam Leffler 
1070091d81d1SSam Leffler 		case CRYPTO_DEFLATE_COMP:
1071151ba793SAlexander Kabaev 			/* Nothing to do */
1072091d81d1SSam Leffler 			break;
1073091d81d1SSam Leffler 		}
1074091d81d1SSam Leffler 
1075*1b0909d5SConrad Meyer 		/* OCF owns and frees the primary session object */
1076*1b0909d5SConrad Meyer 		if (swd != ses)
10771ede983cSDag-Erling Smørgrav 			free(swd, M_CRYPTO_DATA);
1078091d81d1SSam Leffler 	}
1079091d81d1SSam Leffler }
1080091d81d1SSam Leffler 
1081091d81d1SSam Leffler /*
1082091d81d1SSam Leffler  * Process a software request.
1083091d81d1SSam Leffler  */
1084091d81d1SSam Leffler static int
10856810ad6fSSam Leffler swcr_process(device_t dev, struct cryptop *crp, int hint)
1086091d81d1SSam Leffler {
1087091d81d1SSam Leffler 	struct cryptodesc *crd;
1088*1b0909d5SConrad Meyer 	struct swcr_data *sw, *ses;
1089091d81d1SSam Leffler 
1090091d81d1SSam Leffler 	/* Sanity check */
1091091d81d1SSam Leffler 	if (crp == NULL)
1092091d81d1SSam Leffler 		return EINVAL;
1093091d81d1SSam Leffler 
1094091d81d1SSam Leffler 	if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
1095091d81d1SSam Leffler 		crp->crp_etype = EINVAL;
1096091d81d1SSam Leffler 		goto done;
1097091d81d1SSam Leffler 	}
1098091d81d1SSam Leffler 
1099*1b0909d5SConrad Meyer 	ses = crypto_get_driver_session(crp->crp_session);
1100091d81d1SSam Leffler 
1101091d81d1SSam Leffler 	/* Go through crypto descriptors, processing as we go */
1102091d81d1SSam Leffler 	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
1103091d81d1SSam Leffler 		/*
1104091d81d1SSam Leffler 		 * Find the crypto context.
1105091d81d1SSam Leffler 		 *
1106091d81d1SSam Leffler 		 * XXX Note that the logic here prevents us from having
1107091d81d1SSam Leffler 		 * XXX the same algorithm multiple times in a session
1108091d81d1SSam Leffler 		 * XXX (or rather, we can but it won't give us the right
1109091d81d1SSam Leffler 		 * XXX results). To do that, we'd need some way of differentiating
1110091d81d1SSam Leffler 		 * XXX between the various instances of an algorithm (so we can
1111091d81d1SSam Leffler 		 * XXX locate the correct crypto context).
1112091d81d1SSam Leffler 		 */
1113*1b0909d5SConrad Meyer 		for (sw = ses; sw && sw->sw_alg != crd->crd_alg;
1114091d81d1SSam Leffler 		    sw = sw->sw_next)
1115091d81d1SSam Leffler 			;
1116091d81d1SSam Leffler 
1117091d81d1SSam Leffler 		/* No such context ? */
1118091d81d1SSam Leffler 		if (sw == NULL) {
1119091d81d1SSam Leffler 			crp->crp_etype = EINVAL;
1120091d81d1SSam Leffler 			goto done;
1121091d81d1SSam Leffler 		}
1122091d81d1SSam Leffler 		switch (sw->sw_alg) {
1123091d81d1SSam Leffler 		case CRYPTO_DES_CBC:
1124091d81d1SSam Leffler 		case CRYPTO_3DES_CBC:
1125091d81d1SSam Leffler 		case CRYPTO_BLF_CBC:
1126091d81d1SSam Leffler 		case CRYPTO_CAST_CBC:
1127091d81d1SSam Leffler 		case CRYPTO_SKIPJACK_CBC:
1128091d81d1SSam Leffler 		case CRYPTO_RIJNDAEL128_CBC:
1129d295bdeeSPawel Jakub Dawidek 		case CRYPTO_AES_XTS:
113008fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_ICM:
1131559d3390SGeorge V. Neville-Neil 		case CRYPTO_CAMELLIA_CBC:
113261590291SConrad Meyer 		case CRYPTO_CHACHA20:
1133091d81d1SSam Leffler 			if ((crp->crp_etype = swcr_encdec(crd, sw,
1134f34a967bSPawel Jakub Dawidek 			    crp->crp_buf, crp->crp_flags)) != 0)
1135091d81d1SSam Leffler 				goto done;
1136091d81d1SSam Leffler 			break;
1137091d81d1SSam Leffler 		case CRYPTO_NULL_CBC:
1138091d81d1SSam Leffler 			crp->crp_etype = 0;
1139091d81d1SSam Leffler 			break;
1140091d81d1SSam Leffler 		case CRYPTO_MD5_HMAC:
1141091d81d1SSam Leffler 		case CRYPTO_SHA1_HMAC:
1142c97f39ceSConrad Meyer 		case CRYPTO_SHA2_224_HMAC:
1143f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_256_HMAC:
1144f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_384_HMAC:
1145f6c4bc3bSPawel Jakub Dawidek 		case CRYPTO_SHA2_512_HMAC:
1146091d81d1SSam Leffler 		case CRYPTO_RIPEMD160_HMAC:
1147091d81d1SSam Leffler 		case CRYPTO_NULL_HMAC:
1148091d81d1SSam Leffler 		case CRYPTO_MD5_KPDK:
1149091d81d1SSam Leffler 		case CRYPTO_SHA1_KPDK:
1150091d81d1SSam Leffler 		case CRYPTO_MD5:
1151091d81d1SSam Leffler 		case CRYPTO_SHA1:
1152c4729f6eSConrad Meyer 		case CRYPTO_SHA2_224:
1153c4729f6eSConrad Meyer 		case CRYPTO_SHA2_256:
1154c4729f6eSConrad Meyer 		case CRYPTO_SHA2_384:
1155c4729f6eSConrad Meyer 		case CRYPTO_SHA2_512:
11560e33efe4SConrad Meyer 		case CRYPTO_BLAKE2B:
11570e33efe4SConrad Meyer 		case CRYPTO_BLAKE2S:
115838d2f8d6SPawel Jakub Dawidek 			if ((crp->crp_etype = swcr_authcompute(crd, sw,
1159f34a967bSPawel Jakub Dawidek 			    crp->crp_buf, crp->crp_flags)) != 0)
1160091d81d1SSam Leffler 				goto done;
1161091d81d1SSam Leffler 			break;
1162091d81d1SSam Leffler 
116308fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GCM_16:
116408fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_NIST_GMAC:
116508fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_128_NIST_GMAC:
116608fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_192_NIST_GMAC:
116708fca7a5SJohn-Mark Gurney 		case CRYPTO_AES_256_NIST_GMAC:
116808fca7a5SJohn-Mark Gurney 			crp->crp_etype = swcr_authenc(crp);
116908fca7a5SJohn-Mark Gurney 			goto done;
117008fca7a5SJohn-Mark Gurney 
1171091d81d1SSam Leffler 		case CRYPTO_DEFLATE_COMP:
1172091d81d1SSam Leffler 			if ((crp->crp_etype = swcr_compdec(crd, sw,
1173f34a967bSPawel Jakub Dawidek 			    crp->crp_buf, crp->crp_flags)) != 0)
1174091d81d1SSam Leffler 				goto done;
1175091d81d1SSam Leffler 			else
1176091d81d1SSam Leffler 				crp->crp_olen = (int)sw->sw_size;
1177091d81d1SSam Leffler 			break;
1178091d81d1SSam Leffler 
1179091d81d1SSam Leffler 		default:
1180091d81d1SSam Leffler 			/* Unknown/unsupported algorithm */
1181091d81d1SSam Leffler 			crp->crp_etype = EINVAL;
1182091d81d1SSam Leffler 			goto done;
1183091d81d1SSam Leffler 		}
1184091d81d1SSam Leffler 	}
1185091d81d1SSam Leffler 
1186091d81d1SSam Leffler done:
1187091d81d1SSam Leffler 	crypto_done(crp);
1188091d81d1SSam Leffler 	return 0;
1189091d81d1SSam Leffler }
1190091d81d1SSam Leffler 
1191091d81d1SSam Leffler static void
11923f147ab2SWarner Losh swcr_identify(driver_t *drv, device_t parent)
1193091d81d1SSam Leffler {
11946810ad6fSSam Leffler 	/* NB: order 10 is so we get attached after h/w devices */
11956810ad6fSSam Leffler 	if (device_find_child(parent, "cryptosoft", -1) == NULL &&
119686c585d9SMarius Strobl 	    BUS_ADD_CHILD(parent, 10, "cryptosoft", 0) == 0)
11976810ad6fSSam Leffler 		panic("cryptosoft: could not attach");
11986810ad6fSSam Leffler }
1199f6c4bc3bSPawel Jakub Dawidek 
12006810ad6fSSam Leffler static int
12016810ad6fSSam Leffler swcr_probe(device_t dev)
12026810ad6fSSam Leffler {
12036810ad6fSSam Leffler 	device_set_desc(dev, "software crypto");
120486c585d9SMarius Strobl 	return (BUS_PROBE_NOWILDCARD);
12056810ad6fSSam Leffler }
1206f6c4bc3bSPawel Jakub Dawidek 
12076810ad6fSSam Leffler static int
12086810ad6fSSam Leffler swcr_attach(device_t dev)
12096810ad6fSSam Leffler {
12106810ad6fSSam Leffler 	memset(hmac_ipad_buffer, HMAC_IPAD_VAL, HMAC_MAX_BLOCK_LEN);
12116810ad6fSSam Leffler 	memset(hmac_opad_buffer, HMAC_OPAD_VAL, HMAC_MAX_BLOCK_LEN);
12126810ad6fSSam Leffler 
1213*1b0909d5SConrad Meyer 	swcr_id = crypto_get_driverid(dev, sizeof(struct swcr_data),
12146810ad6fSSam Leffler 			CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
12156810ad6fSSam Leffler 	if (swcr_id < 0) {
12166810ad6fSSam Leffler 		device_printf(dev, "cannot initialize!");
12176810ad6fSSam Leffler 		return ENOMEM;
12186810ad6fSSam Leffler 	}
1219091d81d1SSam Leffler #define	REGISTER(alg) \
12206810ad6fSSam Leffler 	crypto_register(swcr_id, alg, 0,0)
12216810ad6fSSam Leffler 	REGISTER(CRYPTO_DES_CBC);
1222091d81d1SSam Leffler 	REGISTER(CRYPTO_3DES_CBC);
1223091d81d1SSam Leffler 	REGISTER(CRYPTO_BLF_CBC);
1224091d81d1SSam Leffler 	REGISTER(CRYPTO_CAST_CBC);
1225091d81d1SSam Leffler 	REGISTER(CRYPTO_SKIPJACK_CBC);
1226091d81d1SSam Leffler 	REGISTER(CRYPTO_NULL_CBC);
1227091d81d1SSam Leffler 	REGISTER(CRYPTO_MD5_HMAC);
1228091d81d1SSam Leffler 	REGISTER(CRYPTO_SHA1_HMAC);
1229c97f39ceSConrad Meyer 	REGISTER(CRYPTO_SHA2_224_HMAC);
1230f6c4bc3bSPawel Jakub Dawidek 	REGISTER(CRYPTO_SHA2_256_HMAC);
1231f6c4bc3bSPawel Jakub Dawidek 	REGISTER(CRYPTO_SHA2_384_HMAC);
1232f6c4bc3bSPawel Jakub Dawidek 	REGISTER(CRYPTO_SHA2_512_HMAC);
1233091d81d1SSam Leffler 	REGISTER(CRYPTO_RIPEMD160_HMAC);
1234091d81d1SSam Leffler 	REGISTER(CRYPTO_NULL_HMAC);
1235091d81d1SSam Leffler 	REGISTER(CRYPTO_MD5_KPDK);
1236091d81d1SSam Leffler 	REGISTER(CRYPTO_SHA1_KPDK);
1237091d81d1SSam Leffler 	REGISTER(CRYPTO_MD5);
1238091d81d1SSam Leffler 	REGISTER(CRYPTO_SHA1);
1239c4729f6eSConrad Meyer 	REGISTER(CRYPTO_SHA2_224);
1240c4729f6eSConrad Meyer 	REGISTER(CRYPTO_SHA2_256);
1241c4729f6eSConrad Meyer 	REGISTER(CRYPTO_SHA2_384);
1242c4729f6eSConrad Meyer 	REGISTER(CRYPTO_SHA2_512);
1243091d81d1SSam Leffler 	REGISTER(CRYPTO_RIJNDAEL128_CBC);
1244d295bdeeSPawel Jakub Dawidek 	REGISTER(CRYPTO_AES_XTS);
124508fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_ICM);
124608fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_NIST_GCM_16);
124708fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_NIST_GMAC);
124808fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_128_NIST_GMAC);
124908fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_192_NIST_GMAC);
125008fca7a5SJohn-Mark Gurney 	REGISTER(CRYPTO_AES_256_NIST_GMAC);
1251559d3390SGeorge V. Neville-Neil  	REGISTER(CRYPTO_CAMELLIA_CBC);
1252091d81d1SSam Leffler 	REGISTER(CRYPTO_DEFLATE_COMP);
12530e33efe4SConrad Meyer 	REGISTER(CRYPTO_BLAKE2B);
12540e33efe4SConrad Meyer 	REGISTER(CRYPTO_BLAKE2S);
125561590291SConrad Meyer 	REGISTER(CRYPTO_CHACHA20);
1256091d81d1SSam Leffler #undef REGISTER
12576810ad6fSSam Leffler 
12586810ad6fSSam Leffler 	return 0;
1259091d81d1SSam Leffler }
12604b465da2SPawel Jakub Dawidek 
12613f147ab2SWarner Losh static int
12626810ad6fSSam Leffler swcr_detach(device_t dev)
12634b465da2SPawel Jakub Dawidek {
12646810ad6fSSam Leffler 	crypto_unregister_all(swcr_id);
12653f147ab2SWarner Losh 	return 0;
12664b465da2SPawel Jakub Dawidek }
12676810ad6fSSam Leffler 
12686810ad6fSSam Leffler static device_method_t swcr_methods[] = {
12696810ad6fSSam Leffler 	DEVMETHOD(device_identify,	swcr_identify),
12706810ad6fSSam Leffler 	DEVMETHOD(device_probe,		swcr_probe),
12716810ad6fSSam Leffler 	DEVMETHOD(device_attach,	swcr_attach),
12726810ad6fSSam Leffler 	DEVMETHOD(device_detach,	swcr_detach),
12736810ad6fSSam Leffler 
12746810ad6fSSam Leffler 	DEVMETHOD(cryptodev_newsession,	swcr_newsession),
12756810ad6fSSam Leffler 	DEVMETHOD(cryptodev_freesession,swcr_freesession),
12766810ad6fSSam Leffler 	DEVMETHOD(cryptodev_process,	swcr_process),
12776810ad6fSSam Leffler 
12786810ad6fSSam Leffler 	{0, 0},
12796810ad6fSSam Leffler };
12806810ad6fSSam Leffler 
12816810ad6fSSam Leffler static driver_t swcr_driver = {
12826810ad6fSSam Leffler 	"cryptosoft",
12836810ad6fSSam Leffler 	swcr_methods,
12846810ad6fSSam Leffler 	0,		/* NB: no softc */
12856810ad6fSSam Leffler };
12866810ad6fSSam Leffler static devclass_t swcr_devclass;
12876810ad6fSSam Leffler 
12886810ad6fSSam Leffler /*
12896810ad6fSSam Leffler  * NB: We explicitly reference the crypto module so we
12906810ad6fSSam Leffler  * get the necessary ordering when built as a loadable
12916810ad6fSSam Leffler  * module.  This is required because we bundle the crypto
12926810ad6fSSam Leffler  * module code together with the cryptosoft driver (otherwise
12936810ad6fSSam Leffler  * normal module dependencies would handle things).
12946810ad6fSSam Leffler  */
12956810ad6fSSam Leffler extern int crypto_modevent(struct module *, int, void *);
12966810ad6fSSam Leffler /* XXX where to attach */
12976810ad6fSSam Leffler DRIVER_MODULE(cryptosoft, nexus, swcr_driver, swcr_devclass, crypto_modevent,0);
12986810ad6fSSam Leffler MODULE_VERSION(cryptosoft, 1);
12996810ad6fSSam Leffler MODULE_DEPEND(cryptosoft, crypto, 1, 1, 1);
1300