1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 #include <k5-int.h> 9 #include <enc_provider.h> 10 11 #define BLOCK_SIZE 16 12 13 #define XOR_BLOCK(src, dst) \ 14 (dst)[0] ^= (src)[0]; \ 15 (dst)[1] ^= (src)[1]; \ 16 (dst)[2] ^= (src)[2]; \ 17 (dst)[3] ^= (src)[3]; \ 18 (dst)[4] ^= (src)[4]; \ 19 (dst)[5] ^= (src)[5]; \ 20 (dst)[6] ^= (src)[6]; \ 21 (dst)[7] ^= (src)[7]; \ 22 (dst)[8] ^= (src)[8]; \ 23 (dst)[9] ^= (src)[9]; \ 24 (dst)[10] ^= (src)[10]; \ 25 (dst)[11] ^= (src)[11]; \ 26 (dst)[12] ^= (src)[12]; \ 27 (dst)[13] ^= (src)[13]; \ 28 (dst)[14] ^= (src)[14]; \ 29 (dst)[15] ^= (src)[15] 30 31 #define xorblock(x,y) XOR_BLOCK(y, x) 32 33 /*ARGSUSED*/ 34 krb5_error_code 35 krb5int_aes_encrypt(krb5_context context, 36 const krb5_keyblock *key, const krb5_data *ivec, 37 const krb5_data *input, krb5_data *output) 38 { 39 krb5_error_code ret = 0; 40 unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE]; 41 int nblocks = 0, blockno; 42 #ifdef _KERNEL 43 crypto_context_t kef_ctx; 44 crypto_mechanism_t mech; 45 int result = 0; 46 #else 47 CK_RV rv; 48 KRB5_MECH_TO_PKCS algos; 49 CK_MECHANISM mechanism; 50 CK_ULONG outlen; 51 #endif /* _KERNEL */ 52 53 if (ivec && ivec->data != NULL && ivec->length >= BLOCK_SIZE) 54 (void) memcpy(tmp, ivec->data, BLOCK_SIZE); 55 else 56 (void) memset(tmp, 0, BLOCK_SIZE); 57 58 nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE; 59 60 #ifndef _KERNEL 61 rv = get_algo(key->enctype, &algos); 62 if (rv != CKR_OK) 63 goto cleanup; 64 65 rv = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key); 66 if (rv != CKR_OK) 67 goto cleanup; 68 69 mechanism.mechanism = algos.enc_algo; 70 mechanism.pParameter = (ivec != NULL ? ivec->data : NULL); 71 mechanism.ulParameterLen = (ivec != NULL ? ivec->length : 0); 72 73 rv = C_EncryptInit(krb_ctx_hSession(context), &mechanism, key->hKey); 74 75 if (rv != CKR_OK) { 76 KRB5_LOG(KRB5_ERR, "C_EncryptInit failed in " 77 "krb5int_aes_encrypt: rv = 0x%x", rv); 78 goto cleanup; 79 } 80 #endif /* !_KERNEL */ 81 82 if (nblocks == 1) { 83 #ifndef _KERNEL 84 /* XXX Used for DK function. */ 85 outlen = (CK_ULONG)output->length; 86 rv = C_Encrypt(krb_ctx_hSession(context), 87 (CK_BYTE_PTR)input->data, 88 (CK_ULONG)input->length, 89 (CK_BYTE_PTR)output->data, 90 (CK_ULONG_PTR)&outlen); 91 output->length = (unsigned int)outlen; 92 #else 93 ret = k5_ef_crypto((const char *)input->data, 94 (char *)output->data, 95 input->length, (krb5_keyblock *)key, 96 (krb5_data *)ivec, FALSE); 97 #endif /* _KERNEL */ 98 } else { 99 int nleft; 100 #ifdef _KERNEL 101 crypto_data_t ct, pt; 102 103 mech.cm_type = key->kef_mt; 104 mech.cm_param = (ivec != NULL ? ivec->data : NULL); 105 mech.cm_param_len = (ivec != NULL ? ivec->length : 0); 106 107 result = crypto_encrypt_init(&mech, 108 (crypto_key_t *)&key->kef_key, 109 key->key_tmpl, &kef_ctx, NULL); 110 if (result != CRYPTO_SUCCESS) 111 goto cleanup; 112 ct.cd_format = CRYPTO_DATA_RAW; 113 ct.cd_offset = 0; 114 ct.cd_length = BLOCK_SIZE; 115 ct.cd_miscdata = NULL; 116 117 pt.cd_format = CRYPTO_DATA_RAW; 118 pt.cd_offset = 0; 119 pt.cd_length = BLOCK_SIZE; 120 pt.cd_miscdata = NULL; 121 #else 122 CK_ULONG outlen = BLOCK_SIZE; 123 #endif /* _KERNEL */ 124 125 for (blockno = 0; blockno < nblocks - 2; blockno++) { 126 xorblock(tmp, (uchar_t *)input->data + blockno * BLOCK_SIZE); 127 #ifdef _KERNEL 128 pt.cd_raw.iov_base = (char *)tmp; 129 pt.cd_raw.iov_len = BLOCK_SIZE; 130 ct.cd_raw.iov_base = (char *)output->data + blockno * BLOCK_SIZE; 131 ct.cd_raw.iov_len = BLOCK_SIZE; 132 133 result = crypto_encrypt_update(kef_ctx, &pt, &ct, NULL); 134 if (result != CRYPTO_SUCCESS) { 135 KRB5_LOG(KRB5_ERR, 136 "crypto_encrypt_update: error: rv = 0x%08x", 137 result); 138 goto cleanup; 139 } 140 bcopy(output->data + blockno * BLOCK_SIZE, tmp, BLOCK_SIZE); 141 #else 142 rv = C_EncryptUpdate(krb_ctx_hSession(context), 143 (CK_BYTE_PTR)tmp, 144 (CK_ULONG)BLOCK_SIZE, 145 (CK_BYTE_PTR)output->data + blockno * BLOCK_SIZE, 146 (CK_ULONG_PTR)&outlen); 147 148 if (rv != CKR_OK) 149 goto cleanup; 150 (void) memcpy(tmp, output->data + blockno * BLOCK_SIZE, 151 outlen); 152 #endif 153 } 154 /* Do final CTS step for last two blocks (the second of which 155 may or may not be incomplete). */ 156 157 xorblock(tmp, (uchar_t *)input->data + (nblocks - 2) * BLOCK_SIZE); 158 159 #ifdef _KERNEL 160 pt.cd_raw.iov_base = (char *)tmp; 161 pt.cd_raw.iov_len = BLOCK_SIZE; 162 163 ct.cd_raw.iov_base = (char *)tmp2; 164 ct.cd_raw.iov_len = BLOCK_SIZE; 165 166 result = crypto_encrypt_update(kef_ctx, &pt, &ct, NULL); 167 if (result != CRYPTO_SUCCESS) { 168 KRB5_LOG(KRB5_ERR, 169 "crypto_encrypt_update: error: rv = 0x%08x", result); 170 goto cleanup; 171 } 172 #else 173 rv = C_EncryptUpdate(krb_ctx_hSession(context), 174 (CK_BYTE_PTR)tmp, 175 (CK_ULONG)BLOCK_SIZE, 176 (CK_BYTE_PTR)tmp2, 177 (CK_ULONG_PTR)&outlen); 178 179 if (rv != CKR_OK) 180 goto cleanup; 181 #endif /* _KERNEL */ 182 183 nleft = input->length - (nblocks - 1) * BLOCK_SIZE; 184 (void) memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, 185 tmp2, nleft); 186 (void) memcpy(tmp, tmp2, BLOCK_SIZE); 187 188 /* 189 * This effectively adds 0's as pad bytes if the last 190 * block is not exactly BLOCK_SIZE. 191 */ 192 (void) memset(tmp3, 0, sizeof(tmp3)); 193 194 (void) memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, nleft); 195 xorblock(tmp, tmp3); 196 #ifdef _KERNEL 197 pt.cd_raw.iov_base = (char *)tmp; 198 pt.cd_raw.iov_len = BLOCK_SIZE; 199 200 ct.cd_raw.iov_base = (char *)tmp2; 201 ct.cd_raw.iov_len = BLOCK_SIZE; 202 203 result = crypto_encrypt_update(kef_ctx, &pt, &ct, NULL); 204 if (result != CRYPTO_SUCCESS) { 205 KRB5_LOG(KRB5_ERR, 206 "crypto_encrypt_update: error: rv = 0x%08x", result); 207 goto cleanup; 208 } 209 #else 210 rv = C_EncryptUpdate(krb_ctx_hSession(context), 211 (CK_BYTE_PTR)tmp, 212 (CK_ULONG)BLOCK_SIZE, 213 (CK_BYTE_PTR)tmp2, 214 (CK_ULONG_PTR)&outlen); 215 216 if (rv != CKR_OK) 217 goto cleanup; 218 #endif /* _KERNEL */ 219 220 (void) memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, 221 tmp2, BLOCK_SIZE); 222 223 if (ivec && ivec->data != NULL && ivec->length >= BLOCK_SIZE) { 224 (void) memcpy(ivec->data, tmp2, BLOCK_SIZE); 225 } 226 227 #ifdef _KERNEL 228 ct.cd_raw.iov_base = (char *)tmp2; 229 ct.cd_raw.iov_len = BLOCK_SIZE; 230 231 result = crypto_encrypt_final(kef_ctx, &ct, NULL); 232 #else 233 /* Close the crypto session, ignore the output */ 234 rv = C_EncryptFinal(krb_ctx_hSession(context), 235 (CK_BYTE_PTR)tmp2, (CK_ULONG_PTR)&outlen); 236 237 if (rv != CKR_OK) 238 goto cleanup; 239 #endif /* _KERNEL */ 240 } 241 242 cleanup: 243 244 #ifdef _KERNEL 245 ret = result; 246 #else 247 if (rv != CKR_OK) 248 ret = PKCS_ERR; 249 #endif /* _KERNEL */ 250 251 if (ret) 252 bzero(output->data, input->length); 253 254 return (ret); 255 } 256 257 /*ARGSUSED*/ 258 krb5_error_code 259 krb5int_aes_decrypt(krb5_context context, 260 const krb5_keyblock *key, const krb5_data *ivec, 261 const krb5_data *input, krb5_data *output) 262 { 263 krb5_error_code ret = 0; 264 unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE]; 265 int nblocks = 0, blockno; 266 #ifdef _KERNEL 267 crypto_context_t kef_ctx; 268 crypto_mechanism_t mech; 269 int result = 0; 270 #else 271 CK_RV rv; 272 KRB5_MECH_TO_PKCS algos; 273 CK_MECHANISM mechanism; 274 CK_ULONG outlen; 275 #endif /* _KERNEL */ 276 277 if (ivec && ivec->data != NULL && ivec->length >= BLOCK_SIZE) 278 (void) memcpy(tmp, ivec->data, BLOCK_SIZE); 279 else 280 (void) memset(tmp, 0, BLOCK_SIZE); 281 282 nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE; 283 284 #ifndef _KERNEL 285 rv = get_algo(key->enctype, &algos); 286 if (rv != CKR_OK) 287 goto cleanup; 288 289 rv = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key); 290 if (rv != CKR_OK) { 291 goto cleanup; 292 } 293 294 mechanism.mechanism = algos.enc_algo; 295 mechanism.pParameter = (ivec != NULL ? ivec->data : NULL); 296 mechanism.ulParameterLen = (ivec != NULL ? ivec->length : 0); 297 298 rv = C_DecryptInit(krb_ctx_hSession(context), &mechanism, key->hKey); 299 300 if (rv != CKR_OK) { 301 KRB5_LOG(KRB5_ERR, "C_DecryptInit failed in " 302 "krb5int_aes_decrypt: rv = 0x%x", rv); 303 goto cleanup; 304 } 305 #endif 306 307 if (nblocks == 1) { 308 if (input->length < BLOCK_SIZE) 309 return (KRB5_CRYPTO_INTERNAL); 310 #ifndef _KERNEL 311 rv = C_Decrypt(krb_ctx_hSession(context), 312 (CK_BYTE_PTR)input->data, 313 (CK_ULONG)input->length, 314 (CK_BYTE_PTR)output->data, 315 (CK_ULONG_PTR)&output->length); 316 #else 317 ret = k5_ef_crypto((const char *)input->data, (char *)output->data, 318 input->length, (krb5_keyblock *)key, 319 (krb5_data *)ivec, FALSE); 320 #endif /* _KERNEL */ 321 322 } else { 323 #ifdef _KERNEL 324 crypto_data_t ct, pt; 325 326 (void) memset(&ct, 0, sizeof(ct)); 327 (void) memset(&pt, 0, sizeof(pt)); 328 329 mech.cm_type = key->kef_mt; 330 mech.cm_param = (ivec != NULL ? ivec->data : NULL); 331 mech.cm_param_len = (ivec != NULL ? ivec->length : 0); 332 333 result = crypto_decrypt_init(&mech, 334 (crypto_key_t *)&key->kef_key, 335 key->key_tmpl, &kef_ctx, NULL); 336 if (result != CRYPTO_SUCCESS) 337 goto cleanup; 338 ct.cd_format = CRYPTO_DATA_RAW; 339 ct.cd_offset = 0; 340 ct.cd_length = BLOCK_SIZE; 341 ct.cd_raw.iov_len = BLOCK_SIZE; 342 343 pt.cd_format = CRYPTO_DATA_RAW; 344 pt.cd_offset = 0; 345 pt.cd_length = BLOCK_SIZE; 346 pt.cd_raw.iov_len = BLOCK_SIZE; 347 #endif /* _KERNEL */ 348 349 for (blockno = 0; blockno < nblocks - 2; blockno++) { 350 #ifdef _KERNEL 351 KRB5_LOG(KRB5_INFO, "krb5int_aes_decrypt: blockno = %d", 352 blockno); 353 ct.cd_raw.iov_base = (char *)input->data + blockno * BLOCK_SIZE; 354 pt.cd_raw.iov_base = (char *)tmp2; 355 356 result = crypto_decrypt_update(kef_ctx, &ct, &pt, NULL); 357 if (result != CRYPTO_SUCCESS) { 358 KRB5_LOG(KRB5_ERR, 359 "crypto_decrypt_update: error: rv = 0x%08x", 360 result); 361 goto cleanup; 362 } 363 #else 364 outlen = sizeof(tmp2); 365 rv = C_DecryptUpdate(krb_ctx_hSession(context), 366 (CK_BYTE_PTR)input->data + blockno * BLOCK_SIZE, 367 (CK_ULONG)BLOCK_SIZE, 368 (CK_BYTE_PTR)tmp2, 369 (CK_ULONG_PTR)&outlen); 370 371 if (rv != CKR_OK) 372 goto cleanup; 373 374 #endif /* _KERNEL */ 375 xorblock(tmp2, tmp); 376 (void) memcpy(output->data + blockno * BLOCK_SIZE, 377 tmp2, BLOCK_SIZE); 378 (void) memcpy(tmp, input->data + blockno * BLOCK_SIZE, 379 BLOCK_SIZE); 380 } 381 /* Do last two blocks, the second of which (next-to-last block 382 of plaintext) may be incomplete. */ 383 #ifdef _KERNEL 384 ct.cd_raw.iov_base = (char *)input->data + (nblocks - 2) * BLOCK_SIZE; 385 ct.cd_raw.iov_len = BLOCK_SIZE; 386 pt.cd_raw.iov_base = (char *)tmp2; 387 pt.cd_raw.iov_len = BLOCK_SIZE; 388 389 result = crypto_decrypt_update(kef_ctx, &ct, &pt, NULL); 390 if (result != CRYPTO_SUCCESS) { 391 KRB5_LOG(KRB5_ERR, 392 "crypto_decrypt_update: error: rv = 0x%08x", 393 result); 394 goto cleanup; 395 } 396 #else 397 outlen = sizeof(tmp2); 398 rv = C_DecryptUpdate(krb_ctx_hSession(context), 399 (CK_BYTE_PTR)input->data + (nblocks - 2) * BLOCK_SIZE, 400 (CK_ULONG)BLOCK_SIZE, 401 (CK_BYTE_PTR)tmp2, 402 (CK_ULONG_PTR)&outlen); 403 404 if (rv != CKR_OK) 405 goto cleanup; 406 #endif /* _KERNEL */ 407 408 /* Set tmp3 to last ciphertext block, padded. */ 409 (void) memset(tmp3, 0, sizeof(tmp3)); 410 (void) memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, 411 input->length - (nblocks - 1) * BLOCK_SIZE); 412 413 /* Set tmp2 to last (possibly partial) plaintext block, and save it. */ 414 xorblock(tmp2, tmp3); 415 (void) memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, 416 input->length - (nblocks - 1) * BLOCK_SIZE); 417 418 /* 419 * Maybe keep the trailing part, and copy in the 420 * last ciphertext block. 421 */ 422 (void) memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE); 423 424 /* 425 * Decrypt, to get next to last plaintext block xor 426 * previous ciphertext. 427 */ 428 #ifdef _KERNEL 429 ct.cd_raw.iov_base = (char *)tmp2; 430 ct.cd_raw.iov_len = BLOCK_SIZE; 431 pt.cd_raw.iov_base = (char *)tmp3; 432 pt.cd_raw.iov_len = BLOCK_SIZE; 433 434 result = crypto_decrypt_update(kef_ctx, &ct, &pt, NULL); 435 if (result != CRYPTO_SUCCESS) { 436 KRB5_LOG(KRB5_ERR, 437 "crypto_decrypt_update: error: rv = 0x%08x", 438 result); 439 goto cleanup; 440 } 441 #else 442 outlen = sizeof(tmp3); 443 rv = C_DecryptUpdate(krb_ctx_hSession(context), 444 (CK_BYTE_PTR)tmp2, 445 (CK_ULONG)BLOCK_SIZE, 446 (CK_BYTE_PTR)tmp3, 447 (CK_ULONG_PTR)&outlen); 448 449 if (rv != CKR_OK) 450 goto cleanup; 451 #endif /* _KERNEL */ 452 453 xorblock(tmp3, tmp); 454 (void) memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, 455 tmp3, BLOCK_SIZE); 456 457 if (ivec) 458 (void) memcpy(ivec->data, 459 input->data + (nblocks - 2) * BLOCK_SIZE, BLOCK_SIZE); 460 461 #ifdef _KERNEL 462 pt.cd_raw.iov_base = (char *)tmp2; 463 pt.cd_raw.iov_len = BLOCK_SIZE; 464 result = crypto_decrypt_final(kef_ctx, &pt, NULL); 465 #else 466 outlen = sizeof(tmp2); 467 rv = C_DecryptFinal(krb_ctx_hSession(context), 468 (CK_BYTE_PTR)tmp2, (CK_ULONG_PTR)&outlen); 469 470 if (rv != CKR_OK) 471 goto cleanup; 472 #endif /* _KERNEL */ 473 } 474 cleanup: 475 #ifdef _KERNEL 476 ret = result; 477 #else 478 if (rv != CKR_OK) 479 ret = PKCS_ERR; 480 #endif /* _KERNEL */ 481 482 if (ret) 483 bzero(output->data, input->length); 484 485 return (ret); 486 } 487 488 static krb5_error_code 489 k5_aes_make_key(krb5_context context, 490 const krb5_data *randombits, krb5_keyblock *key) 491 { 492 krb5_error_code ret = 0; 493 if (key->length != 16 && key->length != 32) 494 return(KRB5_BAD_KEYSIZE); 495 if (randombits->length != key->length) 496 return(KRB5_CRYPTO_INTERNAL); 497 498 key->magic = KV5M_KEYBLOCK; 499 key->dk_list = NULL; 500 501 #ifdef _KERNEL 502 key->kef_key.ck_data = NULL; 503 key->key_tmpl = NULL; 504 (void) memcpy(key->contents, randombits->data, randombits->length); 505 ret = init_key_kef(context->kef_cipher_mt, key); 506 #else 507 key->hKey = CK_INVALID_HANDLE; 508 (void) memcpy(key->contents, randombits->data, randombits->length); 509 ret = init_key_uef(krb_ctx_hSession(context), key); 510 #endif /* _KERNEL */ 511 512 KRB5_LOG0(KRB5_INFO, "k5_aes_make_key() end\n"); 513 return (ret); 514 } 515 516 /*ARGSUSED*/ 517 static krb5_error_code 518 krb5int_aes_init_state (krb5_context context, const krb5_keyblock *key, 519 krb5_keyusage usage, krb5_data *state) 520 { 521 if (!state) 522 return (0); 523 524 if (state && state->data) 525 FREE(state->data, state->length); 526 527 state->length = BLOCK_SIZE; 528 state->data = (void *) MALLOC(BLOCK_SIZE); 529 530 if (state->data == NULL) 531 return ENOMEM; 532 533 (void) memset(state->data, 0, state->length); 534 return (0); 535 } 536 537 const struct krb5_enc_provider krb5int_enc_aes128 = { 538 BLOCK_SIZE, 539 16, 16, 540 krb5int_aes_encrypt, 541 krb5int_aes_decrypt, 542 k5_aes_make_key, 543 krb5int_aes_init_state, 544 krb5int_default_free_state 545 }; 546 547 const struct krb5_enc_provider krb5int_enc_aes256 = { 548 BLOCK_SIZE, 549 32, 32, 550 krb5int_aes_encrypt, 551 krb5int_aes_decrypt, 552 k5_aes_make_key, 553 krb5int_aes_init_state, 554 krb5int_default_free_state 555 }; 556