xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/arcfour/k5_arcfour.c (revision e753f464d28e02e23aa93bd7d51d39fc56f79897)
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