1184588Sdfr/*- 2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5184588Sdfr * 6184588Sdfr * Redistribution and use in source and binary forms, with or without 7184588Sdfr * modification, are permitted provided that the following conditions 8184588Sdfr * are met: 9184588Sdfr * 1. Redistributions of source code must retain the above copyright 10184588Sdfr * notice, this list of conditions and the following disclaimer. 11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12184588Sdfr * notice, this list of conditions and the following disclaimer in the 13184588Sdfr * documentation and/or other materials provided with the distribution. 14184588Sdfr * 15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184588Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184588Sdfr * SUCH DAMAGE. 26184588Sdfr */ 27184588Sdfr 28184588Sdfr#include <sys/cdefs.h> 29184588Sdfr__FBSDID("$FreeBSD$"); 30184588Sdfr 31184588Sdfr#include <sys/param.h> 32184588Sdfr#include <sys/lock.h> 33184588Sdfr#include <sys/malloc.h> 34184588Sdfr#include <sys/mutex.h> 35184588Sdfr#include <sys/kobj.h> 36184588Sdfr#include <sys/mbuf.h> 37184588Sdfr#include <opencrypto/cryptodev.h> 38184588Sdfr 39184588Sdfr#include <kgssapi/gssapi.h> 40184588Sdfr#include <kgssapi/gssapi_impl.h> 41184588Sdfr 42184588Sdfr#include "kcrypto.h" 43184588Sdfr 44184588Sdfrstruct aes_state { 45184588Sdfr struct mtx as_lock; 46184588Sdfr uint64_t as_session; 47184588Sdfr}; 48184588Sdfr 49184588Sdfrstatic void 50184588Sdfraes_init(struct krb5_key_state *ks) 51184588Sdfr{ 52184588Sdfr struct aes_state *as; 53184588Sdfr 54184588Sdfr as = malloc(sizeof(struct aes_state), M_GSSAPI, M_WAITOK|M_ZERO); 55184588Sdfr mtx_init(&as->as_lock, "gss aes lock", NULL, MTX_DEF); 56184588Sdfr ks->ks_priv = as; 57184588Sdfr} 58184588Sdfr 59184588Sdfrstatic void 60184588Sdfraes_destroy(struct krb5_key_state *ks) 61184588Sdfr{ 62184588Sdfr struct aes_state *as = ks->ks_priv; 63184588Sdfr 64184588Sdfr if (as->as_session) 65184588Sdfr crypto_freesession(as->as_session); 66184588Sdfr mtx_destroy(&as->as_lock); 67184588Sdfr free(ks->ks_priv, M_GSSAPI); 68184588Sdfr} 69184588Sdfr 70184588Sdfrstatic void 71184588Sdfraes_set_key(struct krb5_key_state *ks, const void *in) 72184588Sdfr{ 73184588Sdfr void *kp = ks->ks_key; 74184588Sdfr struct aes_state *as = ks->ks_priv; 75184588Sdfr struct cryptoini cri[2]; 76184588Sdfr 77184588Sdfr if (kp != in) 78184588Sdfr bcopy(in, kp, ks->ks_class->ec_keylen); 79184588Sdfr 80184588Sdfr if (as->as_session) 81184588Sdfr crypto_freesession(as->as_session); 82184588Sdfr 83184588Sdfr bzero(cri, sizeof(cri)); 84184588Sdfr 85184588Sdfr /* 86184588Sdfr * We only want the first 96 bits of the HMAC. 87184588Sdfr */ 88184588Sdfr cri[0].cri_alg = CRYPTO_SHA1_HMAC; 89184588Sdfr cri[0].cri_klen = ks->ks_class->ec_keybits; 90184588Sdfr cri[0].cri_mlen = 12; 91184588Sdfr cri[0].cri_key = ks->ks_key; 92184588Sdfr cri[0].cri_next = &cri[1]; 93184588Sdfr 94184588Sdfr cri[1].cri_alg = CRYPTO_AES_CBC; 95184588Sdfr cri[1].cri_klen = ks->ks_class->ec_keybits; 96184588Sdfr cri[1].cri_mlen = 0; 97184588Sdfr cri[1].cri_key = ks->ks_key; 98184588Sdfr cri[1].cri_next = NULL; 99184588Sdfr 100184588Sdfr crypto_newsession(&as->as_session, cri, 101184588Sdfr CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 102184588Sdfr} 103184588Sdfr 104184588Sdfrstatic void 105184588Sdfraes_random_to_key(struct krb5_key_state *ks, const void *in) 106184588Sdfr{ 107184588Sdfr 108184588Sdfr aes_set_key(ks, in); 109184588Sdfr} 110184588Sdfr 111184588Sdfrstatic int 112184588Sdfraes_crypto_cb(struct cryptop *crp) 113184588Sdfr{ 114184588Sdfr int error; 115184588Sdfr struct aes_state *as = (struct aes_state *) crp->crp_opaque; 116184588Sdfr 117184588Sdfr if (CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) 118184588Sdfr return (0); 119184588Sdfr 120184588Sdfr error = crp->crp_etype; 121184588Sdfr if (error == EAGAIN) 122184588Sdfr error = crypto_dispatch(crp); 123184588Sdfr mtx_lock(&as->as_lock); 124184588Sdfr if (error || (crp->crp_flags & CRYPTO_F_DONE)) 125184588Sdfr wakeup(crp); 126184588Sdfr mtx_unlock(&as->as_lock); 127184588Sdfr 128184588Sdfr return (0); 129184588Sdfr} 130184588Sdfr 131184588Sdfrstatic void 132184588Sdfraes_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf, 133184588Sdfr size_t skip, size_t len, void *ivec, int encdec) 134184588Sdfr{ 135184588Sdfr struct aes_state *as = ks->ks_priv; 136184588Sdfr struct cryptop *crp; 137184588Sdfr struct cryptodesc *crd; 138184588Sdfr int error; 139184588Sdfr 140184588Sdfr crp = crypto_getreq(1); 141184588Sdfr crd = crp->crp_desc; 142184588Sdfr 143184588Sdfr crd->crd_skip = skip; 144184588Sdfr crd->crd_len = len; 145184588Sdfr crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | encdec; 146184588Sdfr if (ivec) { 147184588Sdfr bcopy(ivec, crd->crd_iv, 16); 148184588Sdfr } else { 149184588Sdfr bzero(crd->crd_iv, 16); 150184588Sdfr } 151184588Sdfr crd->crd_next = NULL; 152184588Sdfr crd->crd_alg = CRYPTO_AES_CBC; 153184588Sdfr 154184588Sdfr crp->crp_sid = as->as_session; 155184588Sdfr crp->crp_flags = buftype | CRYPTO_F_CBIFSYNC; 156184588Sdfr crp->crp_buf = buf; 157184588Sdfr crp->crp_opaque = (void *) as; 158184588Sdfr crp->crp_callback = aes_crypto_cb; 159184588Sdfr 160184588Sdfr error = crypto_dispatch(crp); 161184588Sdfr 162184588Sdfr if ((CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) == 0) { 163184588Sdfr mtx_lock(&as->as_lock); 164184588Sdfr if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 165184588Sdfr error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 166184588Sdfr mtx_unlock(&as->as_lock); 167184588Sdfr } 168184588Sdfr 169184588Sdfr crypto_freereq(crp); 170184588Sdfr} 171184588Sdfr 172184588Sdfrstatic void 173184588Sdfraes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout, 174184588Sdfr size_t skip, size_t len, void *ivec, size_t ivlen) 175184588Sdfr{ 176184588Sdfr size_t blocklen = 16, plen; 177184588Sdfr struct { 178184588Sdfr uint8_t cn_1[16], cn[16]; 179184588Sdfr } last2; 180184588Sdfr int i, off; 181184588Sdfr 182184588Sdfr /* 183184588Sdfr * AES encryption with cyphertext stealing: 184184588Sdfr * 185184588Sdfr * CTSencrypt(P[0], ..., P[n], IV, K): 186184588Sdfr * len = length(P[n]) 187184588Sdfr * (C[0], ..., C[n-2], E[n-1]) = 188184588Sdfr * CBCencrypt(P[0], ..., P[n-1], IV, K) 189184588Sdfr * P = pad(P[n], 0, blocksize) 190184588Sdfr * E[n] = CBCencrypt(P, E[n-1], K); 191184588Sdfr * C[n-1] = E[n] 192184588Sdfr * C[n] = E[n-1]{0..len-1} 193184588Sdfr */ 194184588Sdfr plen = len % blocklen; 195184588Sdfr if (len == blocklen) { 196184588Sdfr /* 197184588Sdfr * Note: caller will ensure len >= blocklen. 198184588Sdfr */ 199184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 200184588Sdfr CRD_F_ENCRYPT); 201184588Sdfr } else if (plen == 0) { 202184588Sdfr /* 203184588Sdfr * This is equivalent to CBC mode followed by swapping 204184588Sdfr * the last two blocks. We assume that neither of the 205184588Sdfr * last two blocks cross iov boundaries. 206184588Sdfr */ 207184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 208184588Sdfr CRD_F_ENCRYPT); 209184588Sdfr off = skip + len - 2 * blocklen; 210184588Sdfr m_copydata(inout, off, 2 * blocklen, (void*) &last2); 211184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 212184588Sdfr m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 213184588Sdfr } else { 214184588Sdfr /* 215184588Sdfr * This is the difficult case. We encrypt all but the 216184588Sdfr * last partial block first. We then create a padded 217184588Sdfr * copy of the last block and encrypt that using the 218184588Sdfr * second to last encrypted block as IV. Once we have 219184588Sdfr * the encrypted versions of the last two blocks, we 220184588Sdfr * reshuffle to create the final result. 221184588Sdfr */ 222184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 223184588Sdfr ivec, CRD_F_ENCRYPT); 224184588Sdfr 225184588Sdfr /* 226184588Sdfr * Copy out the last two blocks, pad the last block 227184588Sdfr * and encrypt it. Rearrange to get the final 228184588Sdfr * result. The cyphertext for cn_1 is in cn. The 229184588Sdfr * cyphertext for cn is the first plen bytes of what 230184588Sdfr * is in cn_1 now. 231184588Sdfr */ 232184588Sdfr off = skip + len - blocklen - plen; 233184588Sdfr m_copydata(inout, off, blocklen + plen, (void*) &last2); 234184588Sdfr for (i = plen; i < blocklen; i++) 235184588Sdfr last2.cn[i] = 0; 236184588Sdfr aes_encrypt_1(ks, 0, last2.cn, 0, blocklen, last2.cn_1, 237184588Sdfr CRD_F_ENCRYPT); 238184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 239184588Sdfr m_copyback(inout, off + blocklen, plen, last2.cn_1); 240184588Sdfr } 241184588Sdfr} 242184588Sdfr 243184588Sdfrstatic void 244184588Sdfraes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout, 245184588Sdfr size_t skip, size_t len, void *ivec, size_t ivlen) 246184588Sdfr{ 247184588Sdfr size_t blocklen = 16, plen; 248184588Sdfr struct { 249184588Sdfr uint8_t cn_1[16], cn[16]; 250184588Sdfr } last2; 251184588Sdfr int i, off, t; 252184588Sdfr 253184588Sdfr /* 254184588Sdfr * AES decryption with cyphertext stealing: 255184588Sdfr * 256184588Sdfr * CTSencrypt(C[0], ..., C[n], IV, K): 257184588Sdfr * len = length(C[n]) 258184588Sdfr * E[n] = C[n-1] 259184588Sdfr * X = decrypt(E[n], K) 260184588Sdfr * P[n] = (X ^ C[n]){0..len-1} 261184588Sdfr * E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]} 262184588Sdfr * (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K) 263184588Sdfr */ 264184588Sdfr plen = len % blocklen; 265184588Sdfr if (len == blocklen) { 266184588Sdfr /* 267184588Sdfr * Note: caller will ensure len >= blocklen. 268184588Sdfr */ 269184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 270184588Sdfr } else if (plen == 0) { 271184588Sdfr /* 272184588Sdfr * This is equivalent to CBC mode followed by swapping 273184588Sdfr * the last two blocks. 274184588Sdfr */ 275184588Sdfr off = skip + len - 2 * blocklen; 276184588Sdfr m_copydata(inout, off, 2 * blocklen, (void*) &last2); 277184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 278184588Sdfr m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 279184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 280184588Sdfr } else { 281184588Sdfr /* 282184588Sdfr * This is the difficult case. We first decrypt the 283184588Sdfr * second to last block with a zero IV to make X. The 284184588Sdfr * plaintext for the last block is the XOR of X and 285184588Sdfr * the last cyphertext block. 286184588Sdfr * 287184588Sdfr * We derive a new cypher text for the second to last 288184588Sdfr * block by mixing the unused bytes of X with the last 289184588Sdfr * cyphertext block. The result of that can be 290184588Sdfr * decrypted with the rest in CBC mode. 291184588Sdfr */ 292184588Sdfr off = skip + len - plen - blocklen; 293184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, off, blocklen, 294184588Sdfr NULL, 0); 295184588Sdfr m_copydata(inout, off, blocklen + plen, (void*) &last2); 296184588Sdfr 297184588Sdfr for (i = 0; i < plen; i++) { 298184588Sdfr t = last2.cn[i]; 299184588Sdfr last2.cn[i] ^= last2.cn_1[i]; 300184588Sdfr last2.cn_1[i] = t; 301184588Sdfr } 302184588Sdfr 303184588Sdfr m_copyback(inout, off, blocklen + plen, (void*) &last2); 304184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 305184588Sdfr ivec, 0); 306184588Sdfr } 307184588Sdfr 308184588Sdfr} 309184588Sdfr 310184588Sdfrstatic void 311184588Sdfraes_checksum(const struct krb5_key_state *ks, int usage, 312184588Sdfr struct mbuf *inout, size_t skip, size_t inlen, size_t outlen) 313184588Sdfr{ 314184588Sdfr struct aes_state *as = ks->ks_priv; 315184588Sdfr struct cryptop *crp; 316184588Sdfr struct cryptodesc *crd; 317184588Sdfr int error; 318184588Sdfr 319184588Sdfr crp = crypto_getreq(1); 320184588Sdfr crd = crp->crp_desc; 321184588Sdfr 322184588Sdfr crd->crd_skip = skip; 323184588Sdfr crd->crd_len = inlen; 324184588Sdfr crd->crd_inject = skip + inlen; 325184588Sdfr crd->crd_flags = 0; 326184588Sdfr crd->crd_next = NULL; 327184588Sdfr crd->crd_alg = CRYPTO_SHA1_HMAC; 328184588Sdfr 329184588Sdfr crp->crp_sid = as->as_session; 330184588Sdfr crp->crp_ilen = inlen; 331184588Sdfr crp->crp_olen = 12; 332184588Sdfr crp->crp_etype = 0; 333184588Sdfr crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; 334184588Sdfr crp->crp_buf = (void *) inout; 335184588Sdfr crp->crp_opaque = (void *) as; 336184588Sdfr crp->crp_callback = aes_crypto_cb; 337184588Sdfr 338184588Sdfr error = crypto_dispatch(crp); 339184588Sdfr 340184588Sdfr if ((CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) == 0) { 341184588Sdfr mtx_lock(&as->as_lock); 342184588Sdfr if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 343184588Sdfr error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 344184588Sdfr mtx_unlock(&as->as_lock); 345184588Sdfr } 346184588Sdfr 347184588Sdfr crypto_freereq(crp); 348184588Sdfr} 349184588Sdfr 350184588Sdfrstruct krb5_encryption_class krb5_aes128_encryption_class = { 351184588Sdfr "aes128-cts-hmac-sha1-96", /* name */ 352184588Sdfr ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */ 353184588Sdfr EC_DERIVED_KEYS, /* flags */ 354184588Sdfr 16, /* blocklen */ 355184588Sdfr 1, /* msgblocklen */ 356184588Sdfr 12, /* checksumlen */ 357184588Sdfr 128, /* keybits */ 358184588Sdfr 16, /* keylen */ 359184588Sdfr aes_init, 360184588Sdfr aes_destroy, 361184588Sdfr aes_set_key, 362184588Sdfr aes_random_to_key, 363184588Sdfr aes_encrypt, 364184588Sdfr aes_decrypt, 365184588Sdfr aes_checksum 366184588Sdfr}; 367184588Sdfr 368184588Sdfrstruct krb5_encryption_class krb5_aes256_encryption_class = { 369184588Sdfr "aes256-cts-hmac-sha1-96", /* name */ 370184588Sdfr ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */ 371184588Sdfr EC_DERIVED_KEYS, /* flags */ 372184588Sdfr 16, /* blocklen */ 373184588Sdfr 1, /* msgblocklen */ 374184588Sdfr 12, /* checksumlen */ 375184588Sdfr 256, /* keybits */ 376184588Sdfr 32, /* keylen */ 377184588Sdfr aes_init, 378184588Sdfr aes_destroy, 379184588Sdfr aes_set_key, 380184588Sdfr aes_random_to_key, 381184588Sdfr aes_encrypt, 382184588Sdfr aes_decrypt, 383184588Sdfr aes_checksum 384184588Sdfr}; 385