xref: /illumos-gate/usr/src/uts/common/gssapi/mechs/krb5/crypto/arcfour/k5_arcfour.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7 
8 ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
9 This cipher is widely believed and has been tested to be equivalent
10 with the RC4 cipher from RSA Data Security, Inc.  (RC4 is a trademark
11 of RSA Data Security)
12 
13 */
14 #include <k5-int.h>
15 #include <arcfour.h>
16 
17 /* salt string used  for exportable ARCFOUR */
18 static const  char *l40 = "fortybits";
19 
20 void
krb5_arcfour_encrypt_length(enc,hash,inputlen,length)21 krb5_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 
36 krb5_keyusage
krb5int_arcfour_translate_usage(krb5_keyusage usage)37 krb5int_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 
71 krb5_error_code
krb5_arcfour_encrypt(context,enc,hash,key,usage,ivec,input,output)72 krb5_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 */
268 krb5_error_code
krb5_arcfour_decrypt(context,enc,hash,key,usage,ivec,input,output)269 krb5_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