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