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_aes; 47 uint64_t as_session_sha1; 48 }; 49 50 static void 51 aes_init(struct krb5_key_state *ks) 52 { 53 struct aes_state *as; 54 55 as = malloc(sizeof(struct aes_state), M_GSSAPI, M_WAITOK|M_ZERO); 56 mtx_init(&as->as_lock, "gss aes lock", NULL, MTX_DEF); 57 ks->ks_priv = as; 58 } 59 60 static void 61 aes_destroy(struct krb5_key_state *ks) 62 { 63 struct aes_state *as = ks->ks_priv; 64 65 if (as->as_session_aes != 0) 66 crypto_freesession(as->as_session_aes); 67 if (as->as_session_sha1 != 0) 68 crypto_freesession(as->as_session_sha1); 69 mtx_destroy(&as->as_lock); 70 free(ks->ks_priv, M_GSSAPI); 71 } 72 73 static void 74 aes_set_key(struct krb5_key_state *ks, const void *in) 75 { 76 void *kp = ks->ks_key; 77 struct aes_state *as = ks->ks_priv; 78 struct cryptoini cri; 79 80 if (kp != in) 81 bcopy(in, kp, ks->ks_class->ec_keylen); 82 83 if (as->as_session_aes != 0) 84 crypto_freesession(as->as_session_aes); 85 if (as->as_session_sha1 != 0) 86 crypto_freesession(as->as_session_sha1); 87 88 /* 89 * We only want the first 96 bits of the HMAC. 90 */ 91 bzero(&cri, sizeof(cri)); 92 cri.cri_alg = CRYPTO_SHA1_HMAC; 93 cri.cri_klen = ks->ks_class->ec_keybits; 94 cri.cri_mlen = 12; 95 cri.cri_key = ks->ks_key; 96 cri.cri_next = NULL; 97 crypto_newsession(&as->as_session_sha1, &cri, 98 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 99 100 bzero(&cri, sizeof(cri)); 101 cri.cri_alg = CRYPTO_AES_CBC; 102 cri.cri_klen = ks->ks_class->ec_keybits; 103 cri.cri_mlen = 0; 104 cri.cri_key = ks->ks_key; 105 cri.cri_next = NULL; 106 crypto_newsession(&as->as_session_aes, &cri, 107 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); 108 } 109 110 static void 111 aes_random_to_key(struct krb5_key_state *ks, const void *in) 112 { 113 114 aes_set_key(ks, in); 115 } 116 117 static int 118 aes_crypto_cb(struct cryptop *crp) 119 { 120 int error; 121 struct aes_state *as = (struct aes_state *) crp->crp_opaque; 122 123 if (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC) 124 return (0); 125 126 error = crp->crp_etype; 127 if (error == EAGAIN) 128 error = crypto_dispatch(crp); 129 mtx_lock(&as->as_lock); 130 if (error || (crp->crp_flags & CRYPTO_F_DONE)) 131 wakeup(crp); 132 mtx_unlock(&as->as_lock); 133 134 return (0); 135 } 136 137 static void 138 aes_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf, 139 size_t skip, size_t len, void *ivec, int encdec) 140 { 141 struct aes_state *as = ks->ks_priv; 142 struct cryptop *crp; 143 struct cryptodesc *crd; 144 int error; 145 146 crp = crypto_getreq(1); 147 crd = crp->crp_desc; 148 149 crd->crd_skip = skip; 150 crd->crd_len = len; 151 crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | encdec; 152 if (ivec) { 153 bcopy(ivec, crd->crd_iv, 16); 154 } else { 155 bzero(crd->crd_iv, 16); 156 } 157 crd->crd_next = NULL; 158 crd->crd_alg = CRYPTO_AES_CBC; 159 160 crp->crp_sid = as->as_session_aes; 161 crp->crp_flags = buftype | CRYPTO_F_CBIFSYNC; 162 crp->crp_buf = buf; 163 crp->crp_opaque = (void *) as; 164 crp->crp_callback = aes_crypto_cb; 165 166 error = crypto_dispatch(crp); 167 168 if ((CRYPTO_SESID2CAPS(as->as_session_aes) & CRYPTOCAP_F_SYNC) == 0) { 169 mtx_lock(&as->as_lock); 170 if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 171 error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 172 mtx_unlock(&as->as_lock); 173 } 174 175 crypto_freereq(crp); 176 } 177 178 static void 179 aes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout, 180 size_t skip, size_t len, void *ivec, size_t ivlen) 181 { 182 size_t blocklen = 16, plen; 183 struct { 184 uint8_t cn_1[16], cn[16]; 185 } last2; 186 int i, off; 187 188 /* 189 * AES encryption with cyphertext stealing: 190 * 191 * CTSencrypt(P[0], ..., P[n], IV, K): 192 * len = length(P[n]) 193 * (C[0], ..., C[n-2], E[n-1]) = 194 * CBCencrypt(P[0], ..., P[n-1], IV, K) 195 * P = pad(P[n], 0, blocksize) 196 * E[n] = CBCencrypt(P, E[n-1], K); 197 * C[n-1] = E[n] 198 * C[n] = E[n-1]{0..len-1} 199 */ 200 plen = len % blocklen; 201 if (len == blocklen) { 202 /* 203 * Note: caller will ensure len >= blocklen. 204 */ 205 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 206 CRD_F_ENCRYPT); 207 } else if (plen == 0) { 208 /* 209 * This is equivalent to CBC mode followed by swapping 210 * the last two blocks. We assume that neither of the 211 * last two blocks cross iov boundaries. 212 */ 213 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 214 CRD_F_ENCRYPT); 215 off = skip + len - 2 * blocklen; 216 m_copydata(inout, off, 2 * blocklen, (void*) &last2); 217 m_copyback(inout, off, blocklen, last2.cn); 218 m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 219 } else { 220 /* 221 * This is the difficult case. We encrypt all but the 222 * last partial block first. We then create a padded 223 * copy of the last block and encrypt that using the 224 * second to last encrypted block as IV. Once we have 225 * the encrypted versions of the last two blocks, we 226 * reshuffle to create the final result. 227 */ 228 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 229 ivec, CRD_F_ENCRYPT); 230 231 /* 232 * Copy out the last two blocks, pad the last block 233 * and encrypt it. Rearrange to get the final 234 * result. The cyphertext for cn_1 is in cn. The 235 * cyphertext for cn is the first plen bytes of what 236 * is in cn_1 now. 237 */ 238 off = skip + len - blocklen - plen; 239 m_copydata(inout, off, blocklen + plen, (void*) &last2); 240 for (i = plen; i < blocklen; i++) 241 last2.cn[i] = 0; 242 aes_encrypt_1(ks, 0, last2.cn, 0, blocklen, last2.cn_1, 243 CRD_F_ENCRYPT); 244 m_copyback(inout, off, blocklen, last2.cn); 245 m_copyback(inout, off + blocklen, plen, last2.cn_1); 246 } 247 } 248 249 static void 250 aes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout, 251 size_t skip, size_t len, void *ivec, size_t ivlen) 252 { 253 size_t blocklen = 16, plen; 254 struct { 255 uint8_t cn_1[16], cn[16]; 256 } last2; 257 int i, off, t; 258 259 /* 260 * AES decryption with cyphertext stealing: 261 * 262 * CTSencrypt(C[0], ..., C[n], IV, K): 263 * len = length(C[n]) 264 * E[n] = C[n-1] 265 * X = decrypt(E[n], K) 266 * P[n] = (X ^ C[n]){0..len-1} 267 * E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]} 268 * (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K) 269 */ 270 plen = len % blocklen; 271 if (len == blocklen) { 272 /* 273 * Note: caller will ensure len >= blocklen. 274 */ 275 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 276 } else if (plen == 0) { 277 /* 278 * This is equivalent to CBC mode followed by swapping 279 * the last two blocks. 280 */ 281 off = skip + len - 2 * blocklen; 282 m_copydata(inout, off, 2 * blocklen, (void*) &last2); 283 m_copyback(inout, off, blocklen, last2.cn); 284 m_copyback(inout, off + blocklen, blocklen, last2.cn_1); 285 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0); 286 } else { 287 /* 288 * This is the difficult case. We first decrypt the 289 * second to last block with a zero IV to make X. The 290 * plaintext for the last block is the XOR of X and 291 * the last cyphertext block. 292 * 293 * We derive a new cypher text for the second to last 294 * block by mixing the unused bytes of X with the last 295 * cyphertext block. The result of that can be 296 * decrypted with the rest in CBC mode. 297 */ 298 off = skip + len - plen - blocklen; 299 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, off, blocklen, 300 NULL, 0); 301 m_copydata(inout, off, blocklen + plen, (void*) &last2); 302 303 for (i = 0; i < plen; i++) { 304 t = last2.cn[i]; 305 last2.cn[i] ^= last2.cn_1[i]; 306 last2.cn_1[i] = t; 307 } 308 309 m_copyback(inout, off, blocklen + plen, (void*) &last2); 310 aes_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len - plen, 311 ivec, 0); 312 } 313 314 } 315 316 static void 317 aes_checksum(const struct krb5_key_state *ks, int usage, 318 struct mbuf *inout, size_t skip, size_t inlen, size_t outlen) 319 { 320 struct aes_state *as = ks->ks_priv; 321 struct cryptop *crp; 322 struct cryptodesc *crd; 323 int error; 324 325 crp = crypto_getreq(1); 326 crd = crp->crp_desc; 327 328 crd->crd_skip = skip; 329 crd->crd_len = inlen; 330 crd->crd_inject = skip + inlen; 331 crd->crd_flags = 0; 332 crd->crd_next = NULL; 333 crd->crd_alg = CRYPTO_SHA1_HMAC; 334 335 crp->crp_sid = as->as_session_sha1; 336 crp->crp_ilen = inlen; 337 crp->crp_olen = 12; 338 crp->crp_etype = 0; 339 crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC; 340 crp->crp_buf = (void *) inout; 341 crp->crp_opaque = (void *) as; 342 crp->crp_callback = aes_crypto_cb; 343 344 error = crypto_dispatch(crp); 345 346 if ((CRYPTO_SESID2CAPS(as->as_session_sha1) & CRYPTOCAP_F_SYNC) == 0) { 347 mtx_lock(&as->as_lock); 348 if (!error && !(crp->crp_flags & CRYPTO_F_DONE)) 349 error = msleep(crp, &as->as_lock, 0, "gssaes", 0); 350 mtx_unlock(&as->as_lock); 351 } 352 353 crypto_freereq(crp); 354 } 355 356 struct krb5_encryption_class krb5_aes128_encryption_class = { 357 "aes128-cts-hmac-sha1-96", /* name */ 358 ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */ 359 EC_DERIVED_KEYS, /* flags */ 360 16, /* blocklen */ 361 1, /* msgblocklen */ 362 12, /* checksumlen */ 363 128, /* keybits */ 364 16, /* keylen */ 365 aes_init, 366 aes_destroy, 367 aes_set_key, 368 aes_random_to_key, 369 aes_encrypt, 370 aes_decrypt, 371 aes_checksum 372 }; 373 374 struct krb5_encryption_class krb5_aes256_encryption_class = { 375 "aes256-cts-hmac-sha1-96", /* name */ 376 ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */ 377 EC_DERIVED_KEYS, /* flags */ 378 16, /* blocklen */ 379 1, /* msgblocklen */ 380 12, /* checksumlen */ 381 256, /* keybits */ 382 32, /* keylen */ 383 aes_init, 384 aes_destroy, 385 aes_set_key, 386 aes_random_to_key, 387 aes_encrypt, 388 aes_decrypt, 389 aes_checksum 390 }; 391