1 /*- 2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3 * Authors: Doug Rabson <dfr@rabson.org> 4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/lock.h> 33 #include <sys/malloc.h> 34 #include <sys/mutex.h> 35 #include <sys/kobj.h> 36 #include <sys/mbuf.h> 37 #include <opencrypto/cryptodev.h> 38 39 #include <kgssapi/gssapi.h> 40 #include <kgssapi/gssapi_impl.h> 41 42 #include "kcrypto.h" 43 44 struct aes_state { 45 struct mtx as_lock; 46 uint64_t as_session; 47 }; 48 49 static void 50 aes_init(struct krb5_key_state *ks) 51 { 52 struct aes_state *as; 53 54 as = malloc(sizeof(struct aes_state), M_GSSAPI, M_WAITOK|M_ZERO); 55 mtx_init(&as->as_lock, "gss aes lock", NULL, MTX_DEF); 56 ks->ks_priv = as; 57 } 58 59 static void 60 aes_destroy(struct krb5_key_state *ks) 61 { 62 struct aes_state *as = ks->ks_priv; 63 64 if (as->as_session) 65 crypto_freesession(as->as_session); 66 mtx_destroy(&as->as_lock); 67 free(ks->ks_priv, M_GSSAPI); 68 } 69 70 static void 71 aes_set_key(struct krb5_key_state *ks, const void *in) 72 { 73 void *kp = ks->ks_key; 74 struct aes_state *as = ks->ks_priv; 75 struct cryptoini cri[2]; 76 77 if (kp != in) 78 bcopy(in, kp, ks->ks_class->ec_keylen); 79 80 if (as->as_session) 81 crypto_freesession(as->as_session); 82 83 bzero(cri, sizeof(cri)); 84 85 /* 86 * We only want the first 96 bits of the HMAC. 87 */ 88 cri[0].cri_alg = CRYPTO_SHA1_HMAC; 89 cri[0].cri_klen = ks->ks_class->ec_keybits; 90 cri[0].cri_mlen = 12; 91 cri[0].cri_key = ks->ks_key; 92 cri[0].cri_next = &cri[1]; 93 94 cri[1].cri_alg = CRYPTO_AES_CBC; 95 cri[1].cri_klen = ks->ks_class->ec_keybits; 96 cri[1].cri_mlen = 0; 97 cri[1].cri_key = ks->ks_key; 98 cri[1].cri_next = NULL; 99 100 crypto_newsession(&as->as_session, cri, 101 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 102 } 103 104 static void 105 aes_random_to_key(struct krb5_key_state *ks, const void *in) 106 { 107 108 aes_set_key(ks, in); 109 } 110 111 static int 112 aes_crypto_cb(struct cryptop *crp) 113 { 114 int error; 115 struct aes_state *as = (struct aes_state *) crp->crp_opaque; 116 117 if (CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) 118 return (0); 119 120 error = crp->crp_etype; 121 if (error == EAGAIN) 122 error = crypto_dispatch(crp); 123 mtx_lock(&as->as_lock); 124 if (error || (crp->crp_flags & CRYPTO_F_DONE)) 125 wakeup(crp); 126 mtx_unlock(&as->as_lock); 127 128 return (0); 129 } 130 131 static void 132 aes_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf, 133 size_t skip, size_t len, void *ivec, int encdec) 134 { 135 struct aes_state *as = ks->ks_priv; 136 struct cryptop *crp; 137 struct cryptodesc *crd; 138 int error; 139 140 crp = crypto_getreq(1); 141 crd = crp->crp_desc; 142 143 crd->crd_skip = skip; 144 crd->crd_len = len; 145 crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | encdec; 146 if (ivec) { 147 bcopy(ivec, crd->crd_iv, 16); 148 } else { 149 bzero(crd->crd_iv, 16); 150 } 151 crd->crd_next = NULL; 152 crd->crd_alg = CRYPTO_AES_CBC; 153 154 crp->crp_sid = as->as_session; 155 crp->crp_flags = buftype | CRYPTO_F_CBIFSYNC; 156 crp->crp_buf = buf; 157 crp->crp_opaque = (void *) as; 158 crp->crp_callback = aes_crypto_cb; 159 160 error = crypto_dispatch(crp); 161 162 if ((CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) == 0) { 163 mtx_lock(&as->as_lock); 164 if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 165 error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 166 mtx_unlock(&as->as_lock); 167 } 168 169 crypto_freereq(crp); 170 } 171 172 static void 173 aes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout, 174 size_t skip, size_t len, void *ivec, size_t ivlen) 175 { 176 size_t blocklen = 16, plen; 177 struct { 178 uint8_t cn_1[16], cn[16]; 179 } last2; 180 int i, off; 181 182 /* 183 * AES encryption with cyphertext stealing: 184 * 185 * CTSencrypt(P[0], ..., P[n], IV, K): 186 * len = length(P[n]) 187 * (C[0], ..., C[n-2], E[n-1]) = 188 * CBCencrypt(P[0], ..., P[n-1], IV, K) 189 * P = pad(P[n], 0, blocksize) 190 * E[n] = CBCencrypt(P, E[n-1], K); 191 * C[n-1] = E[n] 192 * C[n] = E[n-1]{0..len-1} 193 */ 194 plen = len % blocklen; 195 if (len == blocklen) { 196 /* 197 * Note: caller will ensure len >= blocklen. 198 */ 199 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 200 CRD_F_ENCRYPT); 201 } else if (plen == 0) { 202 /* 203 * This is equivalent to CBC mode followed by swapping 204 * the last two blocks. We assume that neither of the 205 * last two blocks cross iov boundaries. 206 */ 207 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 208 CRD_F_ENCRYPT); 209 off = skip + len - 2 * blocklen; 210 m_copydata(inout, off, 2 * blocklen, (void*) &last2); 211 m_copyback(inout, off, blocklen, last2.cn); 212 m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 213 } else { 214 /* 215 * This is the difficult case. We encrypt all but the 216 * last partial block first. We then create a padded 217 * copy of the last block and encrypt that using the 218 * second to last encrypted block as IV. Once we have 219 * the encrypted versions of the last two blocks, we 220 * reshuffle to create the final result. 221 */ 222 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 223 ivec, CRD_F_ENCRYPT); 224 225 /* 226 * Copy out the last two blocks, pad the last block 227 * and encrypt it. Rearrange to get the final 228 * result. The cyphertext for cn_1 is in cn. The 229 * cyphertext for cn is the first plen bytes of what 230 * is in cn_1 now. 231 */ 232 off = skip + len - blocklen - plen; 233 m_copydata(inout, off, blocklen + plen, (void*) &last2); 234 for (i = plen; i < blocklen; i++) 235 last2.cn[i] = 0; 236 aes_encrypt_1(ks, 0, last2.cn, 0, blocklen, last2.cn_1, 237 CRD_F_ENCRYPT); 238 m_copyback(inout, off, blocklen, last2.cn); 239 m_copyback(inout, off + blocklen, plen, last2.cn_1); 240 } 241 } 242 243 static void 244 aes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout, 245 size_t skip, size_t len, void *ivec, size_t ivlen) 246 { 247 size_t blocklen = 16, plen; 248 struct { 249 uint8_t cn_1[16], cn[16]; 250 } last2; 251 int i, off, t; 252 253 /* 254 * AES decryption with cyphertext stealing: 255 * 256 * CTSencrypt(C[0], ..., C[n], IV, K): 257 * len = length(C[n]) 258 * E[n] = C[n-1] 259 * X = decrypt(E[n], K) 260 * P[n] = (X ^ C[n]){0..len-1} 261 * E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]} 262 * (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K) 263 */ 264 plen = len % blocklen; 265 if (len == blocklen) { 266 /* 267 * Note: caller will ensure len >= blocklen. 268 */ 269 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 270 } else if (plen == 0) { 271 /* 272 * This is equivalent to CBC mode followed by swapping 273 * the last two blocks. 274 */ 275 off = skip + len - 2 * blocklen; 276 m_copydata(inout, off, 2 * blocklen, (void*) &last2); 277 m_copyback(inout, off, blocklen, last2.cn); 278 m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 279 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 280 } else { 281 /* 282 * This is the difficult case. We first decrypt the 283 * second to last block with a zero IV to make X. The 284 * plaintext for the last block is the XOR of X and 285 * the last cyphertext block. 286 * 287 * We derive a new cypher text for the second to last 288 * block by mixing the unused bytes of X with the last 289 * cyphertext block. The result of that can be 290 * decrypted with the rest in CBC mode. 291 */ 292 off = skip + len - plen - blocklen; 293 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, off, blocklen, 294 NULL, 0); 295 m_copydata(inout, off, blocklen + plen, (void*) &last2); 296 297 for (i = 0; i < plen; i++) { 298 t = last2.cn[i]; 299 last2.cn[i] ^= last2.cn_1[i]; 300 last2.cn_1[i] = t; 301 } 302 303 m_copyback(inout, off, blocklen + plen, (void*) &last2); 304 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 305 ivec, 0); 306 } 307 308 } 309 310 static void 311 aes_checksum(const struct krb5_key_state *ks, int usage, 312 struct mbuf *inout, size_t skip, size_t inlen, size_t outlen) 313 { 314 struct aes_state *as = ks->ks_priv; 315 struct cryptop *crp; 316 struct cryptodesc *crd; 317 int error; 318 319 crp = crypto_getreq(1); 320 crd = crp->crp_desc; 321 322 crd->crd_skip = skip; 323 crd->crd_len = inlen; 324 crd->crd_inject = skip + inlen; 325 crd->crd_flags = 0; 326 crd->crd_next = NULL; 327 crd->crd_alg = CRYPTO_SHA1_HMAC; 328 329 crp->crp_sid = as->as_session; 330 crp->crp_ilen = inlen; 331 crp->crp_olen = 12; 332 crp->crp_etype = 0; 333 crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; 334 crp->crp_buf = (void *) inout; 335 crp->crp_opaque = (void *) as; 336 crp->crp_callback = aes_crypto_cb; 337 338 error = crypto_dispatch(crp); 339 340 if ((CRYPTO_SESID2CAPS(as->as_session) & CRYPTOCAP_F_SYNC) == 0) { 341 mtx_lock(&as->as_lock); 342 if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 343 error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 344 mtx_unlock(&as->as_lock); 345 } 346 347 crypto_freereq(crp); 348 } 349 350 struct krb5_encryption_class krb5_aes128_encryption_class = { 351 "aes128-cts-hmac-sha1-96", /* name */ 352 ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */ 353 EC_DERIVED_KEYS, /* flags */ 354 16, /* blocklen */ 355 1, /* msgblocklen */ 356 12, /* checksumlen */ 357 128, /* keybits */ 358 16, /* keylen */ 359 aes_init, 360 aes_destroy, 361 aes_set_key, 362 aes_random_to_key, 363 aes_encrypt, 364 aes_decrypt, 365 aes_checksum 366 }; 367 368 struct krb5_encryption_class krb5_aes256_encryption_class = { 369 "aes256-cts-hmac-sha1-96", /* name */ 370 ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */ 371 EC_DERIVED_KEYS, /* flags */ 372 16, /* blocklen */ 373 1, /* msgblocklen */ 374 12, /* checksumlen */ 375 256, /* keybits */ 376 32, /* keylen */ 377 aes_init, 378 aes_destroy, 379 aes_set_key, 380 aes_random_to_key, 381 aes_encrypt, 382 aes_decrypt, 383 aes_checksum 384 }; 385