1/*
2 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7
8ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
9This cipher is widely believed and has been tested to be equivalent
10with the RC4 cipher from RSA Data Security, Inc.  (RC4 is a trademark
11of RSA Data Security)
12
13*/
14#include <k5-int.h>
15#include <arcfour.h>
16
17/* salt string used  for exportable ARCFOUR */
18static const  char *l40 = "fortybits";
19
20void
21krb5_arcfour_encrypt_length(enc, hash, inputlen, length)
22     const struct krb5_enc_provider *enc;
23     const struct krb5_hash_provider *hash;
24     size_t inputlen;
25     size_t *length;
26{
27  size_t blocksize, hashsize;
28
29  blocksize = enc->block_size;
30  hashsize = hash->hashsize;
31
32  /* checksum + (confounder + inputlen, in even blocksize) */
33  *length = hashsize + krb5_roundup(8 + inputlen, blocksize);
34}
35
36krb5_keyusage
37krb5int_arcfour_translate_usage(krb5_keyusage usage)
38{
39  switch (usage) {
40  case 1:			/* AS-REQ PA-ENC-TIMESTAMP padata timestamp,  */
41    return 1;
42  case 2:			/* ticket from kdc */
43    return 2;
44  case 3:			/* as-rep encrypted part */
45    return 8;
46  case 4:			/* tgs-req authz data */
47    return 4;
48  case 5:			/* tgs-req authz data in subkey */
49    return 5;
50  case 6:			/* tgs-req authenticator cksum */
51    return 6;
52  case 7:			/* tgs-req authenticator */
53    return 7;
54  case 8:
55    return 8;
56  case 9:			/* tgs-rep encrypted with subkey */
57    return 8;
58  case 10:			/* ap-rep authentication cksum */
59    return 10;			/* xxx  Microsoft never uses this*/
60  case 11:			/* app-req authenticator */
61    return 11;
62  case 12:			/* app-rep encrypted part */
63    return 12;
64  case 23: /* sign wrap token*/
65    return 13;
66  default:
67      return usage;
68}
69}
70
71krb5_error_code
72krb5_arcfour_encrypt(context, enc, hash, key, usage, ivec, input, output)
73     krb5_context context;
74     const struct krb5_enc_provider *enc;
75     const struct krb5_hash_provider *hash;
76     const krb5_keyblock *key;
77     krb5_keyusage usage;
78     const krb5_data *ivec;
79     const krb5_data *input;
80     krb5_data *output;
81{
82  krb5_keyblock k1, k2, k3;
83  krb5_keyblock *kptr;
84  krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder;
85  krb5_keyusage ms_usage;
86  size_t keybytes, blocksize, hashsize;
87  krb5_error_code ret = 0;
88
89  blocksize = enc->block_size;
90  keybytes = enc->keybytes;
91  hashsize = hash->hashsize;
92
93  bzero(&d2, sizeof(krb5_data));
94  bzero(&k2, sizeof(krb5_keyblock));
95  /*
96   * d1 is the contents buffer for key k1.
97   * k1  = HMAC(input_key, salt)
98   */
99  d1.length=keybytes;
100  d1.data=MALLOC(d1.length);
101  if (d1.data == NULL)
102    return (ENOMEM);
103  bcopy(key, &k1, sizeof (krb5_keyblock));
104  k1.length=d1.length;
105  k1.contents= (void *) d1.data;
106
107  /*
108   * d2 is the contents of key 'k2', which is used to generate the
109   * checksum field.  'd2' == 'd1' when not using the exportable
110   * enctype.  This is only needed when using the exportable
111   * enctype.
112   */
113  if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) {
114	d2.length=keybytes;
115	d2.data=MALLOC(d2.length);
116	if (d2.data == NULL) {
117		FREE(d1.data, d1.length);
118		return (ENOMEM);
119	}
120	bcopy(key, &k2, sizeof (krb5_keyblock));
121	k2.length=d2.length;
122	k2.contents=(void *) d2.data;
123  }
124
125  /*
126   * d3 will hold the contents of the final key used for the
127   * encryption step.  'k3' is the key structure that has 'd3'
128   * as its 'contents' field.
129   * k3 = HMAC(k1, checksum)
130   */
131  d3.length=keybytes;
132  d3.data=MALLOC(d3.length);
133  if (d3.data == NULL) {
134    FREE(d1.data, d1.length);
135    if (d2.data)
136	FREE(d2.data, d2.length);
137    return (ENOMEM);
138  }
139  bcopy(key, &k3, sizeof (krb5_keyblock));
140  k3.length=d3.length;
141  k3.contents= (void *) d3.data;
142
143  salt.length=14;
144  salt.data=MALLOC(salt.length);
145
146  if (salt.data == NULL) {
147    FREE(d1.data, d1.length);
148    if (d2.data)
149	FREE(d2.data, d2.length);
150    FREE(d3.data, d3.length);
151    return (ENOMEM);
152  }
153
154  /* is "input" already blocksize aligned?  if it is, then we need this
155     step, otherwise we do not */
156  plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
157  plaintext.data=MALLOC(plaintext.length);
158
159  if (plaintext.data == NULL) {
160    FREE(d1.data, d1.length);
161    if (d2.data)
162	FREE(d2.data, d2.length);
163    FREE(d3.data, d3.length);
164    FREE(salt.data, salt.length);
165    return(ENOMEM);
166  }
167  bzero(plaintext.data, plaintext.length);
168
169  /* setup convienient pointers into the allocated data */
170  checksum.length=hashsize;
171  checksum.data=output->data;
172
173  ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
174  ciphertext.data=output->data+hashsize;
175
176  confounder.length=CONFOUNDERLENGTH;
177  confounder.data=plaintext.data;
178
179  output->length = plaintext.length+hashsize;
180
181  /* begin the encryption, computer K1 */
182  ms_usage=krb5int_arcfour_translate_usage(usage);
183  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
184    (void) strncpy(salt.data, l40, salt.length);
185    salt.data[10]=ms_usage & 0xff;
186    salt.data[11]=(ms_usage >> 8) & 0xff;
187    salt.data[12]=(ms_usage >> 16) & 0xff;
188    salt.data[13]=(ms_usage >> 24) & 0xff;
189  } else {
190    salt.length=4;
191    salt.data[0]=ms_usage & 0xff;
192    salt.data[1]=(ms_usage >> 8) & 0xff;
193    salt.data[2]=(ms_usage >> 16) & 0xff;
194    salt.data[3]=(ms_usage >> 24) & 0xff;
195  }
196
197#ifdef _KERNEL
198  ret = krb5_hmac(context, key, &salt, &d1);
199#else
200  ret = krb5_hmac(context, hash, key, 1, &salt, &d1);
201#endif /* _KERNEL */
202  if (ret != 0)
203	goto cleanup;
204
205  if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) {
206    bcopy(k1.contents, k2.contents, k2.length);
207    (void) memset(k1.contents+7, 0xab, 9);
208    kptr = &k2;
209  } else {
210    kptr = &k1;
211  }
212
213  /* create a confounder block */
214  ret=krb5_c_random_make_octets(context, &confounder);
215  bcopy(input->data, plaintext.data+confounder.length, input->length);
216  if (ret)
217    goto cleanup;
218
219  /*
220   * Compute the HMAC checksum field.
221   * checksum = HMAC(k1/k2, plaintext);
222   *    k2 used when key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP
223   */
224#ifdef _KERNEL
225  ret = krb5_hmac(context, kptr, &plaintext, &checksum);
226#else
227  ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &checksum);
228#endif /* _KERNEL */
229  if (ret)
230    goto cleanup;
231
232  /*
233   * The final encryption key is the HMAC of the checksum
234   * using k1
235   *
236   * k3 = HMAC(k1, checksum);
237   *  == or (in other terms) ==
238   * k3 = HMAC((HMAC(input_key,salt), HMAC(k1, plaintext));
239   */
240#ifdef _KERNEL
241  ret = krb5_hmac(context, &k1, &checksum, &d3);
242#else
243  ret = krb5_hmac(context, hash, &k1, 1,  &checksum, &d3);
244#endif /* _KERNEL */
245  if (ret)
246    goto cleanup;
247
248  ret = (*(enc->encrypt))(context, &k3, ivec, &plaintext, &ciphertext);
249
250 cleanup:
251  bzero(d1.data, d1.length);
252  if (d2.data) {
253	bzero(d2.data, d2.length);
254	FREE(d2.data, d2.length);
255  }
256  bzero(d3.data, d3.length);
257  bzero(salt.data, salt.length);
258  bzero(plaintext.data, plaintext.length);
259
260  FREE(d1.data, d1.length);
261  FREE(d3.data, d3.length);
262  FREE(salt.data, salt.length);
263  FREE(plaintext.data, plaintext.length);
264  return (ret);
265}
266
267/* This is the arcfour-hmac decryption routine */
268krb5_error_code
269krb5_arcfour_decrypt(context, enc, hash, key, usage, ivec, input, output)
270     krb5_context context;
271     const struct krb5_enc_provider *enc;
272     const struct krb5_hash_provider *hash;
273     const krb5_keyblock *key;
274     krb5_keyusage usage;
275     const krb5_data *ivec;
276     const krb5_data *input;
277     krb5_data *output;
278{
279  krb5_keyblock k1,k2,k3, *kptr;
280  krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum;
281  krb5_keyusage ms_usage;
282  size_t keybytes, hashsize;
283  krb5_error_code ret;
284
285  keybytes = enc->keybytes;
286  hashsize = hash->hashsize;
287
288  /* Verify input and output lengths. */
289  if (input->length < hashsize + CONFOUNDERLENGTH)
290	return KRB5_BAD_MSIZE;
291  if (output->length < input->length - hashsize - CONFOUNDERLENGTH)
292	return KRB5_BAD_MSIZE;
293
294  bzero(&d2, sizeof(krb5_data));
295  bzero(&k2, sizeof(krb5_keyblock));
296  /*
297   * d1 is the contents buffer for key k1.
298   * k1  = HMAC(input_key, salt)
299   */
300  d1.length=keybytes;
301  d1.data=MALLOC(d1.length);
302  if (d1.data == NULL)
303    return (ENOMEM);
304  (void) bcopy(key, &k1, sizeof (krb5_keyblock));
305  k1.length=d1.length;
306  k1.contents= (void *) d1.data;
307
308  /*
309   * d2 is the contents of key 'k2', which is used to generate the
310   * checksum field.  'd2' == 'd1' when not using the exportable
311   * enctype.  This is only needed when using the exportable
312   * enctype.
313   */
314  if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) {
315	d2.length=keybytes;
316	d2.data=MALLOC(d2.length);
317	if (d2.data == NULL) {
318		FREE(d1.data, d1.length);
319		return (ENOMEM);
320	}
321	(void) bcopy(key, &k2, sizeof(krb5_keyblock));
322	k2.length=d2.length;
323	k2.contents= (void *) d2.data;
324  }
325
326  /*
327   * d3 will hold the contents of the final key used for the
328   * encryption step.  'k3' is the key structure that has 'd3'
329   * as its 'contents' field.
330   * k3 = HMAC(k1, checksum)
331   */
332  d3.length=keybytes;
333  d3.data=MALLOC(d3.length);
334  if  (d3.data == NULL) {
335    FREE(d1.data, d1.length);
336    if (d2.data)
337	FREE(d2.data, d2.length);
338    return (ENOMEM);
339  }
340  bcopy(key, &k3, sizeof(krb5_keyblock));
341  k3.length=d3.length;
342  k3.contents= (void *) d3.data;
343
344  salt.length=14;
345  salt.data=MALLOC(salt.length);
346  if(salt.data==NULL) {
347    FREE(d1.data, d1.length);
348    if (d2.data)
349	FREE(d2.data, d2.length);
350    FREE(d3.data, d3.length);
351    return (ENOMEM);
352  }
353
354  ciphertext.length=input->length-hashsize;
355  ciphertext.data=input->data+hashsize;
356
357  plaintext.length=ciphertext.length;
358  plaintext.data=MALLOC(plaintext.length);
359  if (plaintext.data == NULL) {
360    FREE(d1.data, d1.length);
361    if (d2.data)
362	FREE(d2.data, d2.length);
363    FREE(d3.data, d3.length);
364    FREE(salt.data, salt.length);
365    return (ENOMEM);
366  }
367
368  checksum.length=hashsize;
369  checksum.data=input->data;
370
371  /* compute the salt */
372  ms_usage=krb5int_arcfour_translate_usage(usage);
373  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
374    (void) strncpy(salt.data, l40, salt.length);
375    salt.data[10]=ms_usage & 0xff;
376    salt.data[11]=(ms_usage>>8) & 0xff;
377    salt.data[12]=(ms_usage>>16) & 0xff;
378    salt.data[13]=(ms_usage>>24) & 0xff;
379  } else {
380    salt.length=4;
381    salt.data[0]=ms_usage & 0xff;
382    salt.data[1]=(ms_usage>>8) & 0xff;
383    salt.data[2]=(ms_usage>>16) & 0xff;
384    salt.data[3]=(ms_usage>>24) & 0xff;
385  }
386
387#ifdef _KERNEL
388  ret=krb5_hmac(context, key, &salt, &d1);
389#else
390  ret=krb5_hmac(context, hash, key, 1, &salt, &d1);
391#endif /* _KERNEL */
392  if (ret)
393    goto cleanup;
394
395  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
396    bcopy(k1.contents, k2.contents, d1.length);
397    (void) memset(k1.contents+7, 0xab, 9);
398    kptr = &k2;
399  } else {
400    kptr = &k1;
401  }
402
403#ifdef _KERNEL
404  ret = krb5_hmac(context, &k1, &checksum, &d3);
405#else
406  ret = krb5_hmac(context, hash, &k1, 1, &checksum, &d3);
407#endif /* _KERNEL */
408
409  if (ret)
410    goto cleanup;
411
412  ret=(*(enc->decrypt))(context, &k3, ivec, &ciphertext, &plaintext);
413  if (ret)
414    goto cleanup;
415
416#ifdef _KERNEL
417  ret = krb5_hmac(context, kptr, &plaintext, &d1);
418#else
419  ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &d1);
420#endif /* _KERNEL */
421
422  if (ret)
423    goto cleanup;
424
425  if (bcmp(checksum.data, d1.data, hashsize) != 0) {
426    ret=KRB5KRB_AP_ERR_BAD_INTEGRITY;
427    goto cleanup;
428  }
429
430  bcopy(plaintext.data+CONFOUNDERLENGTH, output->data,
431	 (plaintext.length-CONFOUNDERLENGTH));
432  output->length=plaintext.length-CONFOUNDERLENGTH;
433
434 cleanup:
435  bzero(d1.data, d1.length);
436  if (d2.data) {
437	bzero(d2.data, d2.length);
438	FREE(d2.data, d2.length);
439  }
440  bzero(d3.data, d2.length);
441  bzero(salt.data, salt.length);
442  bzero(plaintext.data, plaintext.length);
443
444  FREE(d1.data, d1.length);
445  FREE(d3.data, d3.length);
446  FREE(salt.data, salt.length);
447  FREE(plaintext.data, plaintext.length);
448
449  return (ret);
450}
451
452