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