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