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 size_t prfsize; 161 162 result.cksumtype = ct->type; 163 ret = krb5_data_alloc(&result.checksum, ct->checksumsize); 164 if (ret) { 165 krb5_set_error_message(context, ret, N_("malloc: out memory", "")); 166 return ret; 167 } 168 169 ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); 170 if (ret) { 171 krb5_data_free(&result.checksum); 172 return ret; 173 } 174 175 if (result.checksum.length < crypto->et->blocksize) 176 krb5_abortx(context, "internal prf error"); 177 178 derived = NULL; 179 ret = krb5_derive_key(context, crypto->key.key, 180 crypto->et->type, "prf", 3, &derived); 181 if (ret) 182 krb5_abortx(context, "krb5_derive_key"); 183 184 prfsize = (result.checksum.length / crypto->et->blocksize) * crypto->et->blocksize; 185 heim_assert(prfsize == crypto->et->prf_length, "prfsize not same ?"); 186 187 ret = krb5_data_alloc(out, crypto->et->blocksize); 188 if (ret) 189 krb5_abortx(context, "malloc failed"); 190 191 { 192 CCAlgorithm alg = (CCAlgorithm)crypto->et->keytype->evp; 193 CCCryptorStatus s; 194 size_t moved; 195 196 s = CCCrypt(kCCEncrypt, 197 alg, 198 0, 199 derived->keyvalue.data, 200 crypto->et->keytype->size, 201 NULL, 202 result.checksum.data, 203 prfsize, 204 out->data, 205 prfsize, 206 &moved); 207 if (s) 208 krb5_abortx(context, "encrypt failed"); 209 if (moved != prfsize) 210 krb5_abortx(context, "encrypt failed"); 211 212 } 213 214 krb5_data_free(&result.checksum); 215 krb5_free_keyblock(context, derived); 216 217 return ret; 218} 219 220static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 }; 221 222static krb5_error_code 223_krb5_cc_encrypt_cts(krb5_context context, 224 struct _krb5_key_data *key, 225 void *data, 226 size_t len, 227 krb5_boolean encryptp, 228 int usage, 229 void *ivec) 230{ 231 struct cc_schedule *ctx = key->schedule->data; 232 size_t blocksize; 233 unsigned char *p, *p0; 234 size_t moved, plen = len; 235 CCCryptorStatus s; 236 CCCryptorRef c; 237 238 c = encryptp ? ctx->enc : ctx->dec; 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 p0 = p = malloc(len); 268 if (p0 == NULL) 269 return ENOMEM; 270 271 if (ivec) 272 CCCryptorReset(c, ivec); 273 else 274 CCCryptorReset(c, zero_ivec); 275 276 s = CCCryptorUpdate(c, data, len, p, plen, &moved); 277 heim_assert(s == 0, "CCCryptorUpdate failed"); 278 plen -= moved; 279 p += moved; 280 s = CCCryptorFinal(c, p, plen, &moved); 281 heim_assert(s == 0, "CCCryptorFinal failed"); 282 plen -= moved; 283 heim_assert(plen == 0, "plen == 0"); 284 285 memcpy(data, p0, len); 286 free(p0); 287 288 return 0; 289} 290 291 292struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { 293 ETYPE_AES128_CTS_HMAC_SHA1_96, 294 "aes128-cts-hmac-sha1-96", 295 16, 296 1, 297 16, 298 &keytype_aes128, 299 &_krb5_checksum_sha1, 300 &_krb5_checksum_hmac_sha1_aes128, 301 F_DERIVED, 302 _krb5_cc_encrypt_cts, 303 16, 304 cc_AES_PRF 305}; 306 307struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { 308 ETYPE_AES256_CTS_HMAC_SHA1_96, 309 "aes256-cts-hmac-sha1-96", 310 16, 311 1, 312 16, 313 &keytype_aes256, 314 &_krb5_checksum_sha1, 315 &_krb5_checksum_hmac_sha1_aes256, 316 F_DERIVED, 317 _krb5_cc_encrypt_cts, 318 16, 319 cc_AES_PRF 320}; 321 322#else 323 324/* 325 * EVP based 326 */ 327 328static struct _krb5_key_type keytype_aes128 = { 329 KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, 330 "aes-128", 331 128, 332 16, 333 sizeof(struct _krb5_evp_schedule), 334 NULL, 335 _krb5_evp_schedule, 336 _krb5_AES_salt, 337 NULL, 338 _krb5_evp_cleanup, 339 EVP_aes_128_cbc 340}; 341 342static struct _krb5_key_type keytype_aes256 = { 343 KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, 344 "aes-256", 345 256, 346 32, 347 sizeof(struct _krb5_evp_schedule), 348 NULL, 349 _krb5_evp_schedule, 350 _krb5_AES_salt, 351 NULL, 352 _krb5_evp_cleanup, 353 EVP_aes_256_cbc 354}; 355 356struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = { 357 CKSUMTYPE_HMAC_SHA1_96_AES_128, 358 "hmac-sha1-96-aes128", 359 64, 360 12, 361 F_KEYED | F_CPROOF | F_DERIVED, 362 _krb5_SP_HMAC_SHA1_checksum, 363 NULL 364}; 365 366struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = { 367 CKSUMTYPE_HMAC_SHA1_96_AES_256, 368 "hmac-sha1-96-aes256", 369 64, 370 12, 371 F_KEYED | F_CPROOF | F_DERIVED, 372 _krb5_SP_HMAC_SHA1_checksum, 373 NULL 374}; 375 376static krb5_error_code 377AES_PRF(krb5_context context, 378 krb5_crypto crypto, 379 const krb5_data *in, 380 krb5_data *out) 381{ 382 struct _krb5_checksum_type *ct = crypto->et->checksum; 383 krb5_error_code ret; 384 Checksum result; 385 krb5_keyblock *derived; 386 387 result.cksumtype = ct->type; 388 ret = krb5_data_alloc(&result.checksum, ct->checksumsize); 389 if (ret) { 390 krb5_set_error_message(context, ret, N_("malloc: out memory", "")); 391 return ret; 392 } 393 394 ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); 395 if (ret) { 396 krb5_data_free(&result.checksum); 397 return ret; 398 } 399 400 if (result.checksum.length < crypto->et->blocksize) 401 krb5_abortx(context, "internal prf error"); 402 403 derived = NULL; 404 ret = krb5_derive_key(context, crypto->key.key, 405 crypto->et->type, "prf", 3, &derived); 406 if (ret) 407 krb5_abortx(context, "krb5_derive_key"); 408 409 ret = krb5_data_alloc(out, crypto->et->blocksize); 410 if (ret) 411 krb5_abortx(context, "malloc failed"); 412 413 { 414 const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); 415 EVP_CIPHER_CTX ctx; 416 417 EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ 418 EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); 419 EVP_Cipher(&ctx, out->data, result.checksum.data, 420 crypto->et->blocksize); 421 EVP_CIPHER_CTX_cleanup(&ctx); 422 } 423 424 krb5_data_free(&result.checksum); 425 krb5_free_keyblock(context, derived); 426 427 return ret; 428} 429 430struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { 431 ETYPE_AES128_CTS_HMAC_SHA1_96, 432 "aes128-cts-hmac-sha1-96", 433 16, 434 1, 435 16, 436 &keytype_aes128, 437 &_krb5_checksum_sha1, 438 &_krb5_checksum_hmac_sha1_aes128, 439 F_DERIVED, 440 _krb5_evp_encrypt_cts, 441 16, 442 AES_PRF 443}; 444 445struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { 446 ETYPE_AES256_CTS_HMAC_SHA1_96, 447 "aes256-cts-hmac-sha1-96", 448 16, 449 1, 450 16, 451 &keytype_aes256, 452 &_krb5_checksum_sha1, 453 &_krb5_checksum_hmac_sha1_aes256, 454 F_DERIVED, 455 _krb5_evp_encrypt_cts, 456 16, 457 AES_PRF 458}; 459 460#endif 461