xref: /freebsd/crypto/heimdal/lib/krb5/crypto.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*
2  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 
36 struct _krb5_key_usage {
37     unsigned usage;
38     struct _krb5_key_data key;
39 };
40 
41 
42 #ifndef HEIMDAL_SMALLER
43 #define DES3_OLD_ENCTYPE 1
44 #endif
45 
46 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
47 					unsigned, struct _krb5_key_data**);
48 static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
49 
50 static void free_key_schedule(krb5_context,
51 			      struct _krb5_key_data *,
52 			      struct _krb5_encryption_type *);
53 
54 /*
55  * Converts etype to a user readable string and sets as a side effect
56  * the krb5_error_message containing this string. Returns
57  * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
58  * which case the error code of the etype convesion is returned.
59  */
60 
61 static krb5_error_code
62 unsupported_enctype(krb5_context context, krb5_enctype etype)
63 {
64     krb5_error_code ret;
65     char *name;
66 
67     ret = krb5_enctype_to_string(context, etype, &name);
68     if (ret)
69 	return ret;
70 
71     krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
72 			   N_("Encryption type %s not supported", ""),
73 			   name);
74     free(name);
75     return KRB5_PROG_ETYPE_NOSUPP;
76 }
77 
78 /*
79  *
80  */
81 
82 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83 krb5_enctype_keysize(krb5_context context,
84 		     krb5_enctype type,
85 		     size_t *keysize)
86 {
87     struct _krb5_encryption_type *et = _krb5_find_enctype(type);
88     if(et == NULL) {
89         return unsupported_enctype (context, type);
90     }
91     *keysize = et->keytype->size;
92     return 0;
93 }
94 
95 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
96 krb5_enctype_keybits(krb5_context context,
97 		     krb5_enctype type,
98 		     size_t *keybits)
99 {
100     struct _krb5_encryption_type *et = _krb5_find_enctype(type);
101     if(et == NULL) {
102         return unsupported_enctype (context, type);
103     }
104     *keybits = et->keytype->bits;
105     return 0;
106 }
107 
108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
109 krb5_generate_random_keyblock(krb5_context context,
110 			      krb5_enctype type,
111 			      krb5_keyblock *key)
112 {
113     krb5_error_code ret;
114     struct _krb5_encryption_type *et = _krb5_find_enctype(type);
115     if(et == NULL) {
116         return unsupported_enctype (context, type);
117     }
118     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
119     if(ret)
120 	return ret;
121     key->keytype = type;
122     if(et->keytype->random_key)
123 	(*et->keytype->random_key)(context, key);
124     else
125 	krb5_generate_random_block(key->keyvalue.data,
126 				   key->keyvalue.length);
127     return 0;
128 }
129 
130 static krb5_error_code
131 _key_schedule(krb5_context context,
132 	      struct _krb5_key_data *key)
133 {
134     krb5_error_code ret;
135     struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
136     struct _krb5_key_type *kt;
137 
138     if (et == NULL) {
139         return unsupported_enctype (context,
140                                key->key->keytype);
141     }
142 
143     kt = et->keytype;
144 
145     if(kt->schedule == NULL)
146 	return 0;
147     if (key->schedule != NULL)
148 	return 0;
149     ALLOC(key->schedule, 1);
150     if(key->schedule == NULL) {
151 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
152 	return ENOMEM;
153     }
154     ret = krb5_data_alloc(key->schedule, kt->schedule_size);
155     if(ret) {
156 	free(key->schedule);
157 	key->schedule = NULL;
158 	return ret;
159     }
160     (*kt->schedule)(context, kt, key);
161     return 0;
162 }
163 
164 /************************************************************
165  *                                                          *
166  ************************************************************/
167 
168 static krb5_error_code
169 SHA1_checksum(krb5_context context,
170 	      struct _krb5_key_data *key,
171 	      const void *data,
172 	      size_t len,
173 	      unsigned usage,
174 	      Checksum *C)
175 {
176     if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
177 	krb5_abortx(context, "sha1 checksum failed");
178     return 0;
179 }
180 
181 /* HMAC according to RFC2104 */
182 krb5_error_code
183 _krb5_internal_hmac(krb5_context context,
184 		    struct _krb5_checksum_type *cm,
185 		    const void *data,
186 		    size_t len,
187 		    unsigned usage,
188 		    struct _krb5_key_data *keyblock,
189 		    Checksum *result)
190 {
191     unsigned char *ipad, *opad;
192     unsigned char *key;
193     size_t key_len;
194     size_t i;
195 
196     ipad = malloc(cm->blocksize + len);
197     if (ipad == NULL)
198 	return ENOMEM;
199     opad = malloc(cm->blocksize + cm->checksumsize);
200     if (opad == NULL) {
201 	free(ipad);
202 	return ENOMEM;
203     }
204     memset(ipad, 0x36, cm->blocksize);
205     memset(opad, 0x5c, cm->blocksize);
206 
207     if(keyblock->key->keyvalue.length > cm->blocksize){
208 	(*cm->checksum)(context,
209 			keyblock,
210 			keyblock->key->keyvalue.data,
211 			keyblock->key->keyvalue.length,
212 			usage,
213 			result);
214 	key = result->checksum.data;
215 	key_len = result->checksum.length;
216     } else {
217 	key = keyblock->key->keyvalue.data;
218 	key_len = keyblock->key->keyvalue.length;
219     }
220     for(i = 0; i < key_len; i++){
221 	ipad[i] ^= key[i];
222 	opad[i] ^= key[i];
223     }
224     memcpy(ipad + cm->blocksize, data, len);
225     (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
226 		    usage, result);
227     memcpy(opad + cm->blocksize, result->checksum.data,
228 	   result->checksum.length);
229     (*cm->checksum)(context, keyblock, opad,
230 		    cm->blocksize + cm->checksumsize, usage, result);
231     memset(ipad, 0, cm->blocksize + len);
232     free(ipad);
233     memset(opad, 0, cm->blocksize + cm->checksumsize);
234     free(opad);
235 
236     return 0;
237 }
238 
239 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240 krb5_hmac(krb5_context context,
241 	  krb5_cksumtype cktype,
242 	  const void *data,
243 	  size_t len,
244 	  unsigned usage,
245 	  krb5_keyblock *key,
246 	  Checksum *result)
247 {
248     struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
249     struct _krb5_key_data kd;
250     krb5_error_code ret;
251 
252     if (c == NULL) {
253 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
254 				N_("checksum type %d not supported", ""),
255 				cktype);
256 	return KRB5_PROG_SUMTYPE_NOSUPP;
257     }
258 
259     kd.key = key;
260     kd.schedule = NULL;
261 
262     ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result);
263 
264     if (kd.schedule)
265 	krb5_free_data(context, kd.schedule);
266 
267     return ret;
268 }
269 
270 krb5_error_code
271 _krb5_SP_HMAC_SHA1_checksum(krb5_context context,
272 			    struct _krb5_key_data *key,
273 			    const void *data,
274 			    size_t len,
275 			    unsigned usage,
276 			    Checksum *result)
277 {
278     struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
279     Checksum res;
280     char sha1_data[20];
281     krb5_error_code ret;
282 
283     res.checksum.data = sha1_data;
284     res.checksum.length = sizeof(sha1_data);
285 
286     ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res);
287     if (ret)
288 	krb5_abortx(context, "hmac failed");
289     memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
290     return 0;
291 }
292 
293 struct _krb5_checksum_type _krb5_checksum_sha1 = {
294     CKSUMTYPE_SHA1,
295     "sha1",
296     64,
297     20,
298     F_CPROOF,
299     SHA1_checksum,
300     NULL
301 };
302 
303 struct _krb5_checksum_type *
304 _krb5_find_checksum(krb5_cksumtype type)
305 {
306     int i;
307     for(i = 0; i < _krb5_num_checksums; i++)
308 	if(_krb5_checksum_types[i]->type == type)
309 	    return _krb5_checksum_types[i];
310     return NULL;
311 }
312 
313 static krb5_error_code
314 get_checksum_key(krb5_context context,
315 		 krb5_crypto crypto,
316 		 unsigned usage,  /* not krb5_key_usage */
317 		 struct _krb5_checksum_type *ct,
318 		 struct _krb5_key_data **key)
319 {
320     krb5_error_code ret = 0;
321 
322     if(ct->flags & F_DERIVED)
323 	ret = _get_derived_key(context, crypto, usage, key);
324     else if(ct->flags & F_VARIANT) {
325 	size_t i;
326 
327 	*key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
328 	if(*key == NULL) {
329 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
330 	    return ENOMEM;
331 	}
332 	ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
333 	if(ret)
334 	    return ret;
335 	for(i = 0; i < (*key)->key->keyvalue.length; i++)
336 	    ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
337     } else {
338 	*key = &crypto->key;
339     }
340     if(ret == 0)
341 	ret = _key_schedule(context, *key);
342     return ret;
343 }
344 
345 static krb5_error_code
346 create_checksum (krb5_context context,
347 		 struct _krb5_checksum_type *ct,
348 		 krb5_crypto crypto,
349 		 unsigned usage,
350 		 void *data,
351 		 size_t len,
352 		 Checksum *result)
353 {
354     krb5_error_code ret;
355     struct _krb5_key_data *dkey;
356     int keyed_checksum;
357 
358     if (ct->flags & F_DISABLED) {
359 	krb5_clear_error_message (context);
360 	return KRB5_PROG_SUMTYPE_NOSUPP;
361     }
362     keyed_checksum = (ct->flags & F_KEYED) != 0;
363     if(keyed_checksum && crypto == NULL) {
364 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
365 				N_("Checksum type %s is keyed but no "
366 				   "crypto context (key) was passed in", ""),
367 				ct->name);
368 	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
369     }
370     if(keyed_checksum) {
371 	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
372 	if (ret)
373 	    return ret;
374     } else
375 	dkey = NULL;
376     result->cksumtype = ct->type;
377     ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
378     if (ret)
379 	return (ret);
380     return (*ct->checksum)(context, dkey, data, len, usage, result);
381 }
382 
383 static int
384 arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
385 {
386     return (ct->type == CKSUMTYPE_HMAC_MD5) &&
387 	(crypto->key.key->keytype == KEYTYPE_ARCFOUR);
388 }
389 
390 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
391 krb5_create_checksum(krb5_context context,
392 		     krb5_crypto crypto,
393 		     krb5_key_usage usage,
394 		     int type,
395 		     void *data,
396 		     size_t len,
397 		     Checksum *result)
398 {
399     struct _krb5_checksum_type *ct = NULL;
400     unsigned keyusage;
401 
402     /* type 0 -> pick from crypto */
403     if (type) {
404 	ct = _krb5_find_checksum(type);
405     } else if (crypto) {
406 	ct = crypto->et->keyed_checksum;
407 	if (ct == NULL)
408 	    ct = crypto->et->checksum;
409     }
410 
411     if(ct == NULL) {
412 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
413 				N_("checksum type %d not supported", ""),
414 				type);
415 	return KRB5_PROG_SUMTYPE_NOSUPP;
416     }
417 
418     if (arcfour_checksum_p(ct, crypto)) {
419 	keyusage = usage;
420 	_krb5_usage2arcfour(context, &keyusage);
421     } else
422 	keyusage = CHECKSUM_USAGE(usage);
423 
424     return create_checksum(context, ct, crypto, keyusage,
425 			   data, len, result);
426 }
427 
428 static krb5_error_code
429 verify_checksum(krb5_context context,
430 		krb5_crypto crypto,
431 		unsigned usage, /* not krb5_key_usage */
432 		void *data,
433 		size_t len,
434 		Checksum *cksum)
435 {
436     krb5_error_code ret;
437     struct _krb5_key_data *dkey;
438     int keyed_checksum;
439     Checksum c;
440     struct _krb5_checksum_type *ct;
441 
442     ct = _krb5_find_checksum(cksum->cksumtype);
443     if (ct == NULL || (ct->flags & F_DISABLED)) {
444 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
445 				N_("checksum type %d not supported", ""),
446 				cksum->cksumtype);
447 	return KRB5_PROG_SUMTYPE_NOSUPP;
448     }
449     if(ct->checksumsize != cksum->checksum.length) {
450 	krb5_clear_error_message (context);
451 	krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
452 			       N_("Decrypt integrity check failed for checksum type %s, "
453 				  "length was %u, expected %u", ""),
454 			       ct->name, (unsigned)cksum->checksum.length,
455 			       (unsigned)ct->checksumsize);
456 
457 	return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
458     }
459     keyed_checksum = (ct->flags & F_KEYED) != 0;
460     if(keyed_checksum) {
461 	struct _krb5_checksum_type *kct;
462 	if (crypto == NULL) {
463 	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
464 				   N_("Checksum type %s is keyed but no "
465 				      "crypto context (key) was passed in", ""),
466 				   ct->name);
467 	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
468 	}
469 	kct = crypto->et->keyed_checksum;
470 	if (kct == NULL || kct->type != ct->type) {
471 	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
472 				   N_("Checksum type %s is keyed, but "
473 				      "the key type %s passed didnt have that checksum "
474 				      "type as the keyed type", ""),
475 				    ct->name, crypto->et->name);
476 	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
477 	}
478 
479 	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
480 	if (ret)
481 	    return ret;
482     } else
483 	dkey = NULL;
484 
485     /*
486      * If checksum have a verify function, lets use that instead of
487      * calling ->checksum and then compare result.
488      */
489 
490     if(ct->verify) {
491 	ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
492 	if (ret)
493 	    krb5_set_error_message(context, ret,
494 				   N_("Decrypt integrity check failed for checksum "
495 				      "type %s, key type %s", ""),
496 				   ct->name, (crypto != NULL)? crypto->et->name : "(none)");
497 	return ret;
498     }
499 
500     ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
501     if (ret)
502 	return ret;
503 
504     ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
505     if (ret) {
506 	krb5_data_free(&c.checksum);
507 	return ret;
508     }
509 
510     if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
511 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
512 	krb5_set_error_message(context, ret,
513 			       N_("Decrypt integrity check failed for checksum "
514 				  "type %s, key type %s", ""),
515 			       ct->name, crypto ? crypto->et->name : "(unkeyed)");
516     } else {
517 	ret = 0;
518     }
519     krb5_data_free (&c.checksum);
520     return ret;
521 }
522 
523 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
524 krb5_verify_checksum(krb5_context context,
525 		     krb5_crypto crypto,
526 		     krb5_key_usage usage,
527 		     void *data,
528 		     size_t len,
529 		     Checksum *cksum)
530 {
531     struct _krb5_checksum_type *ct;
532     unsigned keyusage;
533 
534     ct = _krb5_find_checksum(cksum->cksumtype);
535     if(ct == NULL) {
536 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
537 				N_("checksum type %d not supported", ""),
538 				cksum->cksumtype);
539 	return KRB5_PROG_SUMTYPE_NOSUPP;
540     }
541 
542     if (arcfour_checksum_p(ct, crypto)) {
543 	keyusage = usage;
544 	_krb5_usage2arcfour(context, &keyusage);
545     } else
546 	keyusage = CHECKSUM_USAGE(usage);
547 
548     return verify_checksum(context, crypto, keyusage,
549 			   data, len, cksum);
550 }
551 
552 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
553 krb5_crypto_get_checksum_type(krb5_context context,
554                               krb5_crypto crypto,
555 			      krb5_cksumtype *type)
556 {
557     struct _krb5_checksum_type *ct = NULL;
558 
559     if (crypto != NULL) {
560         ct = crypto->et->keyed_checksum;
561         if (ct == NULL)
562             ct = crypto->et->checksum;
563     }
564 
565     if (ct == NULL) {
566 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
567 				N_("checksum type not found", ""));
568         return KRB5_PROG_SUMTYPE_NOSUPP;
569     }
570 
571     *type = ct->type;
572 
573     return 0;
574 }
575 
576 
577 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
578 krb5_checksumsize(krb5_context context,
579 		  krb5_cksumtype type,
580 		  size_t *size)
581 {
582     struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
583     if(ct == NULL) {
584 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
585 				N_("checksum type %d not supported", ""),
586 				type);
587 	return KRB5_PROG_SUMTYPE_NOSUPP;
588     }
589     *size = ct->checksumsize;
590     return 0;
591 }
592 
593 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
594 krb5_checksum_is_keyed(krb5_context context,
595 		       krb5_cksumtype type)
596 {
597     struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
598     if(ct == NULL) {
599 	if (context)
600 	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
601 				    N_("checksum type %d not supported", ""),
602 				    type);
603 	return KRB5_PROG_SUMTYPE_NOSUPP;
604     }
605     return ct->flags & F_KEYED;
606 }
607 
608 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
609 krb5_checksum_is_collision_proof(krb5_context context,
610 				 krb5_cksumtype type)
611 {
612     struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
613     if(ct == NULL) {
614 	if (context)
615 	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
616 				    N_("checksum type %d not supported", ""),
617 				    type);
618 	return KRB5_PROG_SUMTYPE_NOSUPP;
619     }
620     return ct->flags & F_CPROOF;
621 }
622 
623 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
624 krb5_checksum_disable(krb5_context context,
625 		      krb5_cksumtype type)
626 {
627     struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
628     if(ct == NULL) {
629 	if (context)
630 	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
631 				    N_("checksum type %d not supported", ""),
632 				    type);
633 	return KRB5_PROG_SUMTYPE_NOSUPP;
634     }
635     ct->flags |= F_DISABLED;
636     return 0;
637 }
638 
639 /************************************************************
640  *                                                          *
641  ************************************************************/
642 
643 struct _krb5_encryption_type *
644 _krb5_find_enctype(krb5_enctype type)
645 {
646     int i;
647     for(i = 0; i < _krb5_num_etypes; i++)
648 	if(_krb5_etypes[i]->type == type)
649 	    return _krb5_etypes[i];
650     return NULL;
651 }
652 
653 
654 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
655 krb5_enctype_to_string(krb5_context context,
656 		       krb5_enctype etype,
657 		       char **string)
658 {
659     struct _krb5_encryption_type *e;
660     e = _krb5_find_enctype(etype);
661     if(e == NULL) {
662 	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
663 				N_("encryption type %d not supported", ""),
664 				etype);
665 	*string = NULL;
666 	return KRB5_PROG_ETYPE_NOSUPP;
667     }
668     *string = strdup(e->name);
669     if(*string == NULL) {
670 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
671 	return ENOMEM;
672     }
673     return 0;
674 }
675 
676 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
677 krb5_string_to_enctype(krb5_context context,
678 		       const char *string,
679 		       krb5_enctype *etype)
680 {
681     int i;
682     for(i = 0; i < _krb5_num_etypes; i++)
683 	if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
684 	    *etype = _krb5_etypes[i]->type;
685 	    return 0;
686 	}
687     krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
688 			    N_("encryption type %s not supported", ""),
689 			    string);
690     return KRB5_PROG_ETYPE_NOSUPP;
691 }
692 
693 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
694 krb5_enctype_to_keytype(krb5_context context,
695 			krb5_enctype etype,
696 			krb5_keytype *keytype)
697 {
698     struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
699     if(e == NULL) {
700         return unsupported_enctype (context, etype);
701     }
702     *keytype = e->keytype->type; /* XXX */
703     return 0;
704 }
705 
706 /**
707  * Check if a enctype is valid, return 0 if it is.
708  *
709  * @param context Kerberos context
710  * @param etype enctype to check if its valid or not
711  *
712  * @return Return an error code for an failure or 0 on success (enctype valid).
713  * @ingroup krb5_crypto
714  */
715 
716 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
717 krb5_enctype_valid(krb5_context context,
718 		   krb5_enctype etype)
719 {
720     struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
721     if(e && (e->flags & F_DISABLED) == 0)
722 	return 0;
723     if (context == NULL)
724 	return KRB5_PROG_ETYPE_NOSUPP;
725     if(e == NULL) {
726         return unsupported_enctype (context, etype);
727     }
728     /* Must be (e->flags & F_DISABLED) */
729     krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
730 			    N_("encryption type %s is disabled", ""),
731 			    e->name);
732     return KRB5_PROG_ETYPE_NOSUPP;
733 }
734 
735 /**
736  * Return the coresponding encryption type for a checksum type.
737  *
738  * @param context Kerberos context
739  * @param ctype The checksum type to get the result enctype for
740  * @param etype The returned encryption, when the matching etype is
741  * not found, etype is set to ETYPE_NULL.
742  *
743  * @return Return an error code for an failure or 0 on success.
744  * @ingroup krb5_crypto
745  */
746 
747 
748 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
749 krb5_cksumtype_to_enctype(krb5_context context,
750 			  krb5_cksumtype ctype,
751 			  krb5_enctype *etype)
752 {
753     int i;
754 
755     *etype = ETYPE_NULL;
756 
757     for(i = 0; i < _krb5_num_etypes; i++) {
758 	if(_krb5_etypes[i]->keyed_checksum &&
759 	   _krb5_etypes[i]->keyed_checksum->type == ctype)
760 	    {
761 		*etype = _krb5_etypes[i]->type;
762 		return 0;
763 	    }
764     }
765 
766     krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
767 			    N_("checksum type %d not supported", ""),
768 			    (int)ctype);
769     return KRB5_PROG_SUMTYPE_NOSUPP;
770 }
771 
772 
773 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
774 krb5_cksumtype_valid(krb5_context context,
775 		     krb5_cksumtype ctype)
776 {
777     struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
778     if (c == NULL) {
779 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
780 				N_("checksum type %d not supported", ""),
781 				ctype);
782 	return KRB5_PROG_SUMTYPE_NOSUPP;
783     }
784     if (c->flags & F_DISABLED) {
785 	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
786 				N_("checksum type %s is disabled", ""),
787 				c->name);
788 	return KRB5_PROG_SUMTYPE_NOSUPP;
789     }
790     return 0;
791 }
792 
793 
794 static krb5_boolean
795 derived_crypto(krb5_context context,
796 	       krb5_crypto crypto)
797 {
798     return (crypto->et->flags & F_DERIVED) != 0;
799 }
800 
801 static krb5_boolean
802 special_crypto(krb5_context context,
803 	       krb5_crypto crypto)
804 {
805     return (crypto->et->flags & F_SPECIAL) != 0;
806 }
807 
808 #define CHECKSUMSIZE(C) ((C)->checksumsize)
809 #define CHECKSUMTYPE(C) ((C)->type)
810 
811 static krb5_error_code
812 encrypt_internal_derived(krb5_context context,
813 			 krb5_crypto crypto,
814 			 unsigned usage,
815 			 const void *data,
816 			 size_t len,
817 			 krb5_data *result,
818 			 void *ivec)
819 {
820     size_t sz, block_sz, checksum_sz, total_sz;
821     Checksum cksum;
822     unsigned char *p, *q;
823     krb5_error_code ret;
824     struct _krb5_key_data *dkey;
825     const struct _krb5_encryption_type *et = crypto->et;
826 
827     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
828 
829     sz = et->confoundersize + len;
830     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
831     total_sz = block_sz + checksum_sz;
832     p = calloc(1, total_sz);
833     if(p == NULL) {
834 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
835 	return ENOMEM;
836     }
837 
838     q = p;
839     krb5_generate_random_block(q, et->confoundersize); /* XXX */
840     q += et->confoundersize;
841     memcpy(q, data, len);
842 
843     ret = create_checksum(context,
844 			  et->keyed_checksum,
845 			  crypto,
846 			  INTEGRITY_USAGE(usage),
847 			  p,
848 			  block_sz,
849 			  &cksum);
850     if(ret == 0 && cksum.checksum.length != checksum_sz) {
851 	free_Checksum (&cksum);
852 	krb5_clear_error_message (context);
853 	ret = KRB5_CRYPTO_INTERNAL;
854     }
855     if(ret)
856 	goto fail;
857     memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
858     free_Checksum (&cksum);
859     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
860     if(ret)
861 	goto fail;
862     ret = _key_schedule(context, dkey);
863     if(ret)
864 	goto fail;
865     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
866     if (ret)
867 	goto fail;
868     result->data = p;
869     result->length = total_sz;
870     return 0;
871  fail:
872     memset(p, 0, total_sz);
873     free(p);
874     return ret;
875 }
876 
877 
878 static krb5_error_code
879 encrypt_internal(krb5_context context,
880 		 krb5_crypto crypto,
881 		 const void *data,
882 		 size_t len,
883 		 krb5_data *result,
884 		 void *ivec)
885 {
886     size_t sz, block_sz, checksum_sz;
887     Checksum cksum;
888     unsigned char *p, *q;
889     krb5_error_code ret;
890     const struct _krb5_encryption_type *et = crypto->et;
891 
892     checksum_sz = CHECKSUMSIZE(et->checksum);
893 
894     sz = et->confoundersize + checksum_sz + len;
895     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
896     p = calloc(1, block_sz);
897     if(p == NULL) {
898 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
899 	return ENOMEM;
900     }
901 
902     q = p;
903     krb5_generate_random_block(q, et->confoundersize); /* XXX */
904     q += et->confoundersize;
905     memset(q, 0, checksum_sz);
906     q += checksum_sz;
907     memcpy(q, data, len);
908 
909     ret = create_checksum(context,
910 			  et->checksum,
911 			  crypto,
912 			  0,
913 			  p,
914 			  block_sz,
915 			  &cksum);
916     if(ret == 0 && cksum.checksum.length != checksum_sz) {
917 	krb5_clear_error_message (context);
918 	free_Checksum(&cksum);
919 	ret = KRB5_CRYPTO_INTERNAL;
920     }
921     if(ret)
922 	goto fail;
923     memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
924     free_Checksum(&cksum);
925     ret = _key_schedule(context, &crypto->key);
926     if(ret)
927 	goto fail;
928     ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
929     if (ret) {
930 	memset(p, 0, block_sz);
931 	free(p);
932 	return ret;
933     }
934     result->data = p;
935     result->length = block_sz;
936     return 0;
937  fail:
938     memset(p, 0, block_sz);
939     free(p);
940     return ret;
941 }
942 
943 static krb5_error_code
944 encrypt_internal_special(krb5_context context,
945 			 krb5_crypto crypto,
946 			 int usage,
947 			 const void *data,
948 			 size_t len,
949 			 krb5_data *result,
950 			 void *ivec)
951 {
952     struct _krb5_encryption_type *et = crypto->et;
953     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
954     size_t sz = len + cksum_sz + et->confoundersize;
955     char *tmp, *p;
956     krb5_error_code ret;
957 
958     tmp = malloc (sz);
959     if (tmp == NULL) {
960 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
961 	return ENOMEM;
962     }
963     p = tmp;
964     memset (p, 0, cksum_sz);
965     p += cksum_sz;
966     krb5_generate_random_block(p, et->confoundersize);
967     p += et->confoundersize;
968     memcpy (p, data, len);
969     ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
970     if (ret) {
971 	memset(tmp, 0, sz);
972 	free(tmp);
973 	return ret;
974     }
975     result->data   = tmp;
976     result->length = sz;
977     return 0;
978 }
979 
980 static krb5_error_code
981 decrypt_internal_derived(krb5_context context,
982 			 krb5_crypto crypto,
983 			 unsigned usage,
984 			 void *data,
985 			 size_t len,
986 			 krb5_data *result,
987 			 void *ivec)
988 {
989     size_t checksum_sz;
990     Checksum cksum;
991     unsigned char *p;
992     krb5_error_code ret;
993     struct _krb5_key_data *dkey;
994     struct _krb5_encryption_type *et = crypto->et;
995     unsigned long l;
996 
997     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
998     if (len < checksum_sz + et->confoundersize) {
999 	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1000 			       N_("Encrypted data shorter then "
1001 				  "checksum + confunder", ""));
1002 	return KRB5_BAD_MSIZE;
1003     }
1004 
1005     if (((len - checksum_sz) % et->padsize) != 0) {
1006 	krb5_clear_error_message(context);
1007 	return KRB5_BAD_MSIZE;
1008     }
1009 
1010     p = malloc(len);
1011     if(len != 0 && p == NULL) {
1012 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1013 	return ENOMEM;
1014     }
1015     memcpy(p, data, len);
1016 
1017     len -= checksum_sz;
1018 
1019     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1020     if(ret) {
1021 	free(p);
1022 	return ret;
1023     }
1024     ret = _key_schedule(context, dkey);
1025     if(ret) {
1026 	free(p);
1027 	return ret;
1028     }
1029     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1030     if (ret) {
1031 	free(p);
1032 	return ret;
1033     }
1034 
1035     cksum.checksum.data   = p + len;
1036     cksum.checksum.length = checksum_sz;
1037     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1038 
1039     ret = verify_checksum(context,
1040 			  crypto,
1041 			  INTEGRITY_USAGE(usage),
1042 			  p,
1043 			  len,
1044 			  &cksum);
1045     if(ret) {
1046 	free(p);
1047 	return ret;
1048     }
1049     l = len - et->confoundersize;
1050     memmove(p, p + et->confoundersize, l);
1051     result->data = realloc(p, l);
1052     if(result->data == NULL && l != 0) {
1053 	free(p);
1054 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1055 	return ENOMEM;
1056     }
1057     result->length = l;
1058     return 0;
1059 }
1060 
1061 static krb5_error_code
1062 decrypt_internal(krb5_context context,
1063 		 krb5_crypto crypto,
1064 		 void *data,
1065 		 size_t len,
1066 		 krb5_data *result,
1067 		 void *ivec)
1068 {
1069     krb5_error_code ret;
1070     unsigned char *p;
1071     Checksum cksum;
1072     size_t checksum_sz, l;
1073     struct _krb5_encryption_type *et = crypto->et;
1074 
1075     if ((len % et->padsize) != 0) {
1076 	krb5_clear_error_message(context);
1077 	return KRB5_BAD_MSIZE;
1078     }
1079     checksum_sz = CHECKSUMSIZE(et->checksum);
1080     if (len < checksum_sz + et->confoundersize) {
1081 	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1082 			       N_("Encrypted data shorter then "
1083 				  "checksum + confunder", ""));
1084 	return KRB5_BAD_MSIZE;
1085     }
1086 
1087     p = malloc(len);
1088     if(len != 0 && p == NULL) {
1089 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1090 	return ENOMEM;
1091     }
1092     memcpy(p, data, len);
1093 
1094     ret = _key_schedule(context, &crypto->key);
1095     if(ret) {
1096 	free(p);
1097 	return ret;
1098     }
1099     ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1100     if (ret) {
1101 	free(p);
1102 	return ret;
1103     }
1104     ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1105     if(ret) {
1106  	free(p);
1107  	return ret;
1108     }
1109     memset(p + et->confoundersize, 0, checksum_sz);
1110     cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1111     ret = verify_checksum(context, NULL, 0, p, len, &cksum);
1112     free_Checksum(&cksum);
1113     if(ret) {
1114 	free(p);
1115 	return ret;
1116     }
1117     l = len - et->confoundersize - checksum_sz;
1118     memmove(p, p + et->confoundersize + checksum_sz, l);
1119     result->data = realloc(p, l);
1120     if(result->data == NULL && l != 0) {
1121 	free(p);
1122 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1123 	return ENOMEM;
1124     }
1125     result->length = l;
1126     return 0;
1127 }
1128 
1129 static krb5_error_code
1130 decrypt_internal_special(krb5_context context,
1131 			 krb5_crypto crypto,
1132 			 int usage,
1133 			 void *data,
1134 			 size_t len,
1135 			 krb5_data *result,
1136 			 void *ivec)
1137 {
1138     struct _krb5_encryption_type *et = crypto->et;
1139     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1140     size_t sz = len - cksum_sz - et->confoundersize;
1141     unsigned char *p;
1142     krb5_error_code ret;
1143 
1144     if ((len % et->padsize) != 0) {
1145 	krb5_clear_error_message(context);
1146 	return KRB5_BAD_MSIZE;
1147     }
1148     if (len < cksum_sz + et->confoundersize) {
1149 	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1150 			       N_("Encrypted data shorter then "
1151 				  "checksum + confunder", ""));
1152 	return KRB5_BAD_MSIZE;
1153     }
1154 
1155     p = malloc (len);
1156     if (p == NULL) {
1157 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1158 	return ENOMEM;
1159     }
1160     memcpy(p, data, len);
1161 
1162     ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1163     if (ret) {
1164 	free(p);
1165 	return ret;
1166     }
1167 
1168     memmove (p, p + cksum_sz + et->confoundersize, sz);
1169     result->data = realloc(p, sz);
1170     if(result->data == NULL && sz != 0) {
1171 	free(p);
1172 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1173 	return ENOMEM;
1174     }
1175     result->length = sz;
1176     return 0;
1177 }
1178 
1179 static krb5_crypto_iov *
1180 find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type)
1181 {
1182     size_t i;
1183     for (i = 0; i < num_data; i++)
1184 	if (data[i].flags == type)
1185 	    return &data[i];
1186     return NULL;
1187 }
1188 
1189 /**
1190  * Inline encrypt a kerberos message
1191  *
1192  * @param context Kerberos context
1193  * @param crypto Kerberos crypto context
1194  * @param usage Key usage for this buffer
1195  * @param data array of buffers to process
1196  * @param num_data length of array
1197  * @param ivec initial cbc/cts vector
1198  *
1199  * @return Return an error code or 0.
1200  * @ingroup krb5_crypto
1201  *
1202  * Kerberos encrypted data look like this:
1203  *
1204  * 1. KRB5_CRYPTO_TYPE_HEADER
1205  * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1206  *    KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1207  *    have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1208  *    commonly used headers and trailers.
1209  * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1210  * 4. KRB5_CRYPTO_TYPE_TRAILER
1211  */
1212 
1213 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1214 krb5_encrypt_iov_ivec(krb5_context context,
1215 		      krb5_crypto crypto,
1216 		      unsigned usage,
1217 		      krb5_crypto_iov *data,
1218 		      int num_data,
1219 		      void *ivec)
1220 {
1221     size_t headersz, trailersz, len;
1222     int i;
1223     size_t sz, block_sz, pad_sz;
1224     Checksum cksum;
1225     unsigned char *p, *q;
1226     krb5_error_code ret;
1227     struct _krb5_key_data *dkey;
1228     const struct _krb5_encryption_type *et = crypto->et;
1229     krb5_crypto_iov *tiv, *piv, *hiv;
1230 
1231     if (num_data < 0) {
1232         krb5_clear_error_message(context);
1233 	return KRB5_CRYPTO_INTERNAL;
1234     }
1235 
1236     if(!derived_crypto(context, crypto)) {
1237 	krb5_clear_error_message(context);
1238 	return KRB5_CRYPTO_INTERNAL;
1239     }
1240 
1241     headersz = et->confoundersize;
1242     trailersz = CHECKSUMSIZE(et->keyed_checksum);
1243 
1244     for (len = 0, i = 0; i < num_data; i++) {
1245 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1246 	    continue;
1247 	len += data[i].data.length;
1248     }
1249 
1250     sz = headersz + len;
1251     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1252 
1253     pad_sz = block_sz - sz;
1254 
1255     /* header */
1256 
1257     hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1258     if (hiv == NULL || hiv->data.length != headersz)
1259 	return KRB5_BAD_MSIZE;
1260 
1261     krb5_generate_random_block(hiv->data.data, hiv->data.length);
1262 
1263     /* padding */
1264     piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1265     /* its ok to have no TYPE_PADDING if there is no padding */
1266     if (piv == NULL && pad_sz != 0)
1267 	return KRB5_BAD_MSIZE;
1268     if (piv) {
1269 	if (piv->data.length < pad_sz)
1270 	    return KRB5_BAD_MSIZE;
1271 	piv->data.length = pad_sz;
1272 	if (pad_sz)
1273 	    memset(piv->data.data, pad_sz, pad_sz);
1274 	else
1275 	    piv = NULL;
1276     }
1277 
1278     /* trailer */
1279     tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1280     if (tiv == NULL || tiv->data.length != trailersz)
1281 	return KRB5_BAD_MSIZE;
1282 
1283     /*
1284      * XXX replace with EVP_Sign? at least make create_checksum an iov
1285      * function.
1286      * XXX CTS EVP is broken, can't handle multi buffers :(
1287      */
1288 
1289     len = block_sz;
1290     for (i = 0; i < num_data; i++) {
1291 	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1292 	    continue;
1293 	len += data[i].data.length;
1294     }
1295 
1296     p = q = malloc(len);
1297 
1298     memcpy(q, hiv->data.data, hiv->data.length);
1299     q += hiv->data.length;
1300     for (i = 0; i < num_data; i++) {
1301 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1302 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1303 	    continue;
1304 	memcpy(q, data[i].data.data, data[i].data.length);
1305 	q += data[i].data.length;
1306     }
1307     if (piv)
1308 	memset(q, 0, piv->data.length);
1309 
1310     ret = create_checksum(context,
1311 			  et->keyed_checksum,
1312 			  crypto,
1313 			  INTEGRITY_USAGE(usage),
1314 			  p,
1315 			  len,
1316 			  &cksum);
1317     free(p);
1318     if(ret == 0 && cksum.checksum.length != trailersz) {
1319 	free_Checksum (&cksum);
1320 	krb5_clear_error_message (context);
1321 	ret = KRB5_CRYPTO_INTERNAL;
1322     }
1323     if(ret)
1324 	return ret;
1325 
1326     /* save cksum at end */
1327     memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1328     free_Checksum (&cksum);
1329 
1330     /* XXX replace with EVP_Cipher */
1331     p = q = malloc(block_sz);
1332     if(p == NULL)
1333 	return ENOMEM;
1334 
1335     memcpy(q, hiv->data.data, hiv->data.length);
1336     q += hiv->data.length;
1337 
1338     for (i = 0; i < num_data; i++) {
1339 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1340 	    continue;
1341 	memcpy(q, data[i].data.data, data[i].data.length);
1342 	q += data[i].data.length;
1343     }
1344     if (piv)
1345 	memset(q, 0, piv->data.length);
1346 
1347 
1348     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1349     if(ret) {
1350 	free(p);
1351 	return ret;
1352     }
1353     ret = _key_schedule(context, dkey);
1354     if(ret) {
1355 	free(p);
1356 	return ret;
1357     }
1358 
1359     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1360     if (ret) {
1361 	free(p);
1362 	return ret;
1363     }
1364 
1365     /* now copy data back to buffers */
1366     q = p;
1367 
1368     memcpy(hiv->data.data, q, hiv->data.length);
1369     q += hiv->data.length;
1370 
1371     for (i = 0; i < num_data; i++) {
1372 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1373 	    continue;
1374 	memcpy(data[i].data.data, q, data[i].data.length);
1375 	q += data[i].data.length;
1376     }
1377     if (piv)
1378 	memcpy(piv->data.data, q, pad_sz);
1379 
1380     free(p);
1381 
1382     return ret;
1383 }
1384 
1385 /**
1386  * Inline decrypt a Kerberos message.
1387  *
1388  * @param context Kerberos context
1389  * @param crypto Kerberos crypto context
1390  * @param usage Key usage for this buffer
1391  * @param data array of buffers to process
1392  * @param num_data length of array
1393  * @param ivec initial cbc/cts vector
1394  *
1395  * @return Return an error code or 0.
1396  * @ingroup krb5_crypto
1397  *
1398  * 1. KRB5_CRYPTO_TYPE_HEADER
1399  * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1400  *  any order, however the receiver have to aware of the
1401  *  order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1402  *  protocol headers and trailers. The output data will be of same
1403  *  size as the input data or shorter.
1404  */
1405 
1406 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1407 krb5_decrypt_iov_ivec(krb5_context context,
1408 		      krb5_crypto crypto,
1409 		      unsigned usage,
1410 		      krb5_crypto_iov *data,
1411 		      unsigned int num_data,
1412 		      void *ivec)
1413 {
1414     unsigned int i;
1415     size_t headersz, trailersz, len;
1416     Checksum cksum;
1417     unsigned char *p, *q;
1418     krb5_error_code ret;
1419     struct _krb5_key_data *dkey;
1420     struct _krb5_encryption_type *et = crypto->et;
1421     krb5_crypto_iov *tiv, *hiv;
1422 
1423     if(!derived_crypto(context, crypto)) {
1424 	krb5_clear_error_message(context);
1425 	return KRB5_CRYPTO_INTERNAL;
1426     }
1427 
1428     headersz = et->confoundersize;
1429 
1430     hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1431     if (hiv == NULL || hiv->data.length != headersz)
1432 	return KRB5_BAD_MSIZE;
1433 
1434     /* trailer */
1435     trailersz = CHECKSUMSIZE(et->keyed_checksum);
1436 
1437     tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1438     if (tiv->data.length != trailersz)
1439 	return KRB5_BAD_MSIZE;
1440 
1441     /* Find length of data we will decrypt */
1442 
1443     len = headersz;
1444     for (i = 0; i < num_data; i++) {
1445 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1446 	    continue;
1447 	len += data[i].data.length;
1448     }
1449 
1450     if ((len % et->padsize) != 0) {
1451 	krb5_clear_error_message(context);
1452 	return KRB5_BAD_MSIZE;
1453     }
1454 
1455     /* XXX replace with EVP_Cipher */
1456 
1457     p = q = malloc(len);
1458     if (p == NULL)
1459 	return ENOMEM;
1460 
1461     memcpy(q, hiv->data.data, hiv->data.length);
1462     q += hiv->data.length;
1463 
1464     for (i = 0; i < num_data; i++) {
1465 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1466 	    continue;
1467 	memcpy(q, data[i].data.data, data[i].data.length);
1468 	q += data[i].data.length;
1469     }
1470 
1471     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1472     if(ret) {
1473 	free(p);
1474 	return ret;
1475     }
1476     ret = _key_schedule(context, dkey);
1477     if(ret) {
1478 	free(p);
1479 	return ret;
1480     }
1481 
1482     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1483     if (ret) {
1484 	free(p);
1485 	return ret;
1486     }
1487 
1488     /* copy data back to buffers */
1489     memcpy(hiv->data.data, p, hiv->data.length);
1490     q = p + hiv->data.length;
1491     for (i = 0; i < num_data; i++) {
1492 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1493 	    continue;
1494 	memcpy(data[i].data.data, q, data[i].data.length);
1495 	q += data[i].data.length;
1496     }
1497 
1498     free(p);
1499 
1500     /* check signature */
1501     for (i = 0; i < num_data; i++) {
1502 	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1503 	    continue;
1504 	len += data[i].data.length;
1505     }
1506 
1507     p = q = malloc(len);
1508     if (p == NULL)
1509 	return ENOMEM;
1510 
1511     memcpy(q, hiv->data.data, hiv->data.length);
1512     q += hiv->data.length;
1513     for (i = 0; i < num_data; i++) {
1514 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1515 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1516 	    continue;
1517 	memcpy(q, data[i].data.data, data[i].data.length);
1518 	q += data[i].data.length;
1519     }
1520 
1521     cksum.checksum.data   = tiv->data.data;
1522     cksum.checksum.length = tiv->data.length;
1523     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1524 
1525     ret = verify_checksum(context,
1526 			  crypto,
1527 			  INTEGRITY_USAGE(usage),
1528 			  p,
1529 			  len,
1530 			  &cksum);
1531     free(p);
1532     return ret;
1533 }
1534 
1535 /**
1536  * Create a Kerberos message checksum.
1537  *
1538  * @param context Kerberos context
1539  * @param crypto Kerberos crypto context
1540  * @param usage Key usage for this buffer
1541  * @param data array of buffers to process
1542  * @param num_data length of array
1543  * @param type output data
1544  *
1545  * @return Return an error code or 0.
1546  * @ingroup krb5_crypto
1547  */
1548 
1549 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1550 krb5_create_checksum_iov(krb5_context context,
1551 			 krb5_crypto crypto,
1552 			 unsigned usage,
1553 			 krb5_crypto_iov *data,
1554 			 unsigned int num_data,
1555 			 krb5_cksumtype *type)
1556 {
1557     Checksum cksum;
1558     krb5_crypto_iov *civ;
1559     krb5_error_code ret;
1560     size_t i;
1561     size_t len;
1562     char *p, *q;
1563 
1564     if(!derived_crypto(context, crypto)) {
1565 	krb5_clear_error_message(context);
1566 	return KRB5_CRYPTO_INTERNAL;
1567     }
1568 
1569     civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1570     if (civ == NULL)
1571 	return KRB5_BAD_MSIZE;
1572 
1573     len = 0;
1574     for (i = 0; i < num_data; i++) {
1575 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1576 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1577 	    continue;
1578 	len += data[i].data.length;
1579     }
1580 
1581     p = q = malloc(len);
1582 
1583     for (i = 0; i < num_data; i++) {
1584 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1585 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1586 	    continue;
1587 	memcpy(q, data[i].data.data, data[i].data.length);
1588 	q += data[i].data.length;
1589     }
1590 
1591     ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1592     free(p);
1593     if (ret)
1594 	return ret;
1595 
1596     if (type)
1597 	*type = cksum.cksumtype;
1598 
1599     if (cksum.checksum.length > civ->data.length) {
1600 	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1601 			       N_("Checksum larger then input buffer", ""));
1602 	free_Checksum(&cksum);
1603 	return KRB5_BAD_MSIZE;
1604     }
1605 
1606     civ->data.length = cksum.checksum.length;
1607     memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1608     free_Checksum(&cksum);
1609 
1610     return 0;
1611 }
1612 
1613 /**
1614  * Verify a Kerberos message checksum.
1615  *
1616  * @param context Kerberos context
1617  * @param crypto Kerberos crypto context
1618  * @param usage Key usage for this buffer
1619  * @param data array of buffers to process
1620  * @param num_data length of array
1621  * @param type return checksum type if not NULL
1622  *
1623  * @return Return an error code or 0.
1624  * @ingroup krb5_crypto
1625  */
1626 
1627 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1628 krb5_verify_checksum_iov(krb5_context context,
1629 			 krb5_crypto crypto,
1630 			 unsigned usage,
1631 			 krb5_crypto_iov *data,
1632 			 unsigned int num_data,
1633 			 krb5_cksumtype *type)
1634 {
1635     struct _krb5_encryption_type *et = crypto->et;
1636     Checksum cksum;
1637     krb5_crypto_iov *civ;
1638     krb5_error_code ret;
1639     size_t i;
1640     size_t len;
1641     char *p, *q;
1642 
1643     if(!derived_crypto(context, crypto)) {
1644 	krb5_clear_error_message(context);
1645 	return KRB5_CRYPTO_INTERNAL;
1646     }
1647 
1648     civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1649     if (civ == NULL)
1650 	return KRB5_BAD_MSIZE;
1651 
1652     len = 0;
1653     for (i = 0; i < num_data; i++) {
1654 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1655 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1656 	    continue;
1657 	len += data[i].data.length;
1658     }
1659 
1660     p = q = malloc(len);
1661 
1662     for (i = 0; i < num_data; i++) {
1663 	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1664 	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1665 	    continue;
1666 	memcpy(q, data[i].data.data, data[i].data.length);
1667 	q += data[i].data.length;
1668     }
1669 
1670     cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1671     cksum.checksum.length = civ->data.length;
1672     cksum.checksum.data = civ->data.data;
1673 
1674     ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1675     free(p);
1676 
1677     if (ret == 0 && type)
1678 	*type = cksum.cksumtype;
1679 
1680     return ret;
1681 }
1682 
1683 
1684 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1685 krb5_crypto_length(krb5_context context,
1686 		   krb5_crypto crypto,
1687 		   int type,
1688 		   size_t *len)
1689 {
1690     if (!derived_crypto(context, crypto)) {
1691 	krb5_set_error_message(context, EINVAL, "not a derived crypto");
1692 	return EINVAL;
1693     }
1694 
1695     switch(type) {
1696     case KRB5_CRYPTO_TYPE_EMPTY:
1697 	*len = 0;
1698 	return 0;
1699     case KRB5_CRYPTO_TYPE_HEADER:
1700 	*len = crypto->et->blocksize;
1701 	return 0;
1702     case KRB5_CRYPTO_TYPE_DATA:
1703     case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1704 	/* len must already been filled in */
1705 	return 0;
1706     case KRB5_CRYPTO_TYPE_PADDING:
1707 	if (crypto->et->padsize > 1)
1708 	    *len = crypto->et->padsize;
1709 	else
1710 	    *len = 0;
1711 	return 0;
1712     case KRB5_CRYPTO_TYPE_TRAILER:
1713 	*len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1714 	return 0;
1715     case KRB5_CRYPTO_TYPE_CHECKSUM:
1716 	if (crypto->et->keyed_checksum)
1717 	    *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1718 	else
1719 	    *len = CHECKSUMSIZE(crypto->et->checksum);
1720 	return 0;
1721     }
1722     krb5_set_error_message(context, EINVAL,
1723 			   "%d not a supported type", type);
1724     return EINVAL;
1725 }
1726 
1727 
1728 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1729 krb5_crypto_length_iov(krb5_context context,
1730 		       krb5_crypto crypto,
1731 		       krb5_crypto_iov *data,
1732 		       unsigned int num_data)
1733 {
1734     krb5_error_code ret;
1735     size_t i;
1736 
1737     for (i = 0; i < num_data; i++) {
1738 	ret = krb5_crypto_length(context, crypto,
1739 				 data[i].flags,
1740 				 &data[i].data.length);
1741 	if (ret)
1742 	    return ret;
1743     }
1744     return 0;
1745 }
1746 
1747 
1748 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1749 krb5_encrypt_ivec(krb5_context context,
1750 		  krb5_crypto crypto,
1751 		  unsigned usage,
1752 		  const void *data,
1753 		  size_t len,
1754 		  krb5_data *result,
1755 		  void *ivec)
1756 {
1757     if(derived_crypto(context, crypto))
1758 	return encrypt_internal_derived(context, crypto, usage,
1759 					data, len, result, ivec);
1760     else if (special_crypto(context, crypto))
1761 	return encrypt_internal_special (context, crypto, usage,
1762 					 data, len, result, ivec);
1763     else
1764 	return encrypt_internal(context, crypto, data, len, result, ivec);
1765 }
1766 
1767 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1768 krb5_encrypt(krb5_context context,
1769 	     krb5_crypto crypto,
1770 	     unsigned usage,
1771 	     const void *data,
1772 	     size_t len,
1773 	     krb5_data *result)
1774 {
1775     return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
1776 }
1777 
1778 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1779 krb5_encrypt_EncryptedData(krb5_context context,
1780 			   krb5_crypto crypto,
1781 			   unsigned usage,
1782 			   void *data,
1783 			   size_t len,
1784 			   int kvno,
1785 			   EncryptedData *result)
1786 {
1787     result->etype = CRYPTO_ETYPE(crypto);
1788     if(kvno){
1789 	ALLOC(result->kvno, 1);
1790 	*result->kvno = kvno;
1791     }else
1792 	result->kvno = NULL;
1793     return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
1794 }
1795 
1796 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1797 krb5_decrypt_ivec(krb5_context context,
1798 		  krb5_crypto crypto,
1799 		  unsigned usage,
1800 		  void *data,
1801 		  size_t len,
1802 		  krb5_data *result,
1803 		  void *ivec)
1804 {
1805     if(derived_crypto(context, crypto))
1806 	return decrypt_internal_derived(context, crypto, usage,
1807 					data, len, result, ivec);
1808     else if (special_crypto (context, crypto))
1809 	return decrypt_internal_special(context, crypto, usage,
1810 					data, len, result, ivec);
1811     else
1812 	return decrypt_internal(context, crypto, data, len, result, ivec);
1813 }
1814 
1815 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1816 krb5_decrypt(krb5_context context,
1817 	     krb5_crypto crypto,
1818 	     unsigned usage,
1819 	     void *data,
1820 	     size_t len,
1821 	     krb5_data *result)
1822 {
1823     return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
1824 			      NULL);
1825 }
1826 
1827 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1828 krb5_decrypt_EncryptedData(krb5_context context,
1829 			   krb5_crypto crypto,
1830 			   unsigned usage,
1831 			   const EncryptedData *e,
1832 			   krb5_data *result)
1833 {
1834     return krb5_decrypt(context, crypto, usage,
1835 			e->cipher.data, e->cipher.length, result);
1836 }
1837 
1838 /************************************************************
1839  *                                                          *
1840  ************************************************************/
1841 
1842 krb5_error_code
1843 _krb5_derive_key(krb5_context context,
1844 		 struct _krb5_encryption_type *et,
1845 		 struct _krb5_key_data *key,
1846 		 const void *constant,
1847 		 size_t len)
1848 {
1849     unsigned char *k = NULL;
1850     unsigned int nblocks = 0, i;
1851     krb5_error_code ret = 0;
1852     struct _krb5_key_type *kt = et->keytype;
1853 
1854     ret = _key_schedule(context, key);
1855     if(ret)
1856 	return ret;
1857     if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
1858 	nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
1859 	k = malloc(nblocks * et->blocksize);
1860 	if(k == NULL) {
1861 	    ret = ENOMEM;
1862 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1863 	    goto out;
1864 	}
1865 	ret = _krb5_n_fold(constant, len, k, et->blocksize);
1866 	if (ret) {
1867 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1868 	    goto out;
1869 	}
1870 
1871 	for(i = 0; i < nblocks; i++) {
1872 	    if(i > 0)
1873 		memcpy(k + i * et->blocksize,
1874 		       k + (i - 1) * et->blocksize,
1875 		       et->blocksize);
1876 	    (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
1877 			   1, 0, NULL);
1878 	}
1879     } else {
1880 	/* this case is probably broken, but won't be run anyway */
1881 	void *c = malloc(len);
1882 	size_t res_len = (kt->bits + 7) / 8;
1883 
1884 	if(len != 0 && c == NULL) {
1885 	    ret = ENOMEM;
1886 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1887 	    goto out;
1888 	}
1889 	memcpy(c, constant, len);
1890 	(*et->encrypt)(context, key, c, len, 1, 0, NULL);
1891 	k = malloc(res_len);
1892 	if(res_len != 0 && k == NULL) {
1893 	    free(c);
1894 	    ret = ENOMEM;
1895 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1896 	    goto out;
1897 	}
1898 	ret = _krb5_n_fold(c, len, k, res_len);
1899 	free(c);
1900 	if (ret) {
1901 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1902 	    goto out;
1903 	}
1904     }
1905 
1906     /* XXX keytype dependent post-processing */
1907     switch(kt->type) {
1908     case ETYPE_OLD_DES3_CBC_SHA1:
1909 	_krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
1910 	break;
1911     case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
1912     case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
1913 	memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
1914 	break;
1915     default:
1916 	ret = KRB5_CRYPTO_INTERNAL;
1917 	krb5_set_error_message(context, ret,
1918 			       N_("derive_key() called with unknown keytype (%u)", ""),
1919 			       kt->type);
1920 	break;
1921     }
1922  out:
1923     if (key->schedule) {
1924 	free_key_schedule(context, key, et);
1925 	key->schedule = NULL;
1926     }
1927     if (k) {
1928 	memset(k, 0, nblocks * et->blocksize);
1929 	free(k);
1930     }
1931     return ret;
1932 }
1933 
1934 static struct _krb5_key_data *
1935 _new_derived_key(krb5_crypto crypto, unsigned usage)
1936 {
1937     struct _krb5_key_usage *d = crypto->key_usage;
1938     d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
1939     if(d == NULL)
1940 	return NULL;
1941     crypto->key_usage = d;
1942     d += crypto->num_key_usage++;
1943     memset(d, 0, sizeof(*d));
1944     d->usage = usage;
1945     return &d->key;
1946 }
1947 
1948 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1949 krb5_derive_key(krb5_context context,
1950 		const krb5_keyblock *key,
1951 		krb5_enctype etype,
1952 		const void *constant,
1953 		size_t constant_len,
1954 		krb5_keyblock **derived_key)
1955 {
1956     krb5_error_code ret;
1957     struct _krb5_encryption_type *et;
1958     struct _krb5_key_data d;
1959 
1960     *derived_key = NULL;
1961 
1962     et = _krb5_find_enctype (etype);
1963     if (et == NULL) {
1964         return unsupported_enctype (context, etype);
1965     }
1966 
1967     ret = krb5_copy_keyblock(context, key, &d.key);
1968     if (ret)
1969 	return ret;
1970 
1971     d.schedule = NULL;
1972     ret = _krb5_derive_key(context, et, &d, constant, constant_len);
1973     if (ret == 0)
1974 	ret = krb5_copy_keyblock(context, d.key, derived_key);
1975     _krb5_free_key_data(context, &d, et);
1976     return ret;
1977 }
1978 
1979 static krb5_error_code
1980 _get_derived_key(krb5_context context,
1981 		 krb5_crypto crypto,
1982 		 unsigned usage,
1983 		 struct _krb5_key_data **key)
1984 {
1985     int i;
1986     struct _krb5_key_data *d;
1987     unsigned char constant[5];
1988 
1989     for(i = 0; i < crypto->num_key_usage; i++)
1990 	if(crypto->key_usage[i].usage == usage) {
1991 	    *key = &crypto->key_usage[i].key;
1992 	    return 0;
1993 	}
1994     d = _new_derived_key(crypto, usage);
1995     if(d == NULL) {
1996 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1997 	return ENOMEM;
1998     }
1999     krb5_copy_keyblock(context, crypto->key.key, &d->key);
2000     _krb5_put_int(constant, usage, 5);
2001     _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2002     *key = d;
2003     return 0;
2004 }
2005 
2006 /**
2007  * Create a crypto context used for all encryption and signature
2008  * operation. The encryption type to use is taken from the key, but
2009  * can be overridden with the enctype parameter.  This can be useful
2010  * for encryptions types which is compatiable (DES for example).
2011  *
2012  * To free the crypto context, use krb5_crypto_destroy().
2013  *
2014  * @param context Kerberos context
2015  * @param key the key block information with all key data
2016  * @param etype the encryption type
2017  * @param crypto the resulting crypto context
2018  *
2019  * @return Return an error code or 0.
2020  *
2021  * @ingroup krb5_crypto
2022  */
2023 
2024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2025 krb5_crypto_init(krb5_context context,
2026 		 const krb5_keyblock *key,
2027 		 krb5_enctype etype,
2028 		 krb5_crypto *crypto)
2029 {
2030     krb5_error_code ret;
2031     ALLOC(*crypto, 1);
2032     if(*crypto == NULL) {
2033 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2034 	return ENOMEM;
2035     }
2036     if(etype == ETYPE_NULL)
2037 	etype = key->keytype;
2038     (*crypto)->et = _krb5_find_enctype(etype);
2039     if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2040 	free(*crypto);
2041 	*crypto = NULL;
2042 	return unsupported_enctype(context, etype);
2043     }
2044     if((*crypto)->et->keytype->size != key->keyvalue.length) {
2045 	free(*crypto);
2046 	*crypto = NULL;
2047 	krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2048 				"encryption key has bad length");
2049 	return KRB5_BAD_KEYSIZE;
2050     }
2051     ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2052     if(ret) {
2053 	free(*crypto);
2054 	*crypto = NULL;
2055 	return ret;
2056     }
2057     (*crypto)->key.schedule = NULL;
2058     (*crypto)->num_key_usage = 0;
2059     (*crypto)->key_usage = NULL;
2060     return 0;
2061 }
2062 
2063 static void
2064 free_key_schedule(krb5_context context,
2065 		  struct _krb5_key_data *key,
2066 		  struct _krb5_encryption_type *et)
2067 {
2068     if (et->keytype->cleanup)
2069 	(*et->keytype->cleanup)(context, key);
2070     memset(key->schedule->data, 0, key->schedule->length);
2071     krb5_free_data(context, key->schedule);
2072 }
2073 
2074 void
2075 _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2076 	      struct _krb5_encryption_type *et)
2077 {
2078     krb5_free_keyblock(context, key->key);
2079     if(key->schedule) {
2080 	free_key_schedule(context, key, et);
2081 	key->schedule = NULL;
2082     }
2083 }
2084 
2085 static void
2086 free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2087 	       struct _krb5_encryption_type *et)
2088 {
2089     _krb5_free_key_data(context, &ku->key, et);
2090 }
2091 
2092 /**
2093  * Free a crypto context created by krb5_crypto_init().
2094  *
2095  * @param context Kerberos context
2096  * @param crypto crypto context to free
2097  *
2098  * @return Return an error code or 0.
2099  *
2100  * @ingroup krb5_crypto
2101  */
2102 
2103 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2104 krb5_crypto_destroy(krb5_context context,
2105 		    krb5_crypto crypto)
2106 {
2107     int i;
2108 
2109     for(i = 0; i < crypto->num_key_usage; i++)
2110 	free_key_usage(context, &crypto->key_usage[i], crypto->et);
2111     free(crypto->key_usage);
2112     _krb5_free_key_data(context, &crypto->key, crypto->et);
2113     free (crypto);
2114     return 0;
2115 }
2116 
2117 /**
2118  * Return the blocksize used algorithm referenced by the crypto context
2119  *
2120  * @param context Kerberos context
2121  * @param crypto crypto context to query
2122  * @param blocksize the resulting blocksize
2123  *
2124  * @return Return an error code or 0.
2125  *
2126  * @ingroup krb5_crypto
2127  */
2128 
2129 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2130 krb5_crypto_getblocksize(krb5_context context,
2131 			 krb5_crypto crypto,
2132 			 size_t *blocksize)
2133 {
2134     *blocksize = crypto->et->blocksize;
2135     return 0;
2136 }
2137 
2138 /**
2139  * Return the encryption type used by the crypto context
2140  *
2141  * @param context Kerberos context
2142  * @param crypto crypto context to query
2143  * @param enctype the resulting encryption type
2144  *
2145  * @return Return an error code or 0.
2146  *
2147  * @ingroup krb5_crypto
2148  */
2149 
2150 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2151 krb5_crypto_getenctype(krb5_context context,
2152 		       krb5_crypto crypto,
2153 		       krb5_enctype *enctype)
2154 {
2155     *enctype = crypto->et->type;
2156     return 0;
2157 }
2158 
2159 /**
2160  * Return the padding size used by the crypto context
2161  *
2162  * @param context Kerberos context
2163  * @param crypto crypto context to query
2164  * @param padsize the return padding size
2165  *
2166  * @return Return an error code or 0.
2167  *
2168  * @ingroup krb5_crypto
2169  */
2170 
2171 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2172 krb5_crypto_getpadsize(krb5_context context,
2173                        krb5_crypto crypto,
2174                        size_t *padsize)
2175 {
2176     *padsize = crypto->et->padsize;
2177     return 0;
2178 }
2179 
2180 /**
2181  * Return the confounder size used by the crypto context
2182  *
2183  * @param context Kerberos context
2184  * @param crypto crypto context to query
2185  * @param confoundersize the returned confounder size
2186  *
2187  * @return Return an error code or 0.
2188  *
2189  * @ingroup krb5_crypto
2190  */
2191 
2192 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2193 krb5_crypto_getconfoundersize(krb5_context context,
2194                               krb5_crypto crypto,
2195                               size_t *confoundersize)
2196 {
2197     *confoundersize = crypto->et->confoundersize;
2198     return 0;
2199 }
2200 
2201 
2202 /**
2203  * Disable encryption type
2204  *
2205  * @param context Kerberos 5 context
2206  * @param enctype encryption type to disable
2207  *
2208  * @return Return an error code or 0.
2209  *
2210  * @ingroup krb5_crypto
2211  */
2212 
2213 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2214 krb5_enctype_disable(krb5_context context,
2215 		     krb5_enctype enctype)
2216 {
2217     struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2218     if(et == NULL) {
2219 	if (context)
2220 	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2221 				    N_("encryption type %d not supported", ""),
2222 				    enctype);
2223 	return KRB5_PROG_ETYPE_NOSUPP;
2224     }
2225     et->flags |= F_DISABLED;
2226     return 0;
2227 }
2228 
2229 /**
2230  * Enable encryption type
2231  *
2232  * @param context Kerberos 5 context
2233  * @param enctype encryption type to enable
2234  *
2235  * @return Return an error code or 0.
2236  *
2237  * @ingroup krb5_crypto
2238  */
2239 
2240 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2241 krb5_enctype_enable(krb5_context context,
2242 		    krb5_enctype enctype)
2243 {
2244     struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2245     if(et == NULL) {
2246 	if (context)
2247 	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2248 				    N_("encryption type %d not supported", ""),
2249 				    enctype);
2250 	return KRB5_PROG_ETYPE_NOSUPP;
2251     }
2252     et->flags &= ~F_DISABLED;
2253     return 0;
2254 }
2255 
2256 /**
2257  * Enable or disable all weak encryption types
2258  *
2259  * @param context Kerberos 5 context
2260  * @param enable true to enable, false to disable
2261  *
2262  * @return Return an error code or 0.
2263  *
2264  * @ingroup krb5_crypto
2265  */
2266 
2267 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2268 krb5_allow_weak_crypto(krb5_context context,
2269 		       krb5_boolean enable)
2270 {
2271     int i;
2272 
2273     for(i = 0; i < _krb5_num_etypes; i++)
2274 	if(_krb5_etypes[i]->flags & F_WEAK) {
2275 	    if(enable)
2276 		_krb5_etypes[i]->flags &= ~F_DISABLED;
2277 	    else
2278 		_krb5_etypes[i]->flags |= F_DISABLED;
2279 	}
2280     return 0;
2281 }
2282 
2283 static size_t
2284 wrapped_length (krb5_context context,
2285 		krb5_crypto  crypto,
2286 		size_t       data_len)
2287 {
2288     struct _krb5_encryption_type *et = crypto->et;
2289     size_t padsize = et->padsize;
2290     size_t checksumsize = CHECKSUMSIZE(et->checksum);
2291     size_t res;
2292 
2293     res =  et->confoundersize + checksumsize + data_len;
2294     res =  (res + padsize - 1) / padsize * padsize;
2295     return res;
2296 }
2297 
2298 static size_t
2299 wrapped_length_dervied (krb5_context context,
2300 			krb5_crypto  crypto,
2301 			size_t       data_len)
2302 {
2303     struct _krb5_encryption_type *et = crypto->et;
2304     size_t padsize = et->padsize;
2305     size_t res;
2306 
2307     res =  et->confoundersize + data_len;
2308     res =  (res + padsize - 1) / padsize * padsize;
2309     if (et->keyed_checksum)
2310 	res += et->keyed_checksum->checksumsize;
2311     else
2312 	res += et->checksum->checksumsize;
2313     return res;
2314 }
2315 
2316 /*
2317  * Return the size of an encrypted packet of length `data_len'
2318  */
2319 
2320 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2321 krb5_get_wrapped_length (krb5_context context,
2322 			 krb5_crypto  crypto,
2323 			 size_t       data_len)
2324 {
2325     if (derived_crypto (context, crypto))
2326 	return wrapped_length_dervied (context, crypto, data_len);
2327     else
2328 	return wrapped_length (context, crypto, data_len);
2329 }
2330 
2331 /*
2332  * Return the size of an encrypted packet of length `data_len'
2333  */
2334 
2335 static size_t
2336 crypto_overhead (krb5_context context,
2337 		 krb5_crypto  crypto)
2338 {
2339     struct _krb5_encryption_type *et = crypto->et;
2340     size_t res;
2341 
2342     res = CHECKSUMSIZE(et->checksum);
2343     res += et->confoundersize;
2344     if (et->padsize > 1)
2345 	res += et->padsize;
2346     return res;
2347 }
2348 
2349 static size_t
2350 crypto_overhead_dervied (krb5_context context,
2351 			 krb5_crypto  crypto)
2352 {
2353     struct _krb5_encryption_type *et = crypto->et;
2354     size_t res;
2355 
2356     if (et->keyed_checksum)
2357 	res = CHECKSUMSIZE(et->keyed_checksum);
2358     else
2359 	res = CHECKSUMSIZE(et->checksum);
2360     res += et->confoundersize;
2361     if (et->padsize > 1)
2362 	res += et->padsize;
2363     return res;
2364 }
2365 
2366 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2367 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2368 {
2369     if (derived_crypto (context, crypto))
2370 	return crypto_overhead_dervied (context, crypto);
2371     else
2372 	return crypto_overhead (context, crypto);
2373 }
2374 
2375 /**
2376  * Converts the random bytestring to a protocol key according to
2377  * Kerberos crypto frame work. It may be assumed that all the bits of
2378  * the input string are equally random, even though the entropy
2379  * present in the random source may be limited.
2380  *
2381  * @param context Kerberos 5 context
2382  * @param type the enctype resulting key will be of
2383  * @param data input random data to convert to a key
2384  * @param size size of input random data, at least krb5_enctype_keysize() long
2385  * @param key key, output key, free with krb5_free_keyblock_contents()
2386  *
2387  * @return Return an error code or 0.
2388  *
2389  * @ingroup krb5_crypto
2390  */
2391 
2392 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2393 krb5_random_to_key(krb5_context context,
2394 		   krb5_enctype type,
2395 		   const void *data,
2396 		   size_t size,
2397 		   krb5_keyblock *key)
2398 {
2399     krb5_error_code ret;
2400     struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2401     if(et == NULL) {
2402 	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2403 			       N_("encryption type %d not supported", ""),
2404 			       type);
2405 	return KRB5_PROG_ETYPE_NOSUPP;
2406     }
2407     if ((et->keytype->bits + 7) / 8 > size) {
2408 	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2409 			       N_("encryption key %s needs %d bytes "
2410 				  "of random to make an encryption key "
2411 				  "out of it", ""),
2412 			       et->name, (int)et->keytype->size);
2413 	return KRB5_PROG_ETYPE_NOSUPP;
2414     }
2415     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2416     if(ret)
2417 	return ret;
2418     key->keytype = type;
2419     if (et->keytype->random_to_key)
2420  	(*et->keytype->random_to_key)(context, key, data, size);
2421     else
2422 	memcpy(key->keyvalue.data, data, et->keytype->size);
2423 
2424     return 0;
2425 }
2426 
2427 
2428 
2429 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2430 krb5_crypto_prf_length(krb5_context context,
2431 		       krb5_enctype type,
2432 		       size_t *length)
2433 {
2434     struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2435 
2436     if(et == NULL || et->prf_length == 0) {
2437 	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2438 			       N_("encryption type %d not supported", ""),
2439 			       type);
2440 	return KRB5_PROG_ETYPE_NOSUPP;
2441     }
2442 
2443     *length = et->prf_length;
2444     return 0;
2445 }
2446 
2447 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2448 krb5_crypto_prf(krb5_context context,
2449 		const krb5_crypto crypto,
2450 		const krb5_data *input,
2451 		krb5_data *output)
2452 {
2453     struct _krb5_encryption_type *et = crypto->et;
2454 
2455     krb5_data_zero(output);
2456 
2457     if(et->prf == NULL) {
2458 	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2459 			       "kerberos prf for %s not supported",
2460 			       et->name);
2461 	return KRB5_PROG_ETYPE_NOSUPP;
2462     }
2463 
2464     return (*et->prf)(context, crypto, input, output);
2465 }
2466 
2467 static krb5_error_code
2468 krb5_crypto_prfplus(krb5_context context,
2469 		    const krb5_crypto crypto,
2470 		    const krb5_data *input,
2471 		    size_t length,
2472 		    krb5_data *output)
2473 {
2474     krb5_error_code ret;
2475     krb5_data input2;
2476     unsigned char i = 1;
2477     unsigned char *p;
2478 
2479     krb5_data_zero(&input2);
2480     krb5_data_zero(output);
2481 
2482     krb5_clear_error_message(context);
2483 
2484     ret = krb5_data_alloc(output, length);
2485     if (ret) goto out;
2486     ret = krb5_data_alloc(&input2, input->length + 1);
2487     if (ret) goto out;
2488 
2489     krb5_clear_error_message(context);
2490 
2491     memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2492 
2493     p = output->data;
2494 
2495     while (length) {
2496 	krb5_data block;
2497 
2498 	((unsigned char *)input2.data)[0] = i++;
2499 
2500 	ret = krb5_crypto_prf(context, crypto, &input2, &block);
2501 	if (ret)
2502 	    goto out;
2503 
2504 	if (block.length < length) {
2505 	    memcpy(p, block.data, block.length);
2506 	    length -= block.length;
2507 	} else {
2508 	    memcpy(p, block.data, length);
2509 	    length = 0;
2510 	}
2511 	p += block.length;
2512 	krb5_data_free(&block);
2513     }
2514 
2515  out:
2516     krb5_data_free(&input2);
2517     if (ret)
2518 	krb5_data_free(output);
2519     return 0;
2520 }
2521 
2522 /**
2523  * The FX-CF2 key derivation function, used in FAST and preauth framework.
2524  *
2525  * @param context Kerberos 5 context
2526  * @param crypto1 first key to combine
2527  * @param crypto2 second key to combine
2528  * @param pepper1 factor to combine with first key to garante uniqueness
2529  * @param pepper2 factor to combine with second key to garante uniqueness
2530  * @param enctype the encryption type of the resulting key
2531  * @param res allocated key, free with krb5_free_keyblock_contents()
2532  *
2533  * @return Return an error code or 0.
2534  *
2535  * @ingroup krb5_crypto
2536  */
2537 
2538 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2539 krb5_crypto_fx_cf2(krb5_context context,
2540 		   const krb5_crypto crypto1,
2541 		   const krb5_crypto crypto2,
2542 		   krb5_data *pepper1,
2543 		   krb5_data *pepper2,
2544 		   krb5_enctype enctype,
2545 		   krb5_keyblock *res)
2546 {
2547     krb5_error_code ret;
2548     krb5_data os1, os2;
2549     size_t i, keysize;
2550 
2551     memset(res, 0, sizeof(*res));
2552 
2553     ret = krb5_enctype_keysize(context, enctype, &keysize);
2554     if (ret)
2555 	return ret;
2556 
2557     ret = krb5_data_alloc(&res->keyvalue, keysize);
2558     if (ret)
2559 	goto out;
2560     ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2561     if (ret)
2562 	goto out;
2563     ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2564     if (ret)
2565 	goto out;
2566 
2567     res->keytype = enctype;
2568     {
2569 	unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data;
2570 	for (i = 0; i < keysize; i++)
2571 	    p3[i] = p1[i] ^ p2[i];
2572     }
2573  out:
2574     if (ret)
2575 	krb5_data_free(&res->keyvalue);
2576     krb5_data_free(&os1);
2577     krb5_data_free(&os2);
2578 
2579     return ret;
2580 }
2581 
2582 
2583 
2584 #ifndef HEIMDAL_SMALLER
2585 
2586 /**
2587  * Deprecated: keytypes doesn't exists, they are really enctypes.
2588  *
2589  * @ingroup krb5_deprecated
2590  */
2591 
2592 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2593 krb5_keytype_to_enctypes (krb5_context context,
2594 			  krb5_keytype keytype,
2595 			  unsigned *len,
2596 			  krb5_enctype **val)
2597     KRB5_DEPRECATED_FUNCTION("Use X instead")
2598 {
2599     int i;
2600     unsigned n = 0;
2601     krb5_enctype *ret;
2602 
2603     for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2604 	if (_krb5_etypes[i]->keytype->type == keytype
2605 	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2606 	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2607 	    ++n;
2608     }
2609     if (n == 0) {
2610 	krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
2611 			       "Keytype have no mapping");
2612 	return KRB5_PROG_KEYTYPE_NOSUPP;
2613     }
2614 
2615     ret = malloc(n * sizeof(*ret));
2616     if (ret == NULL && n != 0) {
2617 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2618 	return ENOMEM;
2619     }
2620     n = 0;
2621     for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2622 	if (_krb5_etypes[i]->keytype->type == keytype
2623 	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2624 	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2625 	    ret[n++] = _krb5_etypes[i]->type;
2626     }
2627     *len = n;
2628     *val = ret;
2629     return 0;
2630 }
2631 
2632 /**
2633  * Deprecated: keytypes doesn't exists, they are really enctypes.
2634  *
2635  * @ingroup krb5_deprecated
2636  */
2637 
2638 /* if two enctypes have compatible keys */
2639 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2640 krb5_enctypes_compatible_keys(krb5_context context,
2641 			      krb5_enctype etype1,
2642 			      krb5_enctype etype2)
2643     KRB5_DEPRECATED_FUNCTION("Use X instead")
2644 {
2645     struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
2646     struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
2647     return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2648 }
2649 
2650 #endif /* HEIMDAL_SMALLER */
2651