17c478bd9Sstevel@tonic-gate /* 2*e753f464SWill Fiveash * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). 97c478bd9Sstevel@tonic-gate This cipher is widely believed and has been tested to be equivalent 107c478bd9Sstevel@tonic-gate with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark 117c478bd9Sstevel@tonic-gate of RSA Data Security) 127c478bd9Sstevel@tonic-gate 137c478bd9Sstevel@tonic-gate */ 147c478bd9Sstevel@tonic-gate #include <k5-int.h> 157c478bd9Sstevel@tonic-gate #include <arcfour.h> 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate /* salt string used for exportable ARCFOUR */ 187c478bd9Sstevel@tonic-gate static const char *l40 = "fortybits"; 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate void 217c478bd9Sstevel@tonic-gate krb5_arcfour_encrypt_length(enc, hash, inputlen, length) 227c478bd9Sstevel@tonic-gate const struct krb5_enc_provider *enc; 237c478bd9Sstevel@tonic-gate const struct krb5_hash_provider *hash; 247c478bd9Sstevel@tonic-gate size_t inputlen; 257c478bd9Sstevel@tonic-gate size_t *length; 267c478bd9Sstevel@tonic-gate { 277c478bd9Sstevel@tonic-gate size_t blocksize, hashsize; 287c478bd9Sstevel@tonic-gate 29505d05c7Sgtb blocksize = enc->block_size; 30505d05c7Sgtb hashsize = hash->hashsize; 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* checksum + (confounder + inputlen, in even blocksize) */ 337c478bd9Sstevel@tonic-gate *length = hashsize + krb5_roundup(8 + inputlen, blocksize); 347c478bd9Sstevel@tonic-gate } 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate krb5_keyusage 377c478bd9Sstevel@tonic-gate krb5int_arcfour_translate_usage(krb5_keyusage usage) 387c478bd9Sstevel@tonic-gate { 397c478bd9Sstevel@tonic-gate switch (usage) { 407c478bd9Sstevel@tonic-gate case 1: /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, */ 417c478bd9Sstevel@tonic-gate return 1; 427c478bd9Sstevel@tonic-gate case 2: /* ticket from kdc */ 437c478bd9Sstevel@tonic-gate return 2; 447c478bd9Sstevel@tonic-gate case 3: /* as-rep encrypted part */ 457c478bd9Sstevel@tonic-gate return 8; 467c478bd9Sstevel@tonic-gate case 4: /* tgs-req authz data */ 477c478bd9Sstevel@tonic-gate return 4; 487c478bd9Sstevel@tonic-gate case 5: /* tgs-req authz data in subkey */ 497c478bd9Sstevel@tonic-gate return 5; 507c478bd9Sstevel@tonic-gate case 6: /* tgs-req authenticator cksum */ 517c478bd9Sstevel@tonic-gate return 6; 527c478bd9Sstevel@tonic-gate case 7: /* tgs-req authenticator */ 537c478bd9Sstevel@tonic-gate return 7; 547c478bd9Sstevel@tonic-gate case 8: 557c478bd9Sstevel@tonic-gate return 8; 567c478bd9Sstevel@tonic-gate case 9: /* tgs-rep encrypted with subkey */ 577c478bd9Sstevel@tonic-gate return 8; 587c478bd9Sstevel@tonic-gate case 10: /* ap-rep authentication cksum */ 597c478bd9Sstevel@tonic-gate return 10; /* xxx Microsoft never uses this*/ 607c478bd9Sstevel@tonic-gate case 11: /* app-req authenticator */ 617c478bd9Sstevel@tonic-gate return 11; 627c478bd9Sstevel@tonic-gate case 12: /* app-rep encrypted part */ 637c478bd9Sstevel@tonic-gate return 12; 647c478bd9Sstevel@tonic-gate case 23: /* sign wrap token*/ 657c478bd9Sstevel@tonic-gate return 13; 667c478bd9Sstevel@tonic-gate default: 677c478bd9Sstevel@tonic-gate return usage; 687c478bd9Sstevel@tonic-gate } 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate krb5_error_code 727c478bd9Sstevel@tonic-gate krb5_arcfour_encrypt(context, enc, hash, key, usage, ivec, input, output) 737c478bd9Sstevel@tonic-gate krb5_context context; 747c478bd9Sstevel@tonic-gate const struct krb5_enc_provider *enc; 757c478bd9Sstevel@tonic-gate const struct krb5_hash_provider *hash; 767c478bd9Sstevel@tonic-gate const krb5_keyblock *key; 777c478bd9Sstevel@tonic-gate krb5_keyusage usage; 787c478bd9Sstevel@tonic-gate const krb5_data *ivec; 797c478bd9Sstevel@tonic-gate const krb5_data *input; 807c478bd9Sstevel@tonic-gate krb5_data *output; 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate krb5_keyblock k1, k2, k3; 837c478bd9Sstevel@tonic-gate krb5_keyblock *kptr; 847c478bd9Sstevel@tonic-gate krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder; 857c478bd9Sstevel@tonic-gate krb5_keyusage ms_usage; 86505d05c7Sgtb size_t keybytes, blocksize, hashsize; 877c478bd9Sstevel@tonic-gate krb5_error_code ret = 0; 887c478bd9Sstevel@tonic-gate 89505d05c7Sgtb blocksize = enc->block_size; 90505d05c7Sgtb keybytes = enc->keybytes; 91505d05c7Sgtb hashsize = hash->hashsize; 92*e753f464SWill Fiveash 937c478bd9Sstevel@tonic-gate bzero(&d2, sizeof(krb5_data)); 947c478bd9Sstevel@tonic-gate bzero(&k2, sizeof(krb5_keyblock)); 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * d1 is the contents buffer for key k1. 977c478bd9Sstevel@tonic-gate * k1 = HMAC(input_key, salt) 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate d1.length=keybytes; 1007c478bd9Sstevel@tonic-gate d1.data=MALLOC(d1.length); 1017c478bd9Sstevel@tonic-gate if (d1.data == NULL) 1027c478bd9Sstevel@tonic-gate return (ENOMEM); 1037c478bd9Sstevel@tonic-gate bcopy(key, &k1, sizeof (krb5_keyblock)); 1047c478bd9Sstevel@tonic-gate k1.length=d1.length; 1057c478bd9Sstevel@tonic-gate k1.contents= (void *) d1.data; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * d2 is the contents of key 'k2', which is used to generate the 1097c478bd9Sstevel@tonic-gate * checksum field. 'd2' == 'd1' when not using the exportable 1107c478bd9Sstevel@tonic-gate * enctype. This is only needed when using the exportable 1117c478bd9Sstevel@tonic-gate * enctype. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 1147c478bd9Sstevel@tonic-gate d2.length=keybytes; 1157c478bd9Sstevel@tonic-gate d2.data=MALLOC(d2.length); 1167c478bd9Sstevel@tonic-gate if (d2.data == NULL) { 1177c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 1187c478bd9Sstevel@tonic-gate return (ENOMEM); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate bcopy(key, &k2, sizeof (krb5_keyblock)); 1217c478bd9Sstevel@tonic-gate k2.length=d2.length; 1227c478bd9Sstevel@tonic-gate k2.contents=(void *) d2.data; 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * d3 will hold the contents of the final key used for the 1277c478bd9Sstevel@tonic-gate * encryption step. 'k3' is the key structure that has 'd3' 1287c478bd9Sstevel@tonic-gate * as its 'contents' field. 1297c478bd9Sstevel@tonic-gate * k3 = HMAC(k1, checksum) 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate d3.length=keybytes; 1327c478bd9Sstevel@tonic-gate d3.data=MALLOC(d3.length); 1337c478bd9Sstevel@tonic-gate if (d3.data == NULL) { 1347c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 1357c478bd9Sstevel@tonic-gate if (d2.data) 1367c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 1377c478bd9Sstevel@tonic-gate return (ENOMEM); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate bcopy(key, &k3, sizeof (krb5_keyblock)); 1407c478bd9Sstevel@tonic-gate k3.length=d3.length; 1417c478bd9Sstevel@tonic-gate k3.contents= (void *) d3.data; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate salt.length=14; 1447c478bd9Sstevel@tonic-gate salt.data=MALLOC(salt.length); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate if (salt.data == NULL) { 1477c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 1487c478bd9Sstevel@tonic-gate if (d2.data) 1497c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 1507c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 1517c478bd9Sstevel@tonic-gate return (ENOMEM); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* is "input" already blocksize aligned? if it is, then we need this 1557c478bd9Sstevel@tonic-gate step, otherwise we do not */ 1567c478bd9Sstevel@tonic-gate plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); 1577c478bd9Sstevel@tonic-gate plaintext.data=MALLOC(plaintext.length); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if (plaintext.data == NULL) { 1607c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 1617c478bd9Sstevel@tonic-gate if (d2.data) 1627c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 1637c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 1647c478bd9Sstevel@tonic-gate FREE(salt.data, salt.length); 1657c478bd9Sstevel@tonic-gate return(ENOMEM); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate bzero(plaintext.data, plaintext.length); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* setup convienient pointers into the allocated data */ 1707c478bd9Sstevel@tonic-gate checksum.length=hashsize; 1717c478bd9Sstevel@tonic-gate checksum.data=output->data; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); 1747c478bd9Sstevel@tonic-gate ciphertext.data=output->data+hashsize; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate confounder.length=CONFOUNDERLENGTH; 1777c478bd9Sstevel@tonic-gate confounder.data=plaintext.data; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate output->length = plaintext.length+hashsize; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* begin the encryption, computer K1 */ 1827c478bd9Sstevel@tonic-gate ms_usage=krb5int_arcfour_translate_usage(usage); 1837c478bd9Sstevel@tonic-gate if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 1847c478bd9Sstevel@tonic-gate (void) strncpy(salt.data, l40, salt.length); 1857c478bd9Sstevel@tonic-gate salt.data[10]=ms_usage & 0xff; 1867c478bd9Sstevel@tonic-gate salt.data[11]=(ms_usage >> 8) & 0xff; 1877c478bd9Sstevel@tonic-gate salt.data[12]=(ms_usage >> 16) & 0xff; 1887c478bd9Sstevel@tonic-gate salt.data[13]=(ms_usage >> 24) & 0xff; 1897c478bd9Sstevel@tonic-gate } else { 1907c478bd9Sstevel@tonic-gate salt.length=4; 1917c478bd9Sstevel@tonic-gate salt.data[0]=ms_usage & 0xff; 1927c478bd9Sstevel@tonic-gate salt.data[1]=(ms_usage >> 8) & 0xff; 1937c478bd9Sstevel@tonic-gate salt.data[2]=(ms_usage >> 16) & 0xff; 1947c478bd9Sstevel@tonic-gate salt.data[3]=(ms_usage >> 24) & 0xff; 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate #ifdef _KERNEL 1987c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, key, &salt, &d1); 1997c478bd9Sstevel@tonic-gate #else 2007c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, hash, key, 1, &salt, &d1); 2017c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 2027c478bd9Sstevel@tonic-gate if (ret != 0) 2037c478bd9Sstevel@tonic-gate goto cleanup; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 2067c478bd9Sstevel@tonic-gate bcopy(k1.contents, k2.contents, k2.length); 2077c478bd9Sstevel@tonic-gate (void) memset(k1.contents+7, 0xab, 9); 2087c478bd9Sstevel@tonic-gate kptr = &k2; 2097c478bd9Sstevel@tonic-gate } else { 2107c478bd9Sstevel@tonic-gate kptr = &k1; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* create a confounder block */ 2147c478bd9Sstevel@tonic-gate ret=krb5_c_random_make_octets(context, &confounder); 2157c478bd9Sstevel@tonic-gate bcopy(input->data, plaintext.data+confounder.length, input->length); 2167c478bd9Sstevel@tonic-gate if (ret) 2177c478bd9Sstevel@tonic-gate goto cleanup; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Compute the HMAC checksum field. 2217c478bd9Sstevel@tonic-gate * checksum = HMAC(k1/k2, plaintext); 2227c478bd9Sstevel@tonic-gate * k2 used when key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2257c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, kptr, &plaintext, &checksum); 2267c478bd9Sstevel@tonic-gate #else 2277c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &checksum); 2287c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 2297c478bd9Sstevel@tonic-gate if (ret) 2307c478bd9Sstevel@tonic-gate goto cleanup; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* 2337c478bd9Sstevel@tonic-gate * The final encryption key is the HMAC of the checksum 2347c478bd9Sstevel@tonic-gate * using k1 2357c478bd9Sstevel@tonic-gate * 2367c478bd9Sstevel@tonic-gate * k3 = HMAC(k1, checksum); 2377c478bd9Sstevel@tonic-gate * == or (in other terms) == 2387c478bd9Sstevel@tonic-gate * k3 = HMAC((HMAC(input_key,salt), HMAC(k1, plaintext)); 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2417c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, &k1, &checksum, &d3); 2427c478bd9Sstevel@tonic-gate #else 2437c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, hash, &k1, 1, &checksum, &d3); 2447c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 2457c478bd9Sstevel@tonic-gate if (ret) 2467c478bd9Sstevel@tonic-gate goto cleanup; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate ret = (*(enc->encrypt))(context, &k3, ivec, &plaintext, &ciphertext); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate cleanup: 2517c478bd9Sstevel@tonic-gate bzero(d1.data, d1.length); 2527c478bd9Sstevel@tonic-gate if (d2.data) { 2537c478bd9Sstevel@tonic-gate bzero(d2.data, d2.length); 2547c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate bzero(d3.data, d3.length); 2577c478bd9Sstevel@tonic-gate bzero(salt.data, salt.length); 2587c478bd9Sstevel@tonic-gate bzero(plaintext.data, plaintext.length); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 2617c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 2627c478bd9Sstevel@tonic-gate FREE(salt.data, salt.length); 2637c478bd9Sstevel@tonic-gate FREE(plaintext.data, plaintext.length); 2647c478bd9Sstevel@tonic-gate return (ret); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* This is the arcfour-hmac decryption routine */ 2687c478bd9Sstevel@tonic-gate krb5_error_code 2697c478bd9Sstevel@tonic-gate krb5_arcfour_decrypt(context, enc, hash, key, usage, ivec, input, output) 2707c478bd9Sstevel@tonic-gate krb5_context context; 2717c478bd9Sstevel@tonic-gate const struct krb5_enc_provider *enc; 2727c478bd9Sstevel@tonic-gate const struct krb5_hash_provider *hash; 2737c478bd9Sstevel@tonic-gate const krb5_keyblock *key; 2747c478bd9Sstevel@tonic-gate krb5_keyusage usage; 2757c478bd9Sstevel@tonic-gate const krb5_data *ivec; 2767c478bd9Sstevel@tonic-gate const krb5_data *input; 2777c478bd9Sstevel@tonic-gate krb5_data *output; 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate krb5_keyblock k1,k2,k3, *kptr; 2807c478bd9Sstevel@tonic-gate krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum; 2817c478bd9Sstevel@tonic-gate krb5_keyusage ms_usage; 282505d05c7Sgtb size_t keybytes, hashsize; 2837c478bd9Sstevel@tonic-gate krb5_error_code ret; 2847c478bd9Sstevel@tonic-gate 285505d05c7Sgtb keybytes = enc->keybytes; 286505d05c7Sgtb hashsize = hash->hashsize; 2877c478bd9Sstevel@tonic-gate 288*e753f464SWill Fiveash /* Verify input and output lengths. */ 289*e753f464SWill Fiveash if (input->length < hashsize + CONFOUNDERLENGTH) 290*e753f464SWill Fiveash return KRB5_BAD_MSIZE; 291*e753f464SWill Fiveash if (output->length < input->length - hashsize - CONFOUNDERLENGTH) 292*e753f464SWill Fiveash return KRB5_BAD_MSIZE; 293*e753f464SWill Fiveash 2947c478bd9Sstevel@tonic-gate bzero(&d2, sizeof(krb5_data)); 2957c478bd9Sstevel@tonic-gate bzero(&k2, sizeof(krb5_keyblock)); 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * d1 is the contents buffer for key k1. 2987c478bd9Sstevel@tonic-gate * k1 = HMAC(input_key, salt) 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate d1.length=keybytes; 3017c478bd9Sstevel@tonic-gate d1.data=MALLOC(d1.length); 3027c478bd9Sstevel@tonic-gate if (d1.data == NULL) 3037c478bd9Sstevel@tonic-gate return (ENOMEM); 3047c478bd9Sstevel@tonic-gate (void) bcopy(key, &k1, sizeof (krb5_keyblock)); 3057c478bd9Sstevel@tonic-gate k1.length=d1.length; 3067c478bd9Sstevel@tonic-gate k1.contents= (void *) d1.data; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * d2 is the contents of key 'k2', which is used to generate the 3107c478bd9Sstevel@tonic-gate * checksum field. 'd2' == 'd1' when not using the exportable 3117c478bd9Sstevel@tonic-gate * enctype. This is only needed when using the exportable 3127c478bd9Sstevel@tonic-gate * enctype. 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 3157c478bd9Sstevel@tonic-gate d2.length=keybytes; 3167c478bd9Sstevel@tonic-gate d2.data=MALLOC(d2.length); 3177c478bd9Sstevel@tonic-gate if (d2.data == NULL) { 3187c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 3197c478bd9Sstevel@tonic-gate return (ENOMEM); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate (void) bcopy(key, &k2, sizeof(krb5_keyblock)); 3227c478bd9Sstevel@tonic-gate k2.length=d2.length; 3237c478bd9Sstevel@tonic-gate k2.contents= (void *) d2.data; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * d3 will hold the contents of the final key used for the 3287c478bd9Sstevel@tonic-gate * encryption step. 'k3' is the key structure that has 'd3' 3297c478bd9Sstevel@tonic-gate * as its 'contents' field. 3307c478bd9Sstevel@tonic-gate * k3 = HMAC(k1, checksum) 3317c478bd9Sstevel@tonic-gate */ 3327c478bd9Sstevel@tonic-gate d3.length=keybytes; 3337c478bd9Sstevel@tonic-gate d3.data=MALLOC(d3.length); 3347c478bd9Sstevel@tonic-gate if (d3.data == NULL) { 3357c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 3367c478bd9Sstevel@tonic-gate if (d2.data) 3377c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 3387c478bd9Sstevel@tonic-gate return (ENOMEM); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate bcopy(key, &k3, sizeof(krb5_keyblock)); 3417c478bd9Sstevel@tonic-gate k3.length=d3.length; 3427c478bd9Sstevel@tonic-gate k3.contents= (void *) d3.data; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate salt.length=14; 3457c478bd9Sstevel@tonic-gate salt.data=MALLOC(salt.length); 3467c478bd9Sstevel@tonic-gate if(salt.data==NULL) { 3477c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 3487c478bd9Sstevel@tonic-gate if (d2.data) 3497c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 3507c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 3517c478bd9Sstevel@tonic-gate return (ENOMEM); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate ciphertext.length=input->length-hashsize; 3557c478bd9Sstevel@tonic-gate ciphertext.data=input->data+hashsize; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate plaintext.length=ciphertext.length; 3587c478bd9Sstevel@tonic-gate plaintext.data=MALLOC(plaintext.length); 3597c478bd9Sstevel@tonic-gate if (plaintext.data == NULL) { 3607c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 3617c478bd9Sstevel@tonic-gate if (d2.data) 3627c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 3637c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 3647c478bd9Sstevel@tonic-gate FREE(salt.data, salt.length); 3657c478bd9Sstevel@tonic-gate return (ENOMEM); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate checksum.length=hashsize; 3697c478bd9Sstevel@tonic-gate checksum.data=input->data; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* compute the salt */ 3727c478bd9Sstevel@tonic-gate ms_usage=krb5int_arcfour_translate_usage(usage); 3737c478bd9Sstevel@tonic-gate if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 3747c478bd9Sstevel@tonic-gate (void) strncpy(salt.data, l40, salt.length); 3757c478bd9Sstevel@tonic-gate salt.data[10]=ms_usage & 0xff; 3767c478bd9Sstevel@tonic-gate salt.data[11]=(ms_usage>>8) & 0xff; 3777c478bd9Sstevel@tonic-gate salt.data[12]=(ms_usage>>16) & 0xff; 3787c478bd9Sstevel@tonic-gate salt.data[13]=(ms_usage>>24) & 0xff; 3797c478bd9Sstevel@tonic-gate } else { 3807c478bd9Sstevel@tonic-gate salt.length=4; 3817c478bd9Sstevel@tonic-gate salt.data[0]=ms_usage & 0xff; 3827c478bd9Sstevel@tonic-gate salt.data[1]=(ms_usage>>8) & 0xff; 3837c478bd9Sstevel@tonic-gate salt.data[2]=(ms_usage>>16) & 0xff; 3847c478bd9Sstevel@tonic-gate salt.data[3]=(ms_usage>>24) & 0xff; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate #ifdef _KERNEL 3887c478bd9Sstevel@tonic-gate ret=krb5_hmac(context, key, &salt, &d1); 3897c478bd9Sstevel@tonic-gate #else 3907c478bd9Sstevel@tonic-gate ret=krb5_hmac(context, hash, key, 1, &salt, &d1); 3917c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 3927c478bd9Sstevel@tonic-gate if (ret) 3937c478bd9Sstevel@tonic-gate goto cleanup; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 3967c478bd9Sstevel@tonic-gate bcopy(k1.contents, k2.contents, d1.length); 3977c478bd9Sstevel@tonic-gate (void) memset(k1.contents+7, 0xab, 9); 3987c478bd9Sstevel@tonic-gate kptr = &k2; 3997c478bd9Sstevel@tonic-gate } else { 4007c478bd9Sstevel@tonic-gate kptr = &k1; 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate #ifdef _KERNEL 4047c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, &k1, &checksum, &d3); 4057c478bd9Sstevel@tonic-gate #else 4067c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, hash, &k1, 1, &checksum, &d3); 4077c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate if (ret) 4107c478bd9Sstevel@tonic-gate goto cleanup; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate ret=(*(enc->decrypt))(context, &k3, ivec, &ciphertext, &plaintext); 4137c478bd9Sstevel@tonic-gate if (ret) 4147c478bd9Sstevel@tonic-gate goto cleanup; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate #ifdef _KERNEL 4177c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, kptr, &plaintext, &d1); 4187c478bd9Sstevel@tonic-gate #else 4197c478bd9Sstevel@tonic-gate ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &d1); 4207c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if (ret) 4237c478bd9Sstevel@tonic-gate goto cleanup; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if (bcmp(checksum.data, d1.data, hashsize) != 0) { 4267c478bd9Sstevel@tonic-gate ret=KRB5KRB_AP_ERR_BAD_INTEGRITY; 4277c478bd9Sstevel@tonic-gate goto cleanup; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate bcopy(plaintext.data+CONFOUNDERLENGTH, output->data, 4317c478bd9Sstevel@tonic-gate (plaintext.length-CONFOUNDERLENGTH)); 4327c478bd9Sstevel@tonic-gate output->length=plaintext.length-CONFOUNDERLENGTH; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate cleanup: 4357c478bd9Sstevel@tonic-gate bzero(d1.data, d1.length); 4367c478bd9Sstevel@tonic-gate if (d2.data) { 4377c478bd9Sstevel@tonic-gate bzero(d2.data, d2.length); 4387c478bd9Sstevel@tonic-gate FREE(d2.data, d2.length); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate bzero(d3.data, d2.length); 4417c478bd9Sstevel@tonic-gate bzero(salt.data, salt.length); 4427c478bd9Sstevel@tonic-gate bzero(plaintext.data, plaintext.length); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate FREE(d1.data, d1.length); 4457c478bd9Sstevel@tonic-gate FREE(d3.data, d3.length); 4467c478bd9Sstevel@tonic-gate FREE(salt.data, salt.length); 4477c478bd9Sstevel@tonic-gate FREE(plaintext.data, plaintext.length); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate return (ret); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 452