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