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; 46299617Sngie uint64_t as_session_aes; 47299617Sngie uint64_t as_session_sha1; 48184588Sdfr}; 49184588Sdfr 50184588Sdfrstatic void 51184588Sdfraes_init(struct krb5_key_state *ks) 52184588Sdfr{ 53184588Sdfr struct aes_state *as; 54184588Sdfr 55184588Sdfr as = malloc(sizeof(struct aes_state), M_GSSAPI, M_WAITOK|M_ZERO); 56184588Sdfr mtx_init(&as->as_lock, "gss aes lock", NULL, MTX_DEF); 57184588Sdfr ks->ks_priv = as; 58184588Sdfr} 59184588Sdfr 60184588Sdfrstatic void 61184588Sdfraes_destroy(struct krb5_key_state *ks) 62184588Sdfr{ 63184588Sdfr struct aes_state *as = ks->ks_priv; 64184588Sdfr 65299617Sngie if (as->as_session_aes != 0) 66299617Sngie crypto_freesession(as->as_session_aes); 67299617Sngie if (as->as_session_sha1 != 0) 68299617Sngie crypto_freesession(as->as_session_sha1); 69184588Sdfr mtx_destroy(&as->as_lock); 70184588Sdfr free(ks->ks_priv, M_GSSAPI); 71184588Sdfr} 72184588Sdfr 73184588Sdfrstatic void 74184588Sdfraes_set_key(struct krb5_key_state *ks, const void *in) 75184588Sdfr{ 76184588Sdfr void *kp = ks->ks_key; 77184588Sdfr struct aes_state *as = ks->ks_priv; 78299617Sngie struct cryptoini cri; 79184588Sdfr 80184588Sdfr if (kp != in) 81184588Sdfr bcopy(in, kp, ks->ks_class->ec_keylen); 82184588Sdfr 83299617Sngie if (as->as_session_aes != 0) 84299617Sngie crypto_freesession(as->as_session_aes); 85299617Sngie if (as->as_session_sha1 != 0) 86299617Sngie crypto_freesession(as->as_session_sha1); 87184588Sdfr 88184588Sdfr /* 89184588Sdfr * We only want the first 96 bits of the HMAC. 90184588Sdfr */ 91299617Sngie bzero(&cri, sizeof(cri)); 92299617Sngie cri.cri_alg = CRYPTO_SHA1_HMAC; 93299617Sngie cri.cri_klen = ks->ks_class->ec_keybits; 94299617Sngie cri.cri_mlen = 12; 95299617Sngie cri.cri_key = ks->ks_key; 96299617Sngie cri.cri_next = NULL; 97299617Sngie crypto_newsession(&as->as_session_sha1, &cri, 98299617Sngie CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 99184588Sdfr 100299617Sngie bzero(&cri, sizeof(cri)); 101299617Sngie cri.cri_alg = CRYPTO_AES_CBC; 102299617Sngie cri.cri_klen = ks->ks_class->ec_keybits; 103299617Sngie cri.cri_mlen = 0; 104299617Sngie cri.cri_key = ks->ks_key; 105299617Sngie cri.cri_next = NULL; 106299617Sngie crypto_newsession(&as->as_session_aes, &cri, 107184588Sdfr CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 108184588Sdfr} 109184588Sdfr 110184588Sdfrstatic void 111184588Sdfraes_random_to_key(struct krb5_key_state *ks, const void *in) 112184588Sdfr{ 113184588Sdfr 114184588Sdfr aes_set_key(ks, in); 115184588Sdfr} 116184588Sdfr 117184588Sdfrstatic int 118184588Sdfraes_crypto_cb(struct cryptop *crp) 119184588Sdfr{ 120184588Sdfr int error; 121184588Sdfr struct aes_state *as = (struct aes_state *) crp->crp_opaque; 122184588Sdfr 123299617Sngie if (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC) 124184588Sdfr return (0); 125184588Sdfr 126184588Sdfr error = crp->crp_etype; 127184588Sdfr if (error == EAGAIN) 128184588Sdfr error = crypto_dispatch(crp); 129184588Sdfr mtx_lock(&as->as_lock); 130184588Sdfr if (error || (crp->crp_flags & CRYPTO_F_DONE)) 131184588Sdfr wakeup(crp); 132184588Sdfr mtx_unlock(&as->as_lock); 133184588Sdfr 134184588Sdfr return (0); 135184588Sdfr} 136184588Sdfr 137184588Sdfrstatic void 138184588Sdfraes_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf, 139184588Sdfr size_t skip, size_t len, void *ivec, int encdec) 140184588Sdfr{ 141184588Sdfr struct aes_state *as = ks->ks_priv; 142184588Sdfr struct cryptop *crp; 143184588Sdfr struct cryptodesc *crd; 144184588Sdfr int error; 145184588Sdfr 146184588Sdfr crp = crypto_getreq(1); 147184588Sdfr crd = crp->crp_desc; 148184588Sdfr 149184588Sdfr crd->crd_skip = skip; 150184588Sdfr crd->crd_len = len; 151184588Sdfr crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | encdec; 152184588Sdfr if (ivec) { 153184588Sdfr bcopy(ivec, crd->crd_iv, 16); 154184588Sdfr } else { 155184588Sdfr bzero(crd->crd_iv, 16); 156184588Sdfr } 157184588Sdfr crd->crd_next = NULL; 158184588Sdfr crd->crd_alg = CRYPTO_AES_CBC; 159184588Sdfr 160299617Sngie crp->crp_sid = as->as_session_aes; 161184588Sdfr crp->crp_flags = buftype | CRYPTO_F_CBIFSYNC; 162184588Sdfr crp->crp_buf = buf; 163184588Sdfr crp->crp_opaque = (void *) as; 164184588Sdfr crp->crp_callback = aes_crypto_cb; 165184588Sdfr 166184588Sdfr error = crypto_dispatch(crp); 167184588Sdfr 168299617Sngie if ((CRYPTO_SESID2CAPS(as->as_session_aes) & CRYPTOCAP_F_SYNC) == 0) { 169184588Sdfr mtx_lock(&as->as_lock); 170184588Sdfr if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 171184588Sdfr error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 172184588Sdfr mtx_unlock(&as->as_lock); 173184588Sdfr } 174184588Sdfr 175184588Sdfr crypto_freereq(crp); 176184588Sdfr} 177184588Sdfr 178184588Sdfrstatic void 179184588Sdfraes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout, 180184588Sdfr size_t skip, size_t len, void *ivec, size_t ivlen) 181184588Sdfr{ 182184588Sdfr size_t blocklen = 16, plen; 183184588Sdfr struct { 184184588Sdfr uint8_t cn_1[16], cn[16]; 185184588Sdfr } last2; 186184588Sdfr int i, off; 187184588Sdfr 188184588Sdfr /* 189184588Sdfr * AES encryption with cyphertext stealing: 190184588Sdfr * 191184588Sdfr * CTSencrypt(P[0], ..., P[n], IV, K): 192184588Sdfr * len = length(P[n]) 193184588Sdfr * (C[0], ..., C[n-2], E[n-1]) = 194184588Sdfr * CBCencrypt(P[0], ..., P[n-1], IV, K) 195184588Sdfr * P = pad(P[n], 0, blocksize) 196184588Sdfr * E[n] = CBCencrypt(P, E[n-1], K); 197184588Sdfr * C[n-1] = E[n] 198184588Sdfr * C[n] = E[n-1]{0..len-1} 199184588Sdfr */ 200184588Sdfr plen = len % blocklen; 201184588Sdfr if (len == blocklen) { 202184588Sdfr /* 203184588Sdfr * Note: caller will ensure len >= blocklen. 204184588Sdfr */ 205184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 206184588Sdfr CRD_F_ENCRYPT); 207184588Sdfr } else if (plen == 0) { 208184588Sdfr /* 209184588Sdfr * This is equivalent to CBC mode followed by swapping 210184588Sdfr * the last two blocks. We assume that neither of the 211184588Sdfr * last two blocks cross iov boundaries. 212184588Sdfr */ 213184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 214184588Sdfr CRD_F_ENCRYPT); 215184588Sdfr off = skip + len - 2 * blocklen; 216184588Sdfr m_copydata(inout, off, 2 * blocklen, (void*) &last2); 217184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 218184588Sdfr m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 219184588Sdfr } else { 220184588Sdfr /* 221184588Sdfr * This is the difficult case. We encrypt all but the 222184588Sdfr * last partial block first. We then create a padded 223184588Sdfr * copy of the last block and encrypt that using the 224184588Sdfr * second to last encrypted block as IV. Once we have 225184588Sdfr * the encrypted versions of the last two blocks, we 226184588Sdfr * reshuffle to create the final result. 227184588Sdfr */ 228184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 229184588Sdfr ivec, CRD_F_ENCRYPT); 230184588Sdfr 231184588Sdfr /* 232184588Sdfr * Copy out the last two blocks, pad the last block 233184588Sdfr * and encrypt it. Rearrange to get the final 234184588Sdfr * result. The cyphertext for cn_1 is in cn. The 235184588Sdfr * cyphertext for cn is the first plen bytes of what 236184588Sdfr * is in cn_1 now. 237184588Sdfr */ 238184588Sdfr off = skip + len - blocklen - plen; 239184588Sdfr m_copydata(inout, off, blocklen + plen, (void*) &last2); 240184588Sdfr for (i = plen; i < blocklen; i++) 241184588Sdfr last2.cn[i] = 0; 242184588Sdfr aes_encrypt_1(ks, 0, last2.cn, 0, blocklen, last2.cn_1, 243184588Sdfr CRD_F_ENCRYPT); 244184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 245184588Sdfr m_copyback(inout, off + blocklen, plen, last2.cn_1); 246184588Sdfr } 247184588Sdfr} 248184588Sdfr 249184588Sdfrstatic void 250184588Sdfraes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout, 251184588Sdfr size_t skip, size_t len, void *ivec, size_t ivlen) 252184588Sdfr{ 253184588Sdfr size_t blocklen = 16, plen; 254184588Sdfr struct { 255184588Sdfr uint8_t cn_1[16], cn[16]; 256184588Sdfr } last2; 257184588Sdfr int i, off, t; 258184588Sdfr 259184588Sdfr /* 260184588Sdfr * AES decryption with cyphertext stealing: 261184588Sdfr * 262184588Sdfr * CTSencrypt(C[0], ..., C[n], IV, K): 263184588Sdfr * len = length(C[n]) 264184588Sdfr * E[n] = C[n-1] 265184588Sdfr * X = decrypt(E[n], K) 266184588Sdfr * P[n] = (X ^ C[n]){0..len-1} 267184588Sdfr * E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]} 268184588Sdfr * (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K) 269184588Sdfr */ 270184588Sdfr plen = len % blocklen; 271184588Sdfr if (len == blocklen) { 272184588Sdfr /* 273184588Sdfr * Note: caller will ensure len >= blocklen. 274184588Sdfr */ 275184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 276184588Sdfr } else if (plen == 0) { 277184588Sdfr /* 278184588Sdfr * This is equivalent to CBC mode followed by swapping 279184588Sdfr * the last two blocks. 280184588Sdfr */ 281184588Sdfr off = skip + len - 2 * blocklen; 282184588Sdfr m_copydata(inout, off, 2 * blocklen, (void*) &last2); 283184588Sdfr m_copyback(inout, off, blocklen, last2.cn); 284184588Sdfr m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 285184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 286184588Sdfr } else { 287184588Sdfr /* 288184588Sdfr * This is the difficult case. We first decrypt the 289184588Sdfr * second to last block with a zero IV to make X. The 290184588Sdfr * plaintext for the last block is the XOR of X and 291184588Sdfr * the last cyphertext block. 292184588Sdfr * 293184588Sdfr * We derive a new cypher text for the second to last 294184588Sdfr * block by mixing the unused bytes of X with the last 295184588Sdfr * cyphertext block. The result of that can be 296184588Sdfr * decrypted with the rest in CBC mode. 297184588Sdfr */ 298184588Sdfr off = skip + len - plen - blocklen; 299184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, off, blocklen, 300184588Sdfr NULL, 0); 301184588Sdfr m_copydata(inout, off, blocklen + plen, (void*) &last2); 302184588Sdfr 303184588Sdfr for (i = 0; i < plen; i++) { 304184588Sdfr t = last2.cn[i]; 305184588Sdfr last2.cn[i] ^= last2.cn_1[i]; 306184588Sdfr last2.cn_1[i] = t; 307184588Sdfr } 308184588Sdfr 309184588Sdfr m_copyback(inout, off, blocklen + plen, (void*) &last2); 310184588Sdfr aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 311184588Sdfr ivec, 0); 312184588Sdfr } 313184588Sdfr 314184588Sdfr} 315184588Sdfr 316184588Sdfrstatic void 317184588Sdfraes_checksum(const struct krb5_key_state *ks, int usage, 318184588Sdfr struct mbuf *inout, size_t skip, size_t inlen, size_t outlen) 319184588Sdfr{ 320184588Sdfr struct aes_state *as = ks->ks_priv; 321184588Sdfr struct cryptop *crp; 322184588Sdfr struct cryptodesc *crd; 323184588Sdfr int error; 324184588Sdfr 325184588Sdfr crp = crypto_getreq(1); 326184588Sdfr crd = crp->crp_desc; 327184588Sdfr 328184588Sdfr crd->crd_skip = skip; 329184588Sdfr crd->crd_len = inlen; 330184588Sdfr crd->crd_inject = skip + inlen; 331184588Sdfr crd->crd_flags = 0; 332184588Sdfr crd->crd_next = NULL; 333184588Sdfr crd->crd_alg = CRYPTO_SHA1_HMAC; 334184588Sdfr 335299617Sngie crp->crp_sid = as->as_session_sha1; 336184588Sdfr crp->crp_ilen = inlen; 337184588Sdfr crp->crp_olen = 12; 338184588Sdfr crp->crp_etype = 0; 339184588Sdfr crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; 340184588Sdfr crp->crp_buf = (void *) inout; 341184588Sdfr crp->crp_opaque = (void *) as; 342184588Sdfr crp->crp_callback = aes_crypto_cb; 343184588Sdfr 344184588Sdfr error = crypto_dispatch(crp); 345184588Sdfr 346299617Sngie if ((CRYPTO_SESID2CAPS(as->as_session_sha1) & CRYPTOCAP_F_SYNC) == 0) { 347184588Sdfr mtx_lock(&as->as_lock); 348184588Sdfr if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 349184588Sdfr error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 350184588Sdfr mtx_unlock(&as->as_lock); 351184588Sdfr } 352184588Sdfr 353184588Sdfr crypto_freereq(crp); 354184588Sdfr} 355184588Sdfr 356184588Sdfrstruct krb5_encryption_class krb5_aes128_encryption_class = { 357184588Sdfr "aes128-cts-hmac-sha1-96", /* name */ 358184588Sdfr ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */ 359184588Sdfr EC_DERIVED_KEYS, /* flags */ 360184588Sdfr 16, /* blocklen */ 361184588Sdfr 1, /* msgblocklen */ 362184588Sdfr 12, /* checksumlen */ 363184588Sdfr 128, /* keybits */ 364184588Sdfr 16, /* keylen */ 365184588Sdfr aes_init, 366184588Sdfr aes_destroy, 367184588Sdfr aes_set_key, 368184588Sdfr aes_random_to_key, 369184588Sdfr aes_encrypt, 370184588Sdfr aes_decrypt, 371184588Sdfr aes_checksum 372184588Sdfr}; 373184588Sdfr 374184588Sdfrstruct krb5_encryption_class krb5_aes256_encryption_class = { 375184588Sdfr "aes256-cts-hmac-sha1-96", /* name */ 376184588Sdfr ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */ 377184588Sdfr EC_DERIVED_KEYS, /* flags */ 378184588Sdfr 16, /* blocklen */ 379184588Sdfr 1, /* msgblocklen */ 380184588Sdfr 12, /* checksumlen */ 381184588Sdfr 256, /* keybits */ 382184588Sdfr 32, /* keylen */ 383184588Sdfr aes_init, 384184588Sdfr aes_destroy, 385184588Sdfr aes_set_key, 386184588Sdfr aes_random_to_key, 387184588Sdfr aes_encrypt, 388184588Sdfr aes_decrypt, 389184588Sdfr aes_checksum 390184588Sdfr}; 391