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); 731b0909d5SConrad 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 32425b7033bSConrad Meyer static int __result_use_check 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 } 38025b7033bSConrad Meyer case CRYPTO_POLY1305: 38125b7033bSConrad Meyer if (klen != POLY1305_KEY_LEN) { 38225b7033bSConrad Meyer CRYPTDEB("bad poly1305 key size %d", klen); 38325b7033bSConrad Meyer return EINVAL; 38425b7033bSConrad Meyer } 38525b7033bSConrad Meyer /* FALLTHROUGH */ 3860e33efe4SConrad Meyer case CRYPTO_BLAKE2B: 3870e33efe4SConrad Meyer case CRYPTO_BLAKE2S: 3880e33efe4SConrad Meyer axf->Setkey(sw->sw_ictx, key, klen); 3890e33efe4SConrad Meyer axf->Init(sw->sw_ictx); 3900e33efe4SConrad Meyer break; 391f6c4bc3bSPawel Jakub Dawidek default: 392f6c4bc3bSPawel Jakub Dawidek printf("%s: CRD_F_KEY_EXPLICIT flag given, but algorithm %d " 393f6c4bc3bSPawel Jakub Dawidek "doesn't use keys.\n", __func__, axf->type); 39425b7033bSConrad Meyer return EINVAL; 395f6c4bc3bSPawel Jakub Dawidek } 39625b7033bSConrad Meyer return 0; 397f6c4bc3bSPawel Jakub Dawidek } 398f6c4bc3bSPawel Jakub Dawidek 399091d81d1SSam Leffler /* 400091d81d1SSam Leffler * Compute keyed-hash authenticator. 401091d81d1SSam Leffler */ 402091d81d1SSam Leffler static int 40338d2f8d6SPawel Jakub Dawidek swcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, 404f34a967bSPawel Jakub Dawidek int flags) 405091d81d1SSam Leffler { 4060bbc4bf9SPawel Jakub Dawidek unsigned char aalg[HASH_MAX_LEN]; 407091d81d1SSam Leffler struct auth_hash *axf; 408091d81d1SSam Leffler union authctx ctx; 409091d81d1SSam Leffler int err; 410091d81d1SSam Leffler 411091d81d1SSam Leffler if (sw->sw_ictx == 0) 412091d81d1SSam Leffler return EINVAL; 413091d81d1SSam Leffler 414091d81d1SSam Leffler axf = sw->sw_axf; 415091d81d1SSam Leffler 41625b7033bSConrad Meyer if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { 41725b7033bSConrad Meyer err = swcr_authprepare(axf, sw, crd->crd_key, crd->crd_klen); 41825b7033bSConrad Meyer if (err != 0) 41925b7033bSConrad Meyer return err; 42025b7033bSConrad Meyer } 421f6c4bc3bSPawel Jakub Dawidek 422091d81d1SSam Leffler bcopy(sw->sw_ictx, &ctx, axf->ctxsize); 423091d81d1SSam Leffler 424f34a967bSPawel Jakub Dawidek err = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len, 425f34a967bSPawel Jakub Dawidek (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx); 426091d81d1SSam Leffler if (err) 427091d81d1SSam Leffler return err; 428091d81d1SSam Leffler 429091d81d1SSam Leffler switch (sw->sw_alg) { 430c4729f6eSConrad Meyer case CRYPTO_SHA1: 431c4729f6eSConrad Meyer case CRYPTO_SHA2_224: 432c4729f6eSConrad Meyer case CRYPTO_SHA2_256: 433c4729f6eSConrad Meyer case CRYPTO_SHA2_384: 434c4729f6eSConrad Meyer case CRYPTO_SHA2_512: 435c4729f6eSConrad Meyer axf->Final(aalg, &ctx); 436c4729f6eSConrad Meyer break; 437c4729f6eSConrad Meyer 438091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 439091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 440c97f39ceSConrad Meyer case CRYPTO_SHA2_224_HMAC: 441f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 442f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 443f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 444091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 445091d81d1SSam Leffler if (sw->sw_octx == NULL) 446091d81d1SSam Leffler return EINVAL; 447091d81d1SSam Leffler 448091d81d1SSam Leffler axf->Final(aalg, &ctx); 449091d81d1SSam Leffler bcopy(sw->sw_octx, &ctx, axf->ctxsize); 450091d81d1SSam Leffler axf->Update(&ctx, aalg, axf->hashsize); 451091d81d1SSam Leffler axf->Final(aalg, &ctx); 452091d81d1SSam Leffler break; 453091d81d1SSam Leffler 454091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 455091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 45677680d96SBjoern A. Zeeb /* If we have no key saved, return error. */ 457091d81d1SSam Leffler if (sw->sw_octx == NULL) 458091d81d1SSam Leffler return EINVAL; 459091d81d1SSam Leffler 46077680d96SBjoern A. Zeeb /* 46177680d96SBjoern A. Zeeb * Add the trailing copy of the key (see comment in 46277680d96SBjoern A. Zeeb * swcr_authprepare()) after the data: 46377680d96SBjoern A. Zeeb * ALGO( .., key, algofill ) 46477680d96SBjoern A. Zeeb * and let Final() do the proper, natural "algofill" 46577680d96SBjoern A. Zeeb * padding. 46677680d96SBjoern A. Zeeb */ 467091d81d1SSam Leffler axf->Update(&ctx, sw->sw_octx, sw->sw_klen); 468091d81d1SSam Leffler axf->Final(aalg, &ctx); 469091d81d1SSam Leffler break; 470091d81d1SSam Leffler 4710e33efe4SConrad Meyer case CRYPTO_BLAKE2B: 4720e33efe4SConrad Meyer case CRYPTO_BLAKE2S: 473091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 47425b7033bSConrad Meyer case CRYPTO_POLY1305: 475091d81d1SSam Leffler axf->Final(aalg, &ctx); 476091d81d1SSam Leffler break; 477091d81d1SSam Leffler } 478091d81d1SSam Leffler 479091d81d1SSam Leffler /* Inject the authentication data */ 480f34a967bSPawel Jakub Dawidek crypto_copyback(flags, buf, crd->crd_inject, 481f6c4bc3bSPawel Jakub Dawidek sw->sw_mlen == 0 ? axf->hashsize : sw->sw_mlen, aalg); 482091d81d1SSam Leffler return 0; 483091d81d1SSam Leffler } 484091d81d1SSam Leffler 48508fca7a5SJohn-Mark Gurney CTASSERT(INT_MAX <= (1ll<<39) - 256); /* GCM: plain text < 2^39-256 */ 48608fca7a5SJohn-Mark Gurney CTASSERT(INT_MAX <= (uint64_t)-1); /* GCM: associated data <= 2^64-1 */ 48708fca7a5SJohn-Mark Gurney 48808fca7a5SJohn-Mark Gurney /* 48908fca7a5SJohn-Mark Gurney * Apply a combined encryption-authentication transformation 49008fca7a5SJohn-Mark Gurney */ 49108fca7a5SJohn-Mark Gurney static int 49208fca7a5SJohn-Mark Gurney swcr_authenc(struct cryptop *crp) 49308fca7a5SJohn-Mark Gurney { 49408fca7a5SJohn-Mark Gurney uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))]; 49508fca7a5SJohn-Mark Gurney u_char *blk = (u_char *)blkbuf; 49608fca7a5SJohn-Mark Gurney u_char aalg[AALG_MAX_RESULT_LEN]; 49708fca7a5SJohn-Mark Gurney u_char uaalg[AALG_MAX_RESULT_LEN]; 49808fca7a5SJohn-Mark Gurney u_char iv[EALG_MAX_BLOCK_LEN]; 49908fca7a5SJohn-Mark Gurney union authctx ctx; 500*9ebbebe4SConrad Meyer struct swcr_session *ses; 50108fca7a5SJohn-Mark Gurney struct cryptodesc *crd, *crda = NULL, *crde = NULL; 50208fca7a5SJohn-Mark Gurney struct swcr_data *sw, *swa, *swe = NULL; 50308fca7a5SJohn-Mark Gurney struct auth_hash *axf = NULL; 50408fca7a5SJohn-Mark Gurney struct enc_xform *exf = NULL; 50508fca7a5SJohn-Mark Gurney caddr_t buf = (caddr_t)crp->crp_buf; 50608fca7a5SJohn-Mark Gurney uint32_t *blkp; 50708fca7a5SJohn-Mark Gurney int aadlen, blksz, i, ivlen, len, iskip, oskip, r; 50808fca7a5SJohn-Mark Gurney 50908fca7a5SJohn-Mark Gurney ivlen = blksz = iskip = oskip = 0; 51008fca7a5SJohn-Mark Gurney 511*9ebbebe4SConrad Meyer ses = crypto_get_driver_session(crp->crp_session); 512*9ebbebe4SConrad Meyer 51308fca7a5SJohn-Mark Gurney for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 514*9ebbebe4SConrad Meyer for (i = 0; i < nitems(ses->swcr_algorithms) && 515*9ebbebe4SConrad Meyer ses->swcr_algorithms[i].sw_alg != crd->crd_alg; i++) 51608fca7a5SJohn-Mark Gurney ; 517*9ebbebe4SConrad Meyer if (i == nitems(ses->swcr_algorithms)) 51808fca7a5SJohn-Mark Gurney return (EINVAL); 51908fca7a5SJohn-Mark Gurney 520*9ebbebe4SConrad Meyer sw = &ses->swcr_algorithms[i]; 52108fca7a5SJohn-Mark Gurney switch (sw->sw_alg) { 52208fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GCM_16: 52308fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GMAC: 52408fca7a5SJohn-Mark Gurney swe = sw; 52508fca7a5SJohn-Mark Gurney crde = crd; 52608fca7a5SJohn-Mark Gurney exf = swe->sw_exf; 52708fca7a5SJohn-Mark Gurney ivlen = 12; 52808fca7a5SJohn-Mark Gurney break; 52908fca7a5SJohn-Mark Gurney case CRYPTO_AES_128_NIST_GMAC: 53008fca7a5SJohn-Mark Gurney case CRYPTO_AES_192_NIST_GMAC: 53108fca7a5SJohn-Mark Gurney case CRYPTO_AES_256_NIST_GMAC: 53208fca7a5SJohn-Mark Gurney swa = sw; 53308fca7a5SJohn-Mark Gurney crda = crd; 53408fca7a5SJohn-Mark Gurney axf = swa->sw_axf; 53508fca7a5SJohn-Mark Gurney if (swa->sw_ictx == 0) 53608fca7a5SJohn-Mark Gurney return (EINVAL); 53708fca7a5SJohn-Mark Gurney bcopy(swa->sw_ictx, &ctx, axf->ctxsize); 53808fca7a5SJohn-Mark Gurney blksz = axf->blocksize; 53908fca7a5SJohn-Mark Gurney break; 54008fca7a5SJohn-Mark Gurney default: 54108fca7a5SJohn-Mark Gurney return (EINVAL); 54208fca7a5SJohn-Mark Gurney } 54308fca7a5SJohn-Mark Gurney } 54408fca7a5SJohn-Mark Gurney if (crde == NULL || crda == NULL) 54508fca7a5SJohn-Mark Gurney return (EINVAL); 54608fca7a5SJohn-Mark Gurney 54708fca7a5SJohn-Mark Gurney if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 && 54808fca7a5SJohn-Mark Gurney (crde->crd_flags & CRD_F_IV_EXPLICIT) == 0) 54908fca7a5SJohn-Mark Gurney return (EINVAL); 55008fca7a5SJohn-Mark Gurney 55108fca7a5SJohn-Mark Gurney if (crde->crd_klen != crda->crd_klen) 55208fca7a5SJohn-Mark Gurney return (EINVAL); 55308fca7a5SJohn-Mark Gurney 55408fca7a5SJohn-Mark Gurney /* Initialize the IV */ 55508fca7a5SJohn-Mark Gurney if (crde->crd_flags & CRD_F_ENCRYPT) { 55608fca7a5SJohn-Mark Gurney /* IV explicitly provided ? */ 55708fca7a5SJohn-Mark Gurney if (crde->crd_flags & CRD_F_IV_EXPLICIT) 55808fca7a5SJohn-Mark Gurney bcopy(crde->crd_iv, iv, ivlen); 55908fca7a5SJohn-Mark Gurney else 56008fca7a5SJohn-Mark Gurney arc4rand(iv, ivlen, 0); 56108fca7a5SJohn-Mark Gurney 56208fca7a5SJohn-Mark Gurney /* Do we need to write the IV */ 56308fca7a5SJohn-Mark Gurney if (!(crde->crd_flags & CRD_F_IV_PRESENT)) 56408fca7a5SJohn-Mark Gurney crypto_copyback(crp->crp_flags, buf, crde->crd_inject, 56508fca7a5SJohn-Mark Gurney ivlen, iv); 56608fca7a5SJohn-Mark Gurney 56708fca7a5SJohn-Mark Gurney } else { /* Decryption */ 56808fca7a5SJohn-Mark Gurney /* IV explicitly provided ? */ 56908fca7a5SJohn-Mark Gurney if (crde->crd_flags & CRD_F_IV_EXPLICIT) 57008fca7a5SJohn-Mark Gurney bcopy(crde->crd_iv, iv, ivlen); 57108fca7a5SJohn-Mark Gurney else { 57208fca7a5SJohn-Mark Gurney /* Get IV off buf */ 57308fca7a5SJohn-Mark Gurney crypto_copydata(crp->crp_flags, buf, crde->crd_inject, 57408fca7a5SJohn-Mark Gurney ivlen, iv); 57508fca7a5SJohn-Mark Gurney } 57608fca7a5SJohn-Mark Gurney } 57708fca7a5SJohn-Mark Gurney 57808fca7a5SJohn-Mark Gurney /* Supply MAC with IV */ 57908fca7a5SJohn-Mark Gurney if (axf->Reinit) 58008fca7a5SJohn-Mark Gurney axf->Reinit(&ctx, iv, ivlen); 58108fca7a5SJohn-Mark Gurney 58208fca7a5SJohn-Mark Gurney /* Supply MAC with AAD */ 58308fca7a5SJohn-Mark Gurney aadlen = crda->crd_len; 58408fca7a5SJohn-Mark Gurney 58508fca7a5SJohn-Mark Gurney for (i = iskip; i < crda->crd_len; i += blksz) { 58608fca7a5SJohn-Mark Gurney len = MIN(crda->crd_len - i, blksz - oskip); 58708fca7a5SJohn-Mark Gurney crypto_copydata(crp->crp_flags, buf, crda->crd_skip + i, len, 58808fca7a5SJohn-Mark Gurney blk + oskip); 58908fca7a5SJohn-Mark Gurney bzero(blk + len + oskip, blksz - len - oskip); 59008fca7a5SJohn-Mark Gurney axf->Update(&ctx, blk, blksz); 59108fca7a5SJohn-Mark Gurney oskip = 0; /* reset initial output offset */ 59208fca7a5SJohn-Mark Gurney } 59308fca7a5SJohn-Mark Gurney 59408fca7a5SJohn-Mark Gurney if (exf->reinit) 59508fca7a5SJohn-Mark Gurney exf->reinit(swe->sw_kschedule, iv); 59608fca7a5SJohn-Mark Gurney 59708fca7a5SJohn-Mark Gurney /* Do encryption/decryption with MAC */ 5982f1f9cceSConrad Meyer for (i = 0; i < crde->crd_len; i += len) { 5992f1f9cceSConrad Meyer if (exf->encrypt_multi != NULL) { 6002f1f9cceSConrad Meyer len = rounddown(crde->crd_len - i, blksz); 6012f1f9cceSConrad Meyer if (len == 0) 6022f1f9cceSConrad Meyer len = blksz; 6032f1f9cceSConrad Meyer else 6042f1f9cceSConrad Meyer len = MIN(len, sizeof(blkbuf)); 6052f1f9cceSConrad Meyer } else 6062f1f9cceSConrad Meyer len = blksz; 6072f1f9cceSConrad Meyer len = MIN(crde->crd_len - i, len); 60808fca7a5SJohn-Mark Gurney if (len < blksz) 60908fca7a5SJohn-Mark Gurney bzero(blk, blksz); 61008fca7a5SJohn-Mark Gurney crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len, 61108fca7a5SJohn-Mark Gurney blk); 61208fca7a5SJohn-Mark Gurney if (crde->crd_flags & CRD_F_ENCRYPT) { 6132f1f9cceSConrad Meyer if (exf->encrypt_multi != NULL) 6142f1f9cceSConrad Meyer exf->encrypt_multi(swe->sw_kschedule, blk, 6152f1f9cceSConrad Meyer len); 6162f1f9cceSConrad Meyer else 61708fca7a5SJohn-Mark Gurney exf->encrypt(swe->sw_kschedule, blk); 61808fca7a5SJohn-Mark Gurney axf->Update(&ctx, blk, len); 61908fca7a5SJohn-Mark Gurney crypto_copyback(crp->crp_flags, buf, 62008fca7a5SJohn-Mark Gurney crde->crd_skip + i, len, blk); 62108fca7a5SJohn-Mark Gurney } else { 62208fca7a5SJohn-Mark Gurney axf->Update(&ctx, blk, len); 62308fca7a5SJohn-Mark Gurney } 62408fca7a5SJohn-Mark Gurney } 62508fca7a5SJohn-Mark Gurney 62608fca7a5SJohn-Mark Gurney /* Do any required special finalization */ 62708fca7a5SJohn-Mark Gurney switch (crda->crd_alg) { 62808fca7a5SJohn-Mark Gurney case CRYPTO_AES_128_NIST_GMAC: 62908fca7a5SJohn-Mark Gurney case CRYPTO_AES_192_NIST_GMAC: 63008fca7a5SJohn-Mark Gurney case CRYPTO_AES_256_NIST_GMAC: 63108fca7a5SJohn-Mark Gurney /* length block */ 63208fca7a5SJohn-Mark Gurney bzero(blk, blksz); 63308fca7a5SJohn-Mark Gurney blkp = (uint32_t *)blk + 1; 63408fca7a5SJohn-Mark Gurney *blkp = htobe32(aadlen * 8); 63508fca7a5SJohn-Mark Gurney blkp = (uint32_t *)blk + 3; 63608fca7a5SJohn-Mark Gurney *blkp = htobe32(crde->crd_len * 8); 63708fca7a5SJohn-Mark Gurney axf->Update(&ctx, blk, blksz); 63808fca7a5SJohn-Mark Gurney break; 63908fca7a5SJohn-Mark Gurney } 64008fca7a5SJohn-Mark Gurney 64108fca7a5SJohn-Mark Gurney /* Finalize MAC */ 64208fca7a5SJohn-Mark Gurney axf->Final(aalg, &ctx); 64308fca7a5SJohn-Mark Gurney 64408fca7a5SJohn-Mark Gurney /* Validate tag */ 64508fca7a5SJohn-Mark Gurney if (!(crde->crd_flags & CRD_F_ENCRYPT)) { 64608fca7a5SJohn-Mark Gurney crypto_copydata(crp->crp_flags, buf, crda->crd_inject, 64708fca7a5SJohn-Mark Gurney axf->hashsize, uaalg); 64808fca7a5SJohn-Mark Gurney 64908fca7a5SJohn-Mark Gurney r = timingsafe_bcmp(aalg, uaalg, axf->hashsize); 65008fca7a5SJohn-Mark Gurney if (r == 0) { 65108fca7a5SJohn-Mark Gurney /* tag matches, decrypt data */ 65208fca7a5SJohn-Mark Gurney for (i = 0; i < crde->crd_len; i += blksz) { 65308fca7a5SJohn-Mark Gurney len = MIN(crde->crd_len - i, blksz); 65408fca7a5SJohn-Mark Gurney if (len < blksz) 65508fca7a5SJohn-Mark Gurney bzero(blk, blksz); 65608fca7a5SJohn-Mark Gurney crypto_copydata(crp->crp_flags, buf, 65708fca7a5SJohn-Mark Gurney crde->crd_skip + i, len, blk); 65808fca7a5SJohn-Mark Gurney exf->decrypt(swe->sw_kschedule, blk); 65908fca7a5SJohn-Mark Gurney crypto_copyback(crp->crp_flags, buf, 66008fca7a5SJohn-Mark Gurney crde->crd_skip + i, len, blk); 66108fca7a5SJohn-Mark Gurney } 66208fca7a5SJohn-Mark Gurney } else 66308fca7a5SJohn-Mark Gurney return (EBADMSG); 66408fca7a5SJohn-Mark Gurney } else { 66508fca7a5SJohn-Mark Gurney /* Inject the authentication data */ 66608fca7a5SJohn-Mark Gurney crypto_copyback(crp->crp_flags, buf, crda->crd_inject, 66708fca7a5SJohn-Mark Gurney axf->hashsize, aalg); 66808fca7a5SJohn-Mark Gurney } 66908fca7a5SJohn-Mark Gurney 67008fca7a5SJohn-Mark Gurney return (0); 67108fca7a5SJohn-Mark Gurney } 67208fca7a5SJohn-Mark Gurney 673091d81d1SSam Leffler /* 674091d81d1SSam Leffler * Apply a compression/decompression algorithm 675091d81d1SSam Leffler */ 676091d81d1SSam Leffler static int 677091d81d1SSam Leffler swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw, 678f34a967bSPawel Jakub Dawidek caddr_t buf, int flags) 679091d81d1SSam Leffler { 680091d81d1SSam Leffler u_int8_t *data, *out; 681091d81d1SSam Leffler struct comp_algo *cxf; 682091d81d1SSam Leffler int adj; 683091d81d1SSam Leffler u_int32_t result; 684091d81d1SSam Leffler 685091d81d1SSam Leffler cxf = sw->sw_cxf; 686091d81d1SSam Leffler 687091d81d1SSam Leffler /* We must handle the whole buffer of data in one time 688091d81d1SSam Leffler * then if there is not all the data in the mbuf, we must 689091d81d1SSam Leffler * copy in a buffer. 690091d81d1SSam Leffler */ 691091d81d1SSam Leffler 6921ede983cSDag-Erling Smørgrav data = malloc(crd->crd_len, M_CRYPTO_DATA, M_NOWAIT); 693091d81d1SSam Leffler if (data == NULL) 694091d81d1SSam Leffler return (EINVAL); 695f34a967bSPawel Jakub Dawidek crypto_copydata(flags, buf, crd->crd_skip, crd->crd_len, data); 696091d81d1SSam Leffler 697091d81d1SSam Leffler if (crd->crd_flags & CRD_F_COMP) 698091d81d1SSam Leffler result = cxf->compress(data, crd->crd_len, &out); 699091d81d1SSam Leffler else 700091d81d1SSam Leffler result = cxf->decompress(data, crd->crd_len, &out); 701091d81d1SSam Leffler 7021ede983cSDag-Erling Smørgrav free(data, M_CRYPTO_DATA); 703091d81d1SSam Leffler if (result == 0) 704091d81d1SSam Leffler return EINVAL; 705091d81d1SSam Leffler 706091d81d1SSam Leffler /* Copy back the (de)compressed data. m_copyback is 707091d81d1SSam Leffler * extending the mbuf as necessary. 708091d81d1SSam Leffler */ 709091d81d1SSam Leffler sw->sw_size = result; 710091d81d1SSam Leffler /* Check the compressed size when doing compression */ 711091d81d1SSam Leffler if (crd->crd_flags & CRD_F_COMP) { 712df4dece1SBjoern A. Zeeb if (result >= crd->crd_len) { 713091d81d1SSam Leffler /* Compression was useless, we lost time */ 7141ede983cSDag-Erling Smørgrav free(out, M_CRYPTO_DATA); 715091d81d1SSam Leffler return 0; 716091d81d1SSam Leffler } 717091d81d1SSam Leffler } 718091d81d1SSam Leffler 719f34a967bSPawel Jakub Dawidek crypto_copyback(flags, buf, crd->crd_skip, result, out); 720091d81d1SSam Leffler if (result < crd->crd_len) { 721091d81d1SSam Leffler adj = result - crd->crd_len; 722f34a967bSPawel Jakub Dawidek if (flags & CRYPTO_F_IMBUF) { 723091d81d1SSam Leffler adj = result - crd->crd_len; 724091d81d1SSam Leffler m_adj((struct mbuf *)buf, adj); 725f34a967bSPawel Jakub Dawidek } else if (flags & CRYPTO_F_IOV) { 726091d81d1SSam Leffler struct uio *uio = (struct uio *)buf; 727091d81d1SSam Leffler int ind; 728091d81d1SSam Leffler 729091d81d1SSam Leffler adj = crd->crd_len - result; 730091d81d1SSam Leffler ind = uio->uio_iovcnt - 1; 731091d81d1SSam Leffler 732091d81d1SSam Leffler while (adj > 0 && ind >= 0) { 733091d81d1SSam Leffler if (adj < uio->uio_iov[ind].iov_len) { 734091d81d1SSam Leffler uio->uio_iov[ind].iov_len -= adj; 735091d81d1SSam Leffler break; 736091d81d1SSam Leffler } 737091d81d1SSam Leffler 738091d81d1SSam Leffler adj -= uio->uio_iov[ind].iov_len; 739091d81d1SSam Leffler uio->uio_iov[ind].iov_len = 0; 740091d81d1SSam Leffler ind--; 741091d81d1SSam Leffler uio->uio_iovcnt--; 742091d81d1SSam Leffler } 743091d81d1SSam Leffler } 744091d81d1SSam Leffler } 7451ede983cSDag-Erling Smørgrav free(out, M_CRYPTO_DATA); 746091d81d1SSam Leffler return 0; 747091d81d1SSam Leffler } 748091d81d1SSam Leffler 749091d81d1SSam Leffler /* 750091d81d1SSam Leffler * Generate a new software session. 751091d81d1SSam Leffler */ 752091d81d1SSam Leffler static int 7531b0909d5SConrad Meyer swcr_newsession(device_t dev, crypto_session_t cses, struct cryptoini *cri) 754091d81d1SSam Leffler { 755*9ebbebe4SConrad Meyer struct swcr_session *ses; 756*9ebbebe4SConrad Meyer struct swcr_data *swd; 757091d81d1SSam Leffler struct auth_hash *axf; 758091d81d1SSam Leffler struct enc_xform *txf; 759091d81d1SSam Leffler struct comp_algo *cxf; 760*9ebbebe4SConrad Meyer size_t i; 761a2bc81bfSJohn-Mark Gurney int len; 762f6c4bc3bSPawel Jakub Dawidek int error; 763091d81d1SSam Leffler 7641b0909d5SConrad Meyer if (cses == NULL || cri == NULL) 765091d81d1SSam Leffler return EINVAL; 766091d81d1SSam Leffler 7671b0909d5SConrad Meyer ses = crypto_get_driver_session(cses); 768091d81d1SSam Leffler 769*9ebbebe4SConrad Meyer for (i = 0; cri != NULL && i < nitems(ses->swcr_algorithms); i++) { 770*9ebbebe4SConrad Meyer swd = &ses->swcr_algorithms[i]; 771091d81d1SSam Leffler 772091d81d1SSam Leffler switch (cri->cri_alg) { 773091d81d1SSam Leffler case CRYPTO_DES_CBC: 774091d81d1SSam Leffler txf = &enc_xform_des; 775091d81d1SSam Leffler goto enccommon; 776091d81d1SSam Leffler case CRYPTO_3DES_CBC: 777091d81d1SSam Leffler txf = &enc_xform_3des; 778091d81d1SSam Leffler goto enccommon; 779091d81d1SSam Leffler case CRYPTO_BLF_CBC: 780091d81d1SSam Leffler txf = &enc_xform_blf; 781091d81d1SSam Leffler goto enccommon; 782091d81d1SSam Leffler case CRYPTO_CAST_CBC: 783091d81d1SSam Leffler txf = &enc_xform_cast5; 784091d81d1SSam Leffler goto enccommon; 785091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 786091d81d1SSam Leffler txf = &enc_xform_skipjack; 787091d81d1SSam Leffler goto enccommon; 788091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 789091d81d1SSam Leffler txf = &enc_xform_rijndael128; 790091d81d1SSam Leffler goto enccommon; 791d295bdeeSPawel Jakub Dawidek case CRYPTO_AES_XTS: 792d295bdeeSPawel Jakub Dawidek txf = &enc_xform_aes_xts; 793d295bdeeSPawel Jakub Dawidek goto enccommon; 79408fca7a5SJohn-Mark Gurney case CRYPTO_AES_ICM: 79508fca7a5SJohn-Mark Gurney txf = &enc_xform_aes_icm; 79608fca7a5SJohn-Mark Gurney goto enccommon; 79708fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GCM_16: 79808fca7a5SJohn-Mark Gurney txf = &enc_xform_aes_nist_gcm; 79908fca7a5SJohn-Mark Gurney goto enccommon; 80008fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GMAC: 80108fca7a5SJohn-Mark Gurney txf = &enc_xform_aes_nist_gmac; 802*9ebbebe4SConrad Meyer swd->sw_exf = txf; 80308fca7a5SJohn-Mark Gurney break; 804559d3390SGeorge V. Neville-Neil case CRYPTO_CAMELLIA_CBC: 805559d3390SGeorge V. Neville-Neil txf = &enc_xform_camellia; 806559d3390SGeorge V. Neville-Neil goto enccommon; 807091d81d1SSam Leffler case CRYPTO_NULL_CBC: 808091d81d1SSam Leffler txf = &enc_xform_null; 809091d81d1SSam Leffler goto enccommon; 81061590291SConrad Meyer case CRYPTO_CHACHA20: 81161590291SConrad Meyer txf = &enc_xform_chacha20; 81261590291SConrad Meyer goto enccommon; 813091d81d1SSam Leffler enccommon: 814f6c4bc3bSPawel Jakub Dawidek if (cri->cri_key != NULL) { 815*9ebbebe4SConrad Meyer error = txf->setkey(&swd->sw_kschedule, 816091d81d1SSam Leffler cri->cri_key, cri->cri_klen / 8); 817091d81d1SSam Leffler if (error) { 8181b0909d5SConrad Meyer swcr_freesession(dev, cses); 819091d81d1SSam Leffler return error; 820091d81d1SSam Leffler } 821f6c4bc3bSPawel Jakub Dawidek } 822*9ebbebe4SConrad Meyer swd->sw_exf = txf; 823091d81d1SSam Leffler break; 824091d81d1SSam Leffler 825091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 826f6c4bc3bSPawel Jakub Dawidek axf = &auth_hash_hmac_md5; 827091d81d1SSam Leffler goto authcommon; 828091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 829f6c4bc3bSPawel Jakub Dawidek axf = &auth_hash_hmac_sha1; 830091d81d1SSam Leffler goto authcommon; 831c97f39ceSConrad Meyer case CRYPTO_SHA2_224_HMAC: 832c97f39ceSConrad Meyer axf = &auth_hash_hmac_sha2_224; 833c97f39ceSConrad Meyer goto authcommon; 834f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 835091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_256; 836f6c4bc3bSPawel Jakub Dawidek goto authcommon; 837f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 838091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_384; 839f6c4bc3bSPawel Jakub Dawidek goto authcommon; 840f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 841091d81d1SSam Leffler axf = &auth_hash_hmac_sha2_512; 842091d81d1SSam Leffler goto authcommon; 843091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 844091d81d1SSam Leffler axf = &auth_hash_null; 845091d81d1SSam Leffler goto authcommon; 846091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 847f6c4bc3bSPawel Jakub Dawidek axf = &auth_hash_hmac_ripemd_160; 848091d81d1SSam Leffler authcommon: 849*9ebbebe4SConrad Meyer swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 850091d81d1SSam Leffler M_NOWAIT); 851*9ebbebe4SConrad Meyer if (swd->sw_ictx == NULL) { 8521b0909d5SConrad Meyer swcr_freesession(dev, cses); 853091d81d1SSam Leffler return ENOBUFS; 854091d81d1SSam Leffler } 855091d81d1SSam Leffler 856*9ebbebe4SConrad Meyer swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA, 857091d81d1SSam Leffler M_NOWAIT); 858*9ebbebe4SConrad Meyer if (swd->sw_octx == NULL) { 8591b0909d5SConrad Meyer swcr_freesession(dev, cses); 860091d81d1SSam Leffler return ENOBUFS; 861091d81d1SSam Leffler } 862091d81d1SSam Leffler 863f6c4bc3bSPawel Jakub Dawidek if (cri->cri_key != NULL) { 864*9ebbebe4SConrad Meyer error = swcr_authprepare(axf, swd, 86525b7033bSConrad Meyer cri->cri_key, cri->cri_klen); 86625b7033bSConrad Meyer if (error != 0) { 86725b7033bSConrad Meyer swcr_freesession(dev, cses); 86825b7033bSConrad Meyer return error; 86925b7033bSConrad Meyer } 870f6c4bc3bSPawel Jakub Dawidek } 871091d81d1SSam Leffler 872*9ebbebe4SConrad Meyer swd->sw_mlen = cri->cri_mlen; 873*9ebbebe4SConrad Meyer swd->sw_axf = axf; 874091d81d1SSam Leffler break; 875091d81d1SSam Leffler 876091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 877091d81d1SSam Leffler axf = &auth_hash_key_md5; 878091d81d1SSam Leffler goto auth2common; 879091d81d1SSam Leffler 880091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 881091d81d1SSam Leffler axf = &auth_hash_key_sha1; 882091d81d1SSam Leffler auth2common: 883*9ebbebe4SConrad Meyer swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 884091d81d1SSam Leffler M_NOWAIT); 885*9ebbebe4SConrad Meyer if (swd->sw_ictx == NULL) { 8861b0909d5SConrad Meyer swcr_freesession(dev, cses); 887091d81d1SSam Leffler return ENOBUFS; 888091d81d1SSam Leffler } 889091d81d1SSam Leffler 890*9ebbebe4SConrad Meyer swd->sw_octx = malloc(cri->cri_klen / 8, 891f6c4bc3bSPawel Jakub Dawidek M_CRYPTO_DATA, M_NOWAIT); 892*9ebbebe4SConrad Meyer if (swd->sw_octx == NULL) { 8931b0909d5SConrad Meyer swcr_freesession(dev, cses); 894091d81d1SSam Leffler return ENOBUFS; 895091d81d1SSam Leffler } 896091d81d1SSam Leffler 897f6c4bc3bSPawel Jakub Dawidek /* Store the key so we can "append" it to the payload */ 898f6c4bc3bSPawel Jakub Dawidek if (cri->cri_key != NULL) { 899*9ebbebe4SConrad Meyer error = swcr_authprepare(axf, swd, 90025b7033bSConrad Meyer cri->cri_key, cri->cri_klen); 90125b7033bSConrad Meyer if (error != 0) { 90225b7033bSConrad Meyer swcr_freesession(dev, cses); 90325b7033bSConrad Meyer return error; 90425b7033bSConrad Meyer } 905f6c4bc3bSPawel Jakub Dawidek } 906f6c4bc3bSPawel Jakub Dawidek 907*9ebbebe4SConrad Meyer swd->sw_mlen = cri->cri_mlen; 908*9ebbebe4SConrad Meyer swd->sw_axf = axf; 909091d81d1SSam Leffler break; 910091d81d1SSam Leffler #ifdef notdef 911091d81d1SSam Leffler case CRYPTO_MD5: 912091d81d1SSam Leffler axf = &auth_hash_md5; 913091d81d1SSam Leffler goto auth3common; 914c4729f6eSConrad Meyer #endif 915091d81d1SSam Leffler 916091d81d1SSam Leffler case CRYPTO_SHA1: 917091d81d1SSam Leffler axf = &auth_hash_sha1; 918c4729f6eSConrad Meyer goto auth3common; 919c4729f6eSConrad Meyer case CRYPTO_SHA2_224: 920c4729f6eSConrad Meyer axf = &auth_hash_sha2_224; 921c4729f6eSConrad Meyer goto auth3common; 922c4729f6eSConrad Meyer case CRYPTO_SHA2_256: 923c4729f6eSConrad Meyer axf = &auth_hash_sha2_256; 924c4729f6eSConrad Meyer goto auth3common; 925c4729f6eSConrad Meyer case CRYPTO_SHA2_384: 926c4729f6eSConrad Meyer axf = &auth_hash_sha2_384; 927c4729f6eSConrad Meyer goto auth3common; 928c4729f6eSConrad Meyer case CRYPTO_SHA2_512: 929c4729f6eSConrad Meyer axf = &auth_hash_sha2_512; 930c4729f6eSConrad Meyer 931091d81d1SSam Leffler auth3common: 932*9ebbebe4SConrad Meyer swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 933091d81d1SSam Leffler M_NOWAIT); 934*9ebbebe4SConrad Meyer if (swd->sw_ictx == NULL) { 9351b0909d5SConrad Meyer swcr_freesession(dev, cses); 936091d81d1SSam Leffler return ENOBUFS; 937091d81d1SSam Leffler } 938091d81d1SSam Leffler 939*9ebbebe4SConrad Meyer axf->Init(swd->sw_ictx); 940*9ebbebe4SConrad Meyer swd->sw_mlen = cri->cri_mlen; 941*9ebbebe4SConrad Meyer swd->sw_axf = axf; 942091d81d1SSam Leffler break; 94308fca7a5SJohn-Mark Gurney 94408fca7a5SJohn-Mark Gurney case CRYPTO_AES_128_NIST_GMAC: 94508fca7a5SJohn-Mark Gurney axf = &auth_hash_nist_gmac_aes_128; 94608fca7a5SJohn-Mark Gurney goto auth4common; 94708fca7a5SJohn-Mark Gurney 94808fca7a5SJohn-Mark Gurney case CRYPTO_AES_192_NIST_GMAC: 94908fca7a5SJohn-Mark Gurney axf = &auth_hash_nist_gmac_aes_192; 95008fca7a5SJohn-Mark Gurney goto auth4common; 95108fca7a5SJohn-Mark Gurney 95208fca7a5SJohn-Mark Gurney case CRYPTO_AES_256_NIST_GMAC: 95308fca7a5SJohn-Mark Gurney axf = &auth_hash_nist_gmac_aes_256; 95408fca7a5SJohn-Mark Gurney auth4common: 955a2bc81bfSJohn-Mark Gurney len = cri->cri_klen / 8; 9562e2e26d1SJohn Baldwin if (len != 16 && len != 24 && len != 32) { 9571b0909d5SConrad Meyer swcr_freesession(dev, cses); 958a2bc81bfSJohn-Mark Gurney return EINVAL; 9592e2e26d1SJohn Baldwin } 960a2bc81bfSJohn-Mark Gurney 961*9ebbebe4SConrad Meyer swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 96208fca7a5SJohn-Mark Gurney M_NOWAIT); 963*9ebbebe4SConrad Meyer if (swd->sw_ictx == NULL) { 9641b0909d5SConrad Meyer swcr_freesession(dev, cses); 96508fca7a5SJohn-Mark Gurney return ENOBUFS; 96608fca7a5SJohn-Mark Gurney } 967*9ebbebe4SConrad Meyer axf->Init(swd->sw_ictx); 968*9ebbebe4SConrad Meyer axf->Setkey(swd->sw_ictx, cri->cri_key, len); 969*9ebbebe4SConrad Meyer swd->sw_axf = axf; 97008fca7a5SJohn-Mark Gurney break; 97108fca7a5SJohn-Mark Gurney 9720e33efe4SConrad Meyer case CRYPTO_BLAKE2B: 9730e33efe4SConrad Meyer axf = &auth_hash_blake2b; 9740e33efe4SConrad Meyer goto auth5common; 9750e33efe4SConrad Meyer case CRYPTO_BLAKE2S: 9760e33efe4SConrad Meyer axf = &auth_hash_blake2s; 97725b7033bSConrad Meyer goto auth5common; 97825b7033bSConrad Meyer case CRYPTO_POLY1305: 97925b7033bSConrad Meyer axf = &auth_hash_poly1305; 9800e33efe4SConrad Meyer auth5common: 981*9ebbebe4SConrad Meyer swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, 9820e33efe4SConrad Meyer M_NOWAIT); 983*9ebbebe4SConrad Meyer if (swd->sw_ictx == NULL) { 9841b0909d5SConrad Meyer swcr_freesession(dev, cses); 9850e33efe4SConrad Meyer return ENOBUFS; 9860e33efe4SConrad Meyer } 987*9ebbebe4SConrad Meyer axf->Setkey(swd->sw_ictx, cri->cri_key, 9880e33efe4SConrad Meyer cri->cri_klen / 8); 989*9ebbebe4SConrad Meyer axf->Init(swd->sw_ictx); 990*9ebbebe4SConrad Meyer swd->sw_axf = axf; 9910e33efe4SConrad Meyer break; 9920e33efe4SConrad Meyer 993091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 994091d81d1SSam Leffler cxf = &comp_algo_deflate; 995*9ebbebe4SConrad Meyer swd->sw_cxf = cxf; 996091d81d1SSam Leffler break; 997091d81d1SSam Leffler default: 9981b0909d5SConrad Meyer swcr_freesession(dev, cses); 999091d81d1SSam Leffler return EINVAL; 1000091d81d1SSam Leffler } 1001091d81d1SSam Leffler 1002*9ebbebe4SConrad Meyer swd->sw_alg = cri->cri_alg; 1003091d81d1SSam Leffler cri = cri->cri_next; 1004*9ebbebe4SConrad Meyer ses->swcr_nalgs++; 1005*9ebbebe4SConrad Meyer } 1006*9ebbebe4SConrad Meyer 1007*9ebbebe4SConrad Meyer if (cri != NULL) { 1008*9ebbebe4SConrad Meyer CRYPTDEB("Bogus session request for three or more algorithms"); 1009*9ebbebe4SConrad Meyer return EINVAL; 1010091d81d1SSam Leffler } 1011091d81d1SSam Leffler return 0; 1012091d81d1SSam Leffler } 1013091d81d1SSam Leffler 10141b0909d5SConrad Meyer static void 10151b0909d5SConrad Meyer swcr_freesession(device_t dev, crypto_session_t cses) 1016109919c6SBenno Rice { 1017*9ebbebe4SConrad Meyer struct swcr_session *ses; 1018*9ebbebe4SConrad Meyer struct swcr_data *swd; 1019091d81d1SSam Leffler struct enc_xform *txf; 1020091d81d1SSam Leffler struct auth_hash *axf; 1021*9ebbebe4SConrad Meyer size_t i; 1022091d81d1SSam Leffler 10231b0909d5SConrad Meyer ses = crypto_get_driver_session(cses); 1024091d81d1SSam Leffler 1025*9ebbebe4SConrad Meyer for (i = 0; i < nitems(ses->swcr_algorithms); i++) { 1026*9ebbebe4SConrad Meyer swd = &ses->swcr_algorithms[i]; 1027091d81d1SSam Leffler 1028091d81d1SSam Leffler switch (swd->sw_alg) { 1029091d81d1SSam Leffler case CRYPTO_DES_CBC: 1030091d81d1SSam Leffler case CRYPTO_3DES_CBC: 1031091d81d1SSam Leffler case CRYPTO_BLF_CBC: 1032091d81d1SSam Leffler case CRYPTO_CAST_CBC: 1033091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 1034091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 1035d295bdeeSPawel Jakub Dawidek case CRYPTO_AES_XTS: 103608fca7a5SJohn-Mark Gurney case CRYPTO_AES_ICM: 103708fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GCM_16: 103808fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GMAC: 1039559d3390SGeorge V. Neville-Neil case CRYPTO_CAMELLIA_CBC: 1040091d81d1SSam Leffler case CRYPTO_NULL_CBC: 104161590291SConrad Meyer case CRYPTO_CHACHA20: 1042091d81d1SSam Leffler txf = swd->sw_exf; 1043091d81d1SSam Leffler 1044091d81d1SSam Leffler if (swd->sw_kschedule) 1045091d81d1SSam Leffler txf->zerokey(&(swd->sw_kschedule)); 1046091d81d1SSam Leffler break; 1047091d81d1SSam Leffler 1048091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 1049091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 1050c97f39ceSConrad Meyer case CRYPTO_SHA2_224_HMAC: 1051f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 1052f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 1053f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 1054091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 1055091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 1056091d81d1SSam Leffler axf = swd->sw_axf; 1057091d81d1SSam Leffler 1058091d81d1SSam Leffler if (swd->sw_ictx) { 1059091d81d1SSam Leffler bzero(swd->sw_ictx, axf->ctxsize); 1060091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 1061091d81d1SSam Leffler } 1062091d81d1SSam Leffler if (swd->sw_octx) { 1063091d81d1SSam Leffler bzero(swd->sw_octx, axf->ctxsize); 1064091d81d1SSam Leffler free(swd->sw_octx, M_CRYPTO_DATA); 1065091d81d1SSam Leffler } 1066091d81d1SSam Leffler break; 1067091d81d1SSam Leffler 1068091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 1069091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 1070091d81d1SSam Leffler axf = swd->sw_axf; 1071091d81d1SSam Leffler 1072091d81d1SSam Leffler if (swd->sw_ictx) { 1073091d81d1SSam Leffler bzero(swd->sw_ictx, axf->ctxsize); 1074091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 1075091d81d1SSam Leffler } 1076091d81d1SSam Leffler if (swd->sw_octx) { 1077091d81d1SSam Leffler bzero(swd->sw_octx, swd->sw_klen); 1078091d81d1SSam Leffler free(swd->sw_octx, M_CRYPTO_DATA); 1079091d81d1SSam Leffler } 1080091d81d1SSam Leffler break; 1081091d81d1SSam Leffler 10820e33efe4SConrad Meyer case CRYPTO_BLAKE2B: 10830e33efe4SConrad Meyer case CRYPTO_BLAKE2S: 1084091d81d1SSam Leffler case CRYPTO_MD5: 108525b7033bSConrad Meyer case CRYPTO_POLY1305: 1086091d81d1SSam Leffler case CRYPTO_SHA1: 1087c4729f6eSConrad Meyer case CRYPTO_SHA2_224: 1088c4729f6eSConrad Meyer case CRYPTO_SHA2_256: 1089c4729f6eSConrad Meyer case CRYPTO_SHA2_384: 1090c4729f6eSConrad Meyer case CRYPTO_SHA2_512: 1091091d81d1SSam Leffler axf = swd->sw_axf; 1092091d81d1SSam Leffler 10935fbc5b5aSConrad Meyer if (swd->sw_ictx) { 10945fbc5b5aSConrad Meyer explicit_bzero(swd->sw_ictx, axf->ctxsize); 1095091d81d1SSam Leffler free(swd->sw_ictx, M_CRYPTO_DATA); 10965fbc5b5aSConrad Meyer } 1097091d81d1SSam Leffler break; 1098091d81d1SSam Leffler 1099091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 1100151ba793SAlexander Kabaev /* Nothing to do */ 1101091d81d1SSam Leffler break; 1102091d81d1SSam Leffler } 1103091d81d1SSam Leffler } 1104091d81d1SSam Leffler } 1105091d81d1SSam Leffler 1106091d81d1SSam Leffler /* 1107091d81d1SSam Leffler * Process a software request. 1108091d81d1SSam Leffler */ 1109091d81d1SSam Leffler static int 11106810ad6fSSam Leffler swcr_process(device_t dev, struct cryptop *crp, int hint) 1111091d81d1SSam Leffler { 1112*9ebbebe4SConrad Meyer struct swcr_session *ses; 1113091d81d1SSam Leffler struct cryptodesc *crd; 1114*9ebbebe4SConrad Meyer struct swcr_data *sw; 1115*9ebbebe4SConrad Meyer size_t i; 1116091d81d1SSam Leffler 1117091d81d1SSam Leffler /* Sanity check */ 1118091d81d1SSam Leffler if (crp == NULL) 1119091d81d1SSam Leffler return EINVAL; 1120091d81d1SSam Leffler 1121091d81d1SSam Leffler if (crp->crp_desc == NULL || crp->crp_buf == NULL) { 1122091d81d1SSam Leffler crp->crp_etype = EINVAL; 1123091d81d1SSam Leffler goto done; 1124091d81d1SSam Leffler } 1125091d81d1SSam Leffler 11261b0909d5SConrad Meyer ses = crypto_get_driver_session(crp->crp_session); 1127091d81d1SSam Leffler 1128091d81d1SSam Leffler /* Go through crypto descriptors, processing as we go */ 1129091d81d1SSam Leffler for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 1130091d81d1SSam Leffler /* 1131091d81d1SSam Leffler * Find the crypto context. 1132091d81d1SSam Leffler * 1133091d81d1SSam Leffler * XXX Note that the logic here prevents us from having 1134091d81d1SSam Leffler * XXX the same algorithm multiple times in a session 1135091d81d1SSam Leffler * XXX (or rather, we can but it won't give us the right 1136091d81d1SSam Leffler * XXX results). To do that, we'd need some way of differentiating 1137091d81d1SSam Leffler * XXX between the various instances of an algorithm (so we can 1138091d81d1SSam Leffler * XXX locate the correct crypto context). 1139091d81d1SSam Leffler */ 1140*9ebbebe4SConrad Meyer for (i = 0; i < nitems(ses->swcr_algorithms) && 1141*9ebbebe4SConrad Meyer ses->swcr_algorithms[i].sw_alg != crd->crd_alg; i++) 1142091d81d1SSam Leffler ; 1143091d81d1SSam Leffler 1144091d81d1SSam Leffler /* No such context ? */ 1145*9ebbebe4SConrad Meyer if (i == nitems(ses->swcr_algorithms)) { 1146091d81d1SSam Leffler crp->crp_etype = EINVAL; 1147091d81d1SSam Leffler goto done; 1148091d81d1SSam Leffler } 1149*9ebbebe4SConrad Meyer sw = &ses->swcr_algorithms[i]; 1150091d81d1SSam Leffler switch (sw->sw_alg) { 1151091d81d1SSam Leffler case CRYPTO_DES_CBC: 1152091d81d1SSam Leffler case CRYPTO_3DES_CBC: 1153091d81d1SSam Leffler case CRYPTO_BLF_CBC: 1154091d81d1SSam Leffler case CRYPTO_CAST_CBC: 1155091d81d1SSam Leffler case CRYPTO_SKIPJACK_CBC: 1156091d81d1SSam Leffler case CRYPTO_RIJNDAEL128_CBC: 1157d295bdeeSPawel Jakub Dawidek case CRYPTO_AES_XTS: 115808fca7a5SJohn-Mark Gurney case CRYPTO_AES_ICM: 1159559d3390SGeorge V. Neville-Neil case CRYPTO_CAMELLIA_CBC: 116061590291SConrad Meyer case CRYPTO_CHACHA20: 1161091d81d1SSam Leffler if ((crp->crp_etype = swcr_encdec(crd, sw, 1162f34a967bSPawel Jakub Dawidek crp->crp_buf, crp->crp_flags)) != 0) 1163091d81d1SSam Leffler goto done; 1164091d81d1SSam Leffler break; 1165091d81d1SSam Leffler case CRYPTO_NULL_CBC: 1166091d81d1SSam Leffler crp->crp_etype = 0; 1167091d81d1SSam Leffler break; 1168091d81d1SSam Leffler case CRYPTO_MD5_HMAC: 1169091d81d1SSam Leffler case CRYPTO_SHA1_HMAC: 1170c97f39ceSConrad Meyer case CRYPTO_SHA2_224_HMAC: 1171f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 1172f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 1173f6c4bc3bSPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 1174091d81d1SSam Leffler case CRYPTO_RIPEMD160_HMAC: 1175091d81d1SSam Leffler case CRYPTO_NULL_HMAC: 1176091d81d1SSam Leffler case CRYPTO_MD5_KPDK: 1177091d81d1SSam Leffler case CRYPTO_SHA1_KPDK: 1178091d81d1SSam Leffler case CRYPTO_MD5: 1179091d81d1SSam Leffler case CRYPTO_SHA1: 1180c4729f6eSConrad Meyer case CRYPTO_SHA2_224: 1181c4729f6eSConrad Meyer case CRYPTO_SHA2_256: 1182c4729f6eSConrad Meyer case CRYPTO_SHA2_384: 1183c4729f6eSConrad Meyer case CRYPTO_SHA2_512: 11840e33efe4SConrad Meyer case CRYPTO_BLAKE2B: 11850e33efe4SConrad Meyer case CRYPTO_BLAKE2S: 118625b7033bSConrad Meyer case CRYPTO_POLY1305: 118738d2f8d6SPawel Jakub Dawidek if ((crp->crp_etype = swcr_authcompute(crd, sw, 1188f34a967bSPawel Jakub Dawidek crp->crp_buf, crp->crp_flags)) != 0) 1189091d81d1SSam Leffler goto done; 1190091d81d1SSam Leffler break; 1191091d81d1SSam Leffler 119208fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GCM_16: 119308fca7a5SJohn-Mark Gurney case CRYPTO_AES_NIST_GMAC: 119408fca7a5SJohn-Mark Gurney case CRYPTO_AES_128_NIST_GMAC: 119508fca7a5SJohn-Mark Gurney case CRYPTO_AES_192_NIST_GMAC: 119608fca7a5SJohn-Mark Gurney case CRYPTO_AES_256_NIST_GMAC: 119708fca7a5SJohn-Mark Gurney crp->crp_etype = swcr_authenc(crp); 119808fca7a5SJohn-Mark Gurney goto done; 119908fca7a5SJohn-Mark Gurney 1200091d81d1SSam Leffler case CRYPTO_DEFLATE_COMP: 1201091d81d1SSam Leffler if ((crp->crp_etype = swcr_compdec(crd, sw, 1202f34a967bSPawel Jakub Dawidek crp->crp_buf, crp->crp_flags)) != 0) 1203091d81d1SSam Leffler goto done; 1204091d81d1SSam Leffler else 1205091d81d1SSam Leffler crp->crp_olen = (int)sw->sw_size; 1206091d81d1SSam Leffler break; 1207091d81d1SSam Leffler 1208091d81d1SSam Leffler default: 1209091d81d1SSam Leffler /* Unknown/unsupported algorithm */ 1210091d81d1SSam Leffler crp->crp_etype = EINVAL; 1211091d81d1SSam Leffler goto done; 1212091d81d1SSam Leffler } 1213091d81d1SSam Leffler } 1214091d81d1SSam Leffler 1215091d81d1SSam Leffler done: 1216091d81d1SSam Leffler crypto_done(crp); 1217091d81d1SSam Leffler return 0; 1218091d81d1SSam Leffler } 1219091d81d1SSam Leffler 1220091d81d1SSam Leffler static void 12213f147ab2SWarner Losh swcr_identify(driver_t *drv, device_t parent) 1222091d81d1SSam Leffler { 12236810ad6fSSam Leffler /* NB: order 10 is so we get attached after h/w devices */ 12246810ad6fSSam Leffler if (device_find_child(parent, "cryptosoft", -1) == NULL && 122586c585d9SMarius Strobl BUS_ADD_CHILD(parent, 10, "cryptosoft", 0) == 0) 12266810ad6fSSam Leffler panic("cryptosoft: could not attach"); 12276810ad6fSSam Leffler } 1228f6c4bc3bSPawel Jakub Dawidek 12296810ad6fSSam Leffler static int 12306810ad6fSSam Leffler swcr_probe(device_t dev) 12316810ad6fSSam Leffler { 12326810ad6fSSam Leffler device_set_desc(dev, "software crypto"); 123386c585d9SMarius Strobl return (BUS_PROBE_NOWILDCARD); 12346810ad6fSSam Leffler } 1235f6c4bc3bSPawel Jakub Dawidek 12366810ad6fSSam Leffler static int 12376810ad6fSSam Leffler swcr_attach(device_t dev) 12386810ad6fSSam Leffler { 12396810ad6fSSam Leffler memset(hmac_ipad_buffer, HMAC_IPAD_VAL, HMAC_MAX_BLOCK_LEN); 12406810ad6fSSam Leffler memset(hmac_opad_buffer, HMAC_OPAD_VAL, HMAC_MAX_BLOCK_LEN); 12416810ad6fSSam Leffler 1242*9ebbebe4SConrad Meyer swcr_id = crypto_get_driverid(dev, sizeof(struct swcr_session), 12436810ad6fSSam Leffler CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC); 12446810ad6fSSam Leffler if (swcr_id < 0) { 12456810ad6fSSam Leffler device_printf(dev, "cannot initialize!"); 12466810ad6fSSam Leffler return ENOMEM; 12476810ad6fSSam Leffler } 1248091d81d1SSam Leffler #define REGISTER(alg) \ 12496810ad6fSSam Leffler crypto_register(swcr_id, alg, 0,0) 12506810ad6fSSam Leffler REGISTER(CRYPTO_DES_CBC); 1251091d81d1SSam Leffler REGISTER(CRYPTO_3DES_CBC); 1252091d81d1SSam Leffler REGISTER(CRYPTO_BLF_CBC); 1253091d81d1SSam Leffler REGISTER(CRYPTO_CAST_CBC); 1254091d81d1SSam Leffler REGISTER(CRYPTO_SKIPJACK_CBC); 1255091d81d1SSam Leffler REGISTER(CRYPTO_NULL_CBC); 1256091d81d1SSam Leffler REGISTER(CRYPTO_MD5_HMAC); 1257091d81d1SSam Leffler REGISTER(CRYPTO_SHA1_HMAC); 1258c97f39ceSConrad Meyer REGISTER(CRYPTO_SHA2_224_HMAC); 1259f6c4bc3bSPawel Jakub Dawidek REGISTER(CRYPTO_SHA2_256_HMAC); 1260f6c4bc3bSPawel Jakub Dawidek REGISTER(CRYPTO_SHA2_384_HMAC); 1261f6c4bc3bSPawel Jakub Dawidek REGISTER(CRYPTO_SHA2_512_HMAC); 1262091d81d1SSam Leffler REGISTER(CRYPTO_RIPEMD160_HMAC); 1263091d81d1SSam Leffler REGISTER(CRYPTO_NULL_HMAC); 1264091d81d1SSam Leffler REGISTER(CRYPTO_MD5_KPDK); 1265091d81d1SSam Leffler REGISTER(CRYPTO_SHA1_KPDK); 1266091d81d1SSam Leffler REGISTER(CRYPTO_MD5); 1267091d81d1SSam Leffler REGISTER(CRYPTO_SHA1); 1268c4729f6eSConrad Meyer REGISTER(CRYPTO_SHA2_224); 1269c4729f6eSConrad Meyer REGISTER(CRYPTO_SHA2_256); 1270c4729f6eSConrad Meyer REGISTER(CRYPTO_SHA2_384); 1271c4729f6eSConrad Meyer REGISTER(CRYPTO_SHA2_512); 1272091d81d1SSam Leffler REGISTER(CRYPTO_RIJNDAEL128_CBC); 1273d295bdeeSPawel Jakub Dawidek REGISTER(CRYPTO_AES_XTS); 127408fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_ICM); 127508fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_NIST_GCM_16); 127608fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_NIST_GMAC); 127708fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_128_NIST_GMAC); 127808fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_192_NIST_GMAC); 127908fca7a5SJohn-Mark Gurney REGISTER(CRYPTO_AES_256_NIST_GMAC); 1280559d3390SGeorge V. Neville-Neil REGISTER(CRYPTO_CAMELLIA_CBC); 1281091d81d1SSam Leffler REGISTER(CRYPTO_DEFLATE_COMP); 12820e33efe4SConrad Meyer REGISTER(CRYPTO_BLAKE2B); 12830e33efe4SConrad Meyer REGISTER(CRYPTO_BLAKE2S); 128461590291SConrad Meyer REGISTER(CRYPTO_CHACHA20); 128525b7033bSConrad Meyer REGISTER(CRYPTO_POLY1305); 1286091d81d1SSam Leffler #undef REGISTER 12876810ad6fSSam Leffler 12886810ad6fSSam Leffler return 0; 1289091d81d1SSam Leffler } 12904b465da2SPawel Jakub Dawidek 12913f147ab2SWarner Losh static int 12926810ad6fSSam Leffler swcr_detach(device_t dev) 12934b465da2SPawel Jakub Dawidek { 12946810ad6fSSam Leffler crypto_unregister_all(swcr_id); 12953f147ab2SWarner Losh return 0; 12964b465da2SPawel Jakub Dawidek } 12976810ad6fSSam Leffler 12986810ad6fSSam Leffler static device_method_t swcr_methods[] = { 12996810ad6fSSam Leffler DEVMETHOD(device_identify, swcr_identify), 13006810ad6fSSam Leffler DEVMETHOD(device_probe, swcr_probe), 13016810ad6fSSam Leffler DEVMETHOD(device_attach, swcr_attach), 13026810ad6fSSam Leffler DEVMETHOD(device_detach, swcr_detach), 13036810ad6fSSam Leffler 13046810ad6fSSam Leffler DEVMETHOD(cryptodev_newsession, swcr_newsession), 13056810ad6fSSam Leffler DEVMETHOD(cryptodev_freesession,swcr_freesession), 13066810ad6fSSam Leffler DEVMETHOD(cryptodev_process, swcr_process), 13076810ad6fSSam Leffler 13086810ad6fSSam Leffler {0, 0}, 13096810ad6fSSam Leffler }; 13106810ad6fSSam Leffler 13116810ad6fSSam Leffler static driver_t swcr_driver = { 13126810ad6fSSam Leffler "cryptosoft", 13136810ad6fSSam Leffler swcr_methods, 13146810ad6fSSam Leffler 0, /* NB: no softc */ 13156810ad6fSSam Leffler }; 13166810ad6fSSam Leffler static devclass_t swcr_devclass; 13176810ad6fSSam Leffler 13186810ad6fSSam Leffler /* 13196810ad6fSSam Leffler * NB: We explicitly reference the crypto module so we 13206810ad6fSSam Leffler * get the necessary ordering when built as a loadable 13216810ad6fSSam Leffler * module. This is required because we bundle the crypto 13226810ad6fSSam Leffler * module code together with the cryptosoft driver (otherwise 13236810ad6fSSam Leffler * normal module dependencies would handle things). 13246810ad6fSSam Leffler */ 13256810ad6fSSam Leffler extern int crypto_modevent(struct module *, int, void *); 13266810ad6fSSam Leffler /* XXX where to attach */ 13276810ad6fSSam Leffler DRIVER_MODULE(cryptosoft, nexus, swcr_driver, swcr_devclass, crypto_modevent,0); 13286810ad6fSSam Leffler MODULE_VERSION(cryptosoft, 1); 13296810ad6fSSam Leffler MODULE_DEPEND(cryptosoft, crypto, 1, 1, 1); 1330