1/* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 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 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "krb5_locl.h" 35 36/* 37 * AES 38 */ 39 40#ifdef __APPLE_TARGET_EMBEDDED__ 41 42#include <CommonCrypto/CommonCryptor.h> 43#include <CommonCrypto/CommonCryptorSPI.h> 44 45/* 46 * CommonCrypto based 47 */ 48 49struct cc_schedule { 50 CCCryptorRef enc; 51 CCCryptorRef dec; 52 struct _krb5_key_type *kt; 53}; 54 55static void 56_krb5_cc_schedule(krb5_context context, 57 struct _krb5_key_type *kt, 58 struct _krb5_key_data *kd) 59{ 60 struct cc_schedule *key = kd->schedule->data; 61 CCAlgorithm alg = (CCAlgorithm)kt->evp; 62 63 key->kt = kt; 64 65 if (CCCryptorCreateWithMode(kCCEncrypt, 66 kCCModeCBC, 67 alg, 68 ccCBCCTS3, 69 NULL, 70 kd->key->keyvalue.data, 71 kd->key->keyvalue.length, 72 NULL, 73 0, 74 0, 75 0, 76 &key->enc) != 0) 77 abort(); 78 79 if (CCCryptorCreateWithMode(kCCDecrypt, 80 kCCModeCBC, 81 alg, 82 ccCBCCTS3, 83 NULL, 84 kd->key->keyvalue.data, 85 kd->key->keyvalue.length, 86 NULL, 87 0, 88 0, 89 0, 90 &key->dec) != 0) 91 abort(); 92} 93 94static void 95_krb5_cc_cleanup(krb5_context context, struct _krb5_key_data *kd) 96{ 97 struct cc_schedule *key = kd->schedule->data; 98 CCCryptorRelease(key->enc); 99 CCCryptorRelease(key->dec); 100} 101 102static struct _krb5_key_type keytype_aes128 = { 103 ENCTYPE_AES128_CTS_HMAC_SHA1_96, 104 "aes-128", 105 128, 106 16, 107 sizeof(struct cc_schedule), 108 NULL, 109 _krb5_cc_schedule, 110 _krb5_AES_salt, 111 NULL, 112 _krb5_cc_cleanup, 113 (void *)kCCAlgorithmAES128 114}; 115 116static struct _krb5_key_type keytype_aes256 = { 117 ENCTYPE_AES256_CTS_HMAC_SHA1_96, 118 "aes-256", 119 256, 120 32, 121 sizeof(struct cc_schedule), 122 NULL, 123 _krb5_cc_schedule, 124 _krb5_AES_salt, 125 NULL, 126 _krb5_cc_cleanup, 127 (void *)kCCAlgorithmAES128 128}; 129 130struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = { 131 CKSUMTYPE_HMAC_SHA1_96_AES_128, 132 "hmac-sha1-96-aes128", 133 64, 134 12, 135 F_KEYED | F_CPROOF | F_DERIVED, 136 _krb5_SP_HMAC_SHA1_checksum, 137 NULL 138}; 139 140struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = { 141 CKSUMTYPE_HMAC_SHA1_96_AES_256, 142 "hmac-sha1-96-aes256", 143 64, 144 12, 145 F_KEYED | F_CPROOF | F_DERIVED, 146 _krb5_SP_HMAC_SHA1_checksum, 147 NULL 148}; 149 150static krb5_error_code 151cc_AES_PRF(krb5_context context, 152 krb5_crypto crypto, 153 const krb5_data *in, 154 krb5_data *out) 155{ 156 struct _krb5_checksum_type *ct = crypto->et->checksum; 157 krb5_error_code ret; 158 Checksum result; 159 krb5_keyblock *derived; 160 161 result.cksumtype = ct->type; 162 ret = krb5_data_alloc(&result.checksum, ct->checksumsize); 163 if (ret) { 164 krb5_set_error_message(context, ret, N_("malloc: out memory", "")); 165 return ret; 166 } 167 168 ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); 169 if (ret) { 170 krb5_data_free(&result.checksum); 171 return ret; 172 } 173 174 if (result.checksum.length < crypto->et->blocksize) 175 krb5_abortx(context, "internal prf error"); 176 177 derived = NULL; 178 ret = krb5_derive_key(context, crypto->key.key, 179 crypto->et->type, "prf", 3, &derived); 180 if (ret) 181 krb5_abortx(context, "krb5_derive_key"); 182 183 ret = krb5_data_alloc(out, crypto->et->blocksize); 184 if (ret) 185 krb5_abortx(context, "malloc failed"); 186 187 { 188 CCAlgorithm alg = (CCAlgorithm)crypto->et->keytype->evp; 189 CCCryptorStatus s; 190 size_t moved; 191 192 s = CCCrypt(kCCEncrypt, 193 alg, 194 0, 195 derived->keyvalue.data, 196 crypto->et->keytype->size, 197 NULL, 198 result.checksum.data, 199 crypto->et->blocksize, 200 out->data, 201 crypto->et->blocksize, 202 &moved); 203 if (s) 204 krb5_abortx(context, "encrypt failed"); 205 if (moved != crypto->et->blocksize) 206 krb5_abortx(context, "encrypt failed"); 207 208 } 209 210 krb5_data_free(&result.checksum); 211 krb5_free_keyblock(context, derived); 212 213 return ret; 214} 215 216static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 }; 217 218static krb5_error_code 219_krb5_cc_encrypt_cts(krb5_context context, 220 struct _krb5_key_data *key, 221 void *data, 222 size_t len, 223 krb5_boolean encryptp, 224 int usage, 225 void *ivec) 226{ 227 struct cc_schedule *ctx = key->schedule->data; 228 size_t blocksize; 229 unsigned char *p, *p0; 230 size_t moved, plen = len; 231 CCCryptorStatus s; 232 CCCryptorRef c; 233 234 c = encryptp ? ctx->enc : ctx->dec; 235 236 p0 = p = malloc(len); 237 if (p0 == NULL) 238 return ENOMEM; 239 240 blocksize = 16; /* XXX only for aes now */ 241 242 if (len < blocksize) { 243 krb5_set_error_message(context, EINVAL, 244 "message block too short"); 245 return EINVAL; 246 } else if (len == blocksize) { 247 struct _krb5_key_type *kt = ctx->kt; 248 CCAlgorithm alg = (CCAlgorithm)kt->evp; 249 250 s = CCCrypt(encryptp ? kCCEncrypt : kCCDecrypt, 251 alg, 252 0, 253 key->key->keyvalue.data, 254 key->key->keyvalue.length, 255 NULL, 256 data, 257 len, 258 data, 259 len, 260 &moved); 261 heim_assert(s == 0, "CCCrypt failed"); 262 heim_assert(moved == len, "moved == len"); 263 264 return 0; 265 } 266 267 if (ivec) 268 CCCryptorReset(c, ivec); 269 else 270 CCCryptorReset(c, zero_ivec); 271 272 s = CCCryptorUpdate(c, data, len, p, plen, &moved); 273 heim_assert(s == 0, "CCCryptorUpdate failed"); 274 plen -= moved; 275 p += moved; 276 s = CCCryptorFinal(c, p, plen, &moved); 277 heim_assert(s == 0, "CCCryptorFinal failed"); 278 plen -= moved; 279 heim_assert(plen == 0, "plen == 0"); 280 281 memcpy(data, p0, len); 282 free(p0); 283 284 return 0; 285} 286 287 288struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { 289 ETYPE_AES128_CTS_HMAC_SHA1_96, 290 "aes128-cts-hmac-sha1-96", 291 16, 292 1, 293 16, 294 &keytype_aes128, 295 &_krb5_checksum_sha1, 296 &_krb5_checksum_hmac_sha1_aes128, 297 F_DERIVED, 298 _krb5_cc_encrypt_cts, 299 16, 300 cc_AES_PRF 301}; 302 303struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { 304 ETYPE_AES256_CTS_HMAC_SHA1_96, 305 "aes256-cts-hmac-sha1-96", 306 16, 307 1, 308 16, 309 &keytype_aes256, 310 &_krb5_checksum_sha1, 311 &_krb5_checksum_hmac_sha1_aes256, 312 F_DERIVED, 313 _krb5_cc_encrypt_cts, 314 16, 315 cc_AES_PRF 316}; 317 318#else 319 320/* 321 * EVP based 322 */ 323 324static struct _krb5_key_type keytype_aes128 = { 325 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, 326 "aes-128", 327 128, 328 16, 329 sizeof(struct _krb5_evp_schedule), 330 NULL, 331 _krb5_evp_schedule, 332 _krb5_AES_salt, 333 NULL, 334 _krb5_evp_cleanup, 335 EVP_aes_128_cbc 336}; 337 338static struct _krb5_key_type keytype_aes256 = { 339 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, 340 "aes-256", 341 256, 342 32, 343 sizeof(struct _krb5_evp_schedule), 344 NULL, 345 _krb5_evp_schedule, 346 _krb5_AES_salt, 347 NULL, 348 _krb5_evp_cleanup, 349 EVP_aes_256_cbc 350}; 351 352struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = { 353 CKSUMTYPE_HMAC_SHA1_96_AES_128, 354 "hmac-sha1-96-aes128", 355 64, 356 12, 357 F_KEYED | F_CPROOF | F_DERIVED, 358 _krb5_SP_HMAC_SHA1_checksum, 359 NULL 360}; 361 362struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = { 363 CKSUMTYPE_HMAC_SHA1_96_AES_256, 364 "hmac-sha1-96-aes256", 365 64, 366 12, 367 F_KEYED | F_CPROOF | F_DERIVED, 368 _krb5_SP_HMAC_SHA1_checksum, 369 NULL 370}; 371 372static krb5_error_code 373AES_PRF(krb5_context context, 374 krb5_crypto crypto, 375 const krb5_data *in, 376 krb5_data *out) 377{ 378 struct _krb5_checksum_type *ct = crypto->et->checksum; 379 krb5_error_code ret; 380 Checksum result; 381 krb5_keyblock *derived; 382 383 result.cksumtype = ct->type; 384 ret = krb5_data_alloc(&result.checksum, ct->checksumsize); 385 if (ret) { 386 krb5_set_error_message(context, ret, N_("malloc: out memory", "")); 387 return ret; 388 } 389 390 ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); 391 if (ret) { 392 krb5_data_free(&result.checksum); 393 return ret; 394 } 395 396 if (result.checksum.length < crypto->et->blocksize) 397 krb5_abortx(context, "internal prf error"); 398 399 derived = NULL; 400 ret = krb5_derive_key(context, crypto->key.key, 401 crypto->et->type, "prf", 3, &derived); 402 if (ret) 403 krb5_abortx(context, "krb5_derive_key"); 404 405 ret = krb5_data_alloc(out, crypto->et->blocksize); 406 if (ret) 407 krb5_abortx(context, "malloc failed"); 408 409 { 410 const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); 411 EVP_CIPHER_CTX ctx; 412 413 EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ 414 EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); 415 EVP_Cipher(&ctx, out->data, result.checksum.data, 416 crypto->et->blocksize); 417 EVP_CIPHER_CTX_cleanup(&ctx); 418 } 419 420 krb5_data_free(&result.checksum); 421 krb5_free_keyblock(context, derived); 422 423 return ret; 424} 425 426struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { 427 ETYPE_AES128_CTS_HMAC_SHA1_96, 428 "aes128-cts-hmac-sha1-96", 429 16, 430 1, 431 16, 432 &keytype_aes128, 433 &_krb5_checksum_sha1, 434 &_krb5_checksum_hmac_sha1_aes128, 435 F_DERIVED, 436 _krb5_evp_encrypt_cts, 437 16, 438 AES_PRF 439}; 440 441struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { 442 ETYPE_AES256_CTS_HMAC_SHA1_96, 443 "aes256-cts-hmac-sha1-96", 444 16, 445 1, 446 16, 447 &keytype_aes256, 448 &_krb5_checksum_sha1, 449 &_krb5_checksum_hmac_sha1_aes256, 450 F_DERIVED, 451 _krb5_evp_encrypt_cts, 452 16, 453 AES_PRF 454}; 455 456#endif 457