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