1/*	$NetBSD: crypto.c,v 1.2 2017/01/28 21:31:49 christos 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#include "krb5_locl.h"
37
38struct _krb5_key_usage {
39    unsigned usage;
40    struct _krb5_key_data key;
41};
42
43
44#ifndef HEIMDAL_SMALLER
45#define DES3_OLD_ENCTYPE 1
46#endif
47
48static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
49					unsigned, struct _krb5_key_data**);
50static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
51
52static void free_key_schedule(krb5_context,
53			      struct _krb5_key_data *,
54			      struct _krb5_encryption_type *);
55
56/*
57 * Converts etype to a user readable string and sets as a side effect
58 * the krb5_error_message containing this string. Returns
59 * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
60 * which case the error code of the etype convesion is returned.
61 */
62
63static krb5_error_code
64unsupported_enctype(krb5_context context, krb5_enctype etype)
65{
66    krb5_error_code ret;
67    char *name;
68
69    ret = krb5_enctype_to_string(context, etype, &name);
70    if (ret)
71	return ret;
72
73    krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
74			   N_("Encryption type %s not supported", ""),
75			   name);
76    free(name);
77    return KRB5_PROG_ETYPE_NOSUPP;
78}
79
80/*
81 *
82 */
83
84KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
85krb5_enctype_keysize(krb5_context context,
86		     krb5_enctype type,
87		     size_t *keysize)
88{
89    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
90    if(et == NULL) {
91        return unsupported_enctype (context, type);
92    }
93    *keysize = et->keytype->size;
94    return 0;
95}
96
97KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
98krb5_enctype_keybits(krb5_context context,
99		     krb5_enctype type,
100		     size_t *keybits)
101{
102    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
103    if(et == NULL) {
104        return unsupported_enctype (context, type);
105    }
106    *keybits = et->keytype->bits;
107    return 0;
108}
109
110KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
111krb5_generate_random_keyblock(krb5_context context,
112			      krb5_enctype type,
113			      krb5_keyblock *key)
114{
115    krb5_error_code ret;
116    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
117    if(et == NULL) {
118        return unsupported_enctype (context, type);
119    }
120    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
121    if(ret)
122	return ret;
123    key->keytype = type;
124    if(et->keytype->random_key)
125	(*et->keytype->random_key)(context, key);
126    else
127	krb5_generate_random_block(key->keyvalue.data,
128				   key->keyvalue.length);
129    return 0;
130}
131
132static krb5_error_code
133_key_schedule(krb5_context context,
134	      struct _krb5_key_data *key)
135{
136    krb5_error_code ret;
137    struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
138    struct _krb5_key_type *kt;
139
140    if (et == NULL) {
141        return unsupported_enctype (context,
142                               key->key->keytype);
143    }
144
145    kt = et->keytype;
146
147    if(kt->schedule == NULL)
148	return 0;
149    if (key->schedule != NULL)
150	return 0;
151    ALLOC(key->schedule, 1);
152    if (key->schedule == NULL)
153	return krb5_enomem(context);
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
168static krb5_error_code
169SHA1_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 */
182KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
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
239KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240krb5_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
270krb5_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
293struct _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
303KRB5_LIB_FUNCTION struct _krb5_checksum_type * KRB5_LIB_CALL
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
313static krb5_error_code
314get_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	    return krb5_enomem(context);
330	ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
331	if(ret)
332	    return ret;
333	for(i = 0; i < (*key)->key->keyvalue.length; i++)
334	    ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
335    } else {
336	*key = &crypto->key;
337    }
338    if(ret == 0)
339	ret = _key_schedule(context, *key);
340    return ret;
341}
342
343static krb5_error_code
344create_checksum (krb5_context context,
345		 struct _krb5_checksum_type *ct,
346		 krb5_crypto crypto,
347		 unsigned usage,
348		 void *data,
349		 size_t len,
350		 Checksum *result)
351{
352    krb5_error_code ret;
353    struct _krb5_key_data *dkey;
354    int keyed_checksum;
355
356    if (ct->flags & F_DISABLED) {
357	krb5_clear_error_message (context);
358	return KRB5_PROG_SUMTYPE_NOSUPP;
359    }
360    keyed_checksum = (ct->flags & F_KEYED) != 0;
361    if(keyed_checksum && crypto == NULL) {
362	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
363				N_("Checksum type %s is keyed but no "
364				   "crypto context (key) was passed in", ""),
365				ct->name);
366	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
367    }
368    if(keyed_checksum) {
369	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
370	if (ret)
371	    return ret;
372    } else
373	dkey = NULL;
374    result->cksumtype = ct->type;
375    ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
376    if (ret)
377	return (ret);
378    return (*ct->checksum)(context, dkey, data, len, usage, result);
379}
380
381static int
382arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
383{
384    return (ct->type == CKSUMTYPE_HMAC_MD5) &&
385	(crypto->key.key->keytype == KEYTYPE_ARCFOUR);
386}
387
388KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
389krb5_create_checksum(krb5_context context,
390		     krb5_crypto crypto,
391		     krb5_key_usage usage,
392		     int type,
393		     void *data,
394		     size_t len,
395		     Checksum *result)
396{
397    struct _krb5_checksum_type *ct = NULL;
398    unsigned keyusage;
399
400    /* type 0 -> pick from crypto */
401    if (type) {
402	ct = _krb5_find_checksum(type);
403    } else if (crypto) {
404	ct = crypto->et->keyed_checksum;
405	if (ct == NULL)
406	    ct = crypto->et->checksum;
407    }
408
409    if(ct == NULL) {
410	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
411				N_("checksum type %d not supported", ""),
412				type);
413	return KRB5_PROG_SUMTYPE_NOSUPP;
414    }
415
416    if (arcfour_checksum_p(ct, crypto)) {
417	keyusage = usage;
418	_krb5_usage2arcfour(context, &keyusage);
419    } else
420	keyusage = CHECKSUM_USAGE(usage);
421
422    return create_checksum(context, ct, crypto, keyusage,
423			   data, len, result);
424}
425
426static krb5_error_code
427verify_checksum(krb5_context context,
428		krb5_crypto crypto,
429		unsigned usage, /* not krb5_key_usage */
430		void *data,
431		size_t len,
432		Checksum *cksum)
433{
434    krb5_error_code ret;
435    struct _krb5_key_data *dkey;
436    int keyed_checksum;
437    Checksum c;
438    struct _krb5_checksum_type *ct;
439
440    ct = _krb5_find_checksum(cksum->cksumtype);
441    if (ct == NULL || (ct->flags & F_DISABLED)) {
442	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
443				N_("checksum type %d not supported", ""),
444				cksum->cksumtype);
445	return KRB5_PROG_SUMTYPE_NOSUPP;
446    }
447    if(ct->checksumsize != cksum->checksum.length) {
448	krb5_clear_error_message (context);
449	krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
450			       N_("Decrypt integrity check failed for checksum type %s, "
451				  "length was %u, expected %u", ""),
452			       ct->name, (unsigned)cksum->checksum.length,
453			       (unsigned)ct->checksumsize);
454
455	return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
456    }
457    keyed_checksum = (ct->flags & F_KEYED) != 0;
458    if(keyed_checksum) {
459	struct _krb5_checksum_type *kct;
460	if (crypto == NULL) {
461	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
462				   N_("Checksum type %s is keyed but no "
463				      "crypto context (key) was passed in", ""),
464				   ct->name);
465	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
466	}
467	kct = crypto->et->keyed_checksum;
468	if (kct == NULL || kct->type != ct->type) {
469	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
470				   N_("Checksum type %s is keyed, but "
471				      "the key type %s passed didnt have that checksum "
472				      "type as the keyed type", ""),
473				    ct->name, crypto->et->name);
474	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
475	}
476
477	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
478	if (ret)
479	    return ret;
480    } else
481	dkey = NULL;
482
483    /*
484     * If checksum have a verify function, lets use that instead of
485     * calling ->checksum and then compare result.
486     */
487
488    if(ct->verify) {
489	ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
490	if (ret)
491	    krb5_set_error_message(context, ret,
492				   N_("Decrypt integrity check failed for checksum "
493				      "type %s, key type %s", ""),
494				   ct->name, (crypto != NULL)? crypto->et->name : "(none)");
495	return ret;
496    }
497
498    ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
499    if (ret)
500	return ret;
501
502    ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
503    if (ret) {
504	krb5_data_free(&c.checksum);
505	return ret;
506    }
507
508    if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
509	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
510	krb5_set_error_message(context, ret,
511			       N_("Decrypt integrity check failed for checksum "
512				  "type %s, key type %s", ""),
513			       ct->name, crypto ? crypto->et->name : "(unkeyed)");
514    } else {
515	ret = 0;
516    }
517    krb5_data_free (&c.checksum);
518    return ret;
519}
520
521KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
522krb5_verify_checksum(krb5_context context,
523		     krb5_crypto crypto,
524		     krb5_key_usage usage,
525		     void *data,
526		     size_t len,
527		     Checksum *cksum)
528{
529    struct _krb5_checksum_type *ct;
530    unsigned keyusage;
531
532    ct = _krb5_find_checksum(cksum->cksumtype);
533    if(ct == NULL) {
534	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
535				N_("checksum type %d not supported", ""),
536				cksum->cksumtype);
537	return KRB5_PROG_SUMTYPE_NOSUPP;
538    }
539
540    if (arcfour_checksum_p(ct, crypto)) {
541	keyusage = usage;
542	_krb5_usage2arcfour(context, &keyusage);
543    } else
544	keyusage = CHECKSUM_USAGE(usage);
545
546    return verify_checksum(context, crypto, keyusage,
547			   data, len, cksum);
548}
549
550KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
551krb5_crypto_get_checksum_type(krb5_context context,
552                              krb5_crypto crypto,
553			      krb5_cksumtype *type)
554{
555    struct _krb5_checksum_type *ct = NULL;
556
557    if (crypto != NULL) {
558        ct = crypto->et->keyed_checksum;
559        if (ct == NULL)
560            ct = crypto->et->checksum;
561    }
562
563    if (ct == NULL) {
564	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
565				N_("checksum type not found", ""));
566        return KRB5_PROG_SUMTYPE_NOSUPP;
567    }
568
569    *type = ct->type;
570
571    return 0;
572}
573
574
575KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
576krb5_checksumsize(krb5_context context,
577		  krb5_cksumtype type,
578		  size_t *size)
579{
580    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
581    if(ct == NULL) {
582	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
583				N_("checksum type %d not supported", ""),
584				type);
585	return KRB5_PROG_SUMTYPE_NOSUPP;
586    }
587    *size = ct->checksumsize;
588    return 0;
589}
590
591KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
592krb5_checksum_is_keyed(krb5_context context,
593		       krb5_cksumtype type)
594{
595    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
596    if(ct == NULL) {
597	if (context)
598	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
599				    N_("checksum type %d not supported", ""),
600				    type);
601	return KRB5_PROG_SUMTYPE_NOSUPP;
602    }
603    return ct->flags & F_KEYED;
604}
605
606KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
607krb5_checksum_is_collision_proof(krb5_context context,
608				 krb5_cksumtype type)
609{
610    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
611    if(ct == NULL) {
612	if (context)
613	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
614				    N_("checksum type %d not supported", ""),
615				    type);
616	return KRB5_PROG_SUMTYPE_NOSUPP;
617    }
618    return ct->flags & F_CPROOF;
619}
620
621KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
622krb5_checksum_disable(krb5_context context,
623		      krb5_cksumtype type)
624{
625    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
626    if(ct == NULL) {
627	if (context)
628	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
629				    N_("checksum type %d not supported", ""),
630				    type);
631	return KRB5_PROG_SUMTYPE_NOSUPP;
632    }
633    ct->flags |= F_DISABLED;
634    return 0;
635}
636
637/************************************************************
638 *                                                          *
639 ************************************************************/
640
641KRB5_LIB_FUNCTION struct _krb5_encryption_type * KRB5_LIB_CALL
642_krb5_find_enctype(krb5_enctype type)
643{
644    int i;
645    for(i = 0; i < _krb5_num_etypes; i++)
646	if(_krb5_etypes[i]->type == type)
647	    return _krb5_etypes[i];
648    return NULL;
649}
650
651
652KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
653krb5_enctype_to_string(krb5_context context,
654		       krb5_enctype etype,
655		       char **string)
656{
657    struct _krb5_encryption_type *e;
658    e = _krb5_find_enctype(etype);
659    if(e == NULL) {
660	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
661				N_("encryption type %d not supported", ""),
662				etype);
663	*string = NULL;
664	return KRB5_PROG_ETYPE_NOSUPP;
665    }
666    *string = strdup(e->name);
667    if (*string == NULL)
668	return krb5_enomem(context);
669    return 0;
670}
671
672KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
673krb5_string_to_enctype(krb5_context context,
674		       const char *string,
675		       krb5_enctype *etype)
676{
677    int i;
678    for(i = 0; i < _krb5_num_etypes; i++) {
679	if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
680	    *etype = _krb5_etypes[i]->type;
681	    return 0;
682	}
683	if(_krb5_etypes[i]->alias != NULL &&
684	   strcasecmp(_krb5_etypes[i]->alias, string) == 0){
685	    *etype = _krb5_etypes[i]->type;
686	    return 0;
687	}
688    }
689    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
690			    N_("encryption type %s not supported", ""),
691			    string);
692    return KRB5_PROG_ETYPE_NOSUPP;
693}
694
695KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
696krb5_enctype_to_keytype(krb5_context context,
697			krb5_enctype etype,
698			krb5_keytype *keytype)
699{
700    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
701    if(e == NULL) {
702        return unsupported_enctype (context, etype);
703    }
704    *keytype = e->keytype->type; /* XXX */
705    return 0;
706}
707
708/**
709 * Check if a enctype is valid, return 0 if it is.
710 *
711 * @param context Kerberos context
712 * @param etype enctype to check if its valid or not
713 *
714 * @return Return an error code for an failure or 0 on success (enctype valid).
715 * @ingroup krb5_crypto
716 */
717
718KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
719krb5_enctype_valid(krb5_context context,
720		   krb5_enctype etype)
721{
722    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
723    if(e && (e->flags & F_DISABLED) == 0)
724	return 0;
725    if (context == NULL)
726	return KRB5_PROG_ETYPE_NOSUPP;
727    if(e == NULL) {
728        return unsupported_enctype (context, etype);
729    }
730    /* Must be (e->flags & F_DISABLED) */
731    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
732			    N_("encryption type %s is disabled", ""),
733			    e->name);
734    return KRB5_PROG_ETYPE_NOSUPP;
735}
736
737/**
738 * Return the coresponding encryption type for a checksum type.
739 *
740 * @param context Kerberos context
741 * @param ctype The checksum type to get the result enctype for
742 * @param etype The returned encryption, when the matching etype is
743 * not found, etype is set to ETYPE_NULL.
744 *
745 * @return Return an error code for an failure or 0 on success.
746 * @ingroup krb5_crypto
747 */
748
749
750KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
751krb5_cksumtype_to_enctype(krb5_context context,
752			  krb5_cksumtype ctype,
753			  krb5_enctype *etype)
754{
755    int i;
756
757    *etype = ETYPE_NULL;
758
759    for(i = 0; i < _krb5_num_etypes; i++) {
760	if(_krb5_etypes[i]->keyed_checksum &&
761	   _krb5_etypes[i]->keyed_checksum->type == ctype)
762	    {
763		*etype = _krb5_etypes[i]->type;
764		return 0;
765	    }
766    }
767
768    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
769			    N_("checksum type %d not supported", ""),
770			    (int)ctype);
771    return KRB5_PROG_SUMTYPE_NOSUPP;
772}
773
774
775KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
776krb5_cksumtype_valid(krb5_context context,
777		     krb5_cksumtype ctype)
778{
779    struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
780    if (c == NULL) {
781	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
782				N_("checksum type %d not supported", ""),
783				ctype);
784	return KRB5_PROG_SUMTYPE_NOSUPP;
785    }
786    if (c->flags & F_DISABLED) {
787	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
788				N_("checksum type %s is disabled", ""),
789				c->name);
790	return KRB5_PROG_SUMTYPE_NOSUPP;
791    }
792    return 0;
793}
794
795static krb5_boolean
796derived_crypto(krb5_context context,
797	       krb5_crypto crypto)
798{
799    return (crypto->et->flags & F_DERIVED) != 0;
800}
801
802#define CHECKSUMSIZE(C) ((C)->checksumsize)
803#define CHECKSUMTYPE(C) ((C)->type)
804
805static krb5_error_code
806encrypt_internal_derived(krb5_context context,
807			 krb5_crypto crypto,
808			 unsigned usage,
809			 const void *data,
810			 size_t len,
811			 krb5_data *result,
812			 void *ivec)
813{
814    size_t sz, block_sz, checksum_sz, total_sz;
815    Checksum cksum;
816    unsigned char *p, *q;
817    krb5_error_code ret;
818    struct _krb5_key_data *dkey;
819    const struct _krb5_encryption_type *et = crypto->et;
820
821    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
822
823    sz = et->confoundersize + len;
824    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
825    total_sz = block_sz + checksum_sz;
826    p = calloc(1, total_sz);
827    if (p == NULL)
828	return krb5_enomem(context);
829
830    q = p;
831    krb5_generate_random_block(q, et->confoundersize); /* XXX */
832    q += et->confoundersize;
833    memcpy(q, data, len);
834
835    ret = create_checksum(context,
836			  et->keyed_checksum,
837			  crypto,
838			  INTEGRITY_USAGE(usage),
839			  p,
840			  block_sz,
841			  &cksum);
842    if(ret == 0 && cksum.checksum.length != checksum_sz) {
843	free_Checksum (&cksum);
844	krb5_clear_error_message (context);
845	ret = KRB5_CRYPTO_INTERNAL;
846    }
847    if(ret)
848	goto fail;
849    memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
850    free_Checksum (&cksum);
851    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
852    if(ret)
853	goto fail;
854    ret = _key_schedule(context, dkey);
855    if(ret)
856	goto fail;
857    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
858    if (ret)
859	goto fail;
860    result->data = p;
861    result->length = total_sz;
862    return 0;
863 fail:
864    memset(p, 0, total_sz);
865    free(p);
866    return ret;
867}
868
869static krb5_error_code
870encrypt_internal_enc_then_cksum(krb5_context context,
871				krb5_crypto crypto,
872				unsigned usage,
873				const void *data,
874				size_t len,
875				krb5_data *result,
876				void *ivec)
877{
878    size_t sz, block_sz, checksum_sz, total_sz;
879    Checksum cksum;
880    unsigned char *p, *q, *ivc = NULL;
881    krb5_error_code ret;
882    struct _krb5_key_data *dkey;
883    const struct _krb5_encryption_type *et = crypto->et;
884
885    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
886
887    sz = et->confoundersize + len;
888    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
889    total_sz = block_sz + checksum_sz;
890    p = calloc(1, total_sz);
891    if (p == NULL)
892	return krb5_enomem(context);
893
894    q = p;
895    krb5_generate_random_block(q, et->confoundersize); /* XXX */
896    q += et->confoundersize;
897    memcpy(q, data, len);
898
899    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
900    if(ret)
901	goto fail;
902    ret = _key_schedule(context, dkey);
903    if(ret)
904	goto fail;
905
906    /* XXX EVP style update API would avoid needing to allocate here */
907    ivc = malloc(et->blocksize + block_sz);
908    if (ivc == NULL) {
909	ret = krb5_enomem(context);
910	goto fail;
911    }
912    if (ivec)
913	memcpy(ivc, ivec, et->blocksize);
914    else
915	memset(ivc, 0, et->blocksize);
916
917    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
918    if (ret)
919	goto fail;
920    memcpy(&ivc[et->blocksize], p, block_sz);
921
922    ret = create_checksum(context,
923			  et->keyed_checksum,
924			  crypto,
925			  INTEGRITY_USAGE(usage),
926			  ivc,
927			  et->blocksize + block_sz,
928			  &cksum);
929    if(ret == 0 && cksum.checksum.length != checksum_sz) {
930	free_Checksum (&cksum);
931	krb5_clear_error_message (context);
932	ret = KRB5_CRYPTO_INTERNAL;
933    }
934    if(ret)
935	goto fail;
936    memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
937    free_Checksum (&cksum);
938    result->data = p;
939    result->length = total_sz;
940    free(ivc);
941    return 0;
942 fail:
943    memset_s(p, total_sz, 0, total_sz);
944    free(p);
945    free(ivc);
946    return ret;
947}
948
949static krb5_error_code
950encrypt_internal(krb5_context context,
951		 krb5_crypto crypto,
952		 const void *data,
953		 size_t len,
954		 krb5_data *result,
955		 void *ivec)
956{
957    size_t sz, block_sz, checksum_sz;
958    Checksum cksum;
959    unsigned char *p, *q;
960    krb5_error_code ret;
961    const struct _krb5_encryption_type *et = crypto->et;
962
963    checksum_sz = CHECKSUMSIZE(et->checksum);
964
965    sz = et->confoundersize + checksum_sz + len;
966    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
967    p = calloc(1, block_sz);
968    if (p == NULL)
969	return krb5_enomem(context);
970
971    q = p;
972    krb5_generate_random_block(q, et->confoundersize); /* XXX */
973    q += et->confoundersize;
974    memset(q, 0, checksum_sz);
975    q += checksum_sz;
976    memcpy(q, data, len);
977
978    ret = create_checksum(context,
979			  et->checksum,
980			  crypto,
981			  0,
982			  p,
983			  block_sz,
984			  &cksum);
985    if(ret == 0 && cksum.checksum.length != checksum_sz) {
986	krb5_clear_error_message (context);
987	free_Checksum(&cksum);
988	ret = KRB5_CRYPTO_INTERNAL;
989    }
990    if(ret)
991	goto fail;
992    memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
993    free_Checksum(&cksum);
994    ret = _key_schedule(context, &crypto->key);
995    if(ret)
996	goto fail;
997    ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
998    if (ret) {
999	memset(p, 0, block_sz);
1000	free(p);
1001	return ret;
1002    }
1003    result->data = p;
1004    result->length = block_sz;
1005    return 0;
1006 fail:
1007    memset(p, 0, block_sz);
1008    free(p);
1009    return ret;
1010}
1011
1012static krb5_error_code
1013encrypt_internal_special(krb5_context context,
1014			 krb5_crypto crypto,
1015			 int usage,
1016			 const void *data,
1017			 size_t len,
1018			 krb5_data *result,
1019			 void *ivec)
1020{
1021    struct _krb5_encryption_type *et = crypto->et;
1022    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1023    size_t sz = len + cksum_sz + et->confoundersize;
1024    char *tmp, *p;
1025    krb5_error_code ret;
1026
1027    tmp = malloc (sz);
1028    if (tmp == NULL)
1029	return krb5_enomem(context);
1030    p = tmp;
1031    memset (p, 0, cksum_sz);
1032    p += cksum_sz;
1033    krb5_generate_random_block(p, et->confoundersize);
1034    p += et->confoundersize;
1035    memcpy (p, data, len);
1036    ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
1037    if (ret) {
1038	memset(tmp, 0, sz);
1039	free(tmp);
1040	return ret;
1041    }
1042    result->data   = tmp;
1043    result->length = sz;
1044    return 0;
1045}
1046
1047static krb5_error_code
1048decrypt_internal_derived(krb5_context context,
1049			 krb5_crypto crypto,
1050			 unsigned usage,
1051			 void *data,
1052			 size_t len,
1053			 krb5_data *result,
1054			 void *ivec)
1055{
1056    size_t checksum_sz;
1057    Checksum cksum;
1058    unsigned char *p;
1059    krb5_error_code ret;
1060    struct _krb5_key_data *dkey;
1061    struct _krb5_encryption_type *et = crypto->et;
1062    unsigned long l;
1063
1064    checksum_sz = CHECKSUMSIZE(et->keyed_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    if (((len - checksum_sz) % et->padsize) != 0) {
1073	krb5_clear_error_message(context);
1074	return KRB5_BAD_MSIZE;
1075    }
1076
1077    p = malloc(len);
1078    if (len != 0 && p == NULL)
1079	return krb5_enomem(context);
1080    memcpy(p, data, len);
1081
1082    len -= checksum_sz;
1083
1084    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1085    if(ret) {
1086	free(p);
1087	return ret;
1088    }
1089    ret = _key_schedule(context, dkey);
1090    if(ret) {
1091	free(p);
1092	return ret;
1093    }
1094    ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1095    if (ret) {
1096	free(p);
1097	return ret;
1098    }
1099
1100    cksum.checksum.data   = p + len;
1101    cksum.checksum.length = checksum_sz;
1102    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1103
1104    ret = verify_checksum(context,
1105			  crypto,
1106			  INTEGRITY_USAGE(usage),
1107			  p,
1108			  len,
1109			  &cksum);
1110    if(ret) {
1111	free(p);
1112	return ret;
1113    }
1114    l = len - et->confoundersize;
1115    memmove(p, p + et->confoundersize, l);
1116    result->data = realloc(p, l);
1117    if(result->data == NULL && l != 0) {
1118	free(p);
1119	return krb5_enomem(context);
1120    }
1121    result->length = l;
1122    return 0;
1123}
1124
1125static krb5_error_code
1126decrypt_internal_enc_then_cksum(krb5_context context,
1127				krb5_crypto crypto,
1128				unsigned usage,
1129				void *data,
1130				size_t len,
1131				krb5_data *result,
1132				void *ivec)
1133{
1134    size_t checksum_sz;
1135    Checksum cksum;
1136    unsigned char *p;
1137    krb5_error_code ret;
1138    struct _krb5_key_data *dkey;
1139    struct _krb5_encryption_type *et = crypto->et;
1140    unsigned long l;
1141
1142    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1143    if (len < checksum_sz + et->confoundersize) {
1144	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1145			       N_("Encrypted data shorter then "
1146				  "checksum + confunder", ""));
1147	return KRB5_BAD_MSIZE;
1148    }
1149
1150    if (((len - checksum_sz) % et->padsize) != 0) {
1151	krb5_clear_error_message(context);
1152	return KRB5_BAD_MSIZE;
1153    }
1154
1155    len -= checksum_sz;
1156
1157    p = malloc(et->blocksize + len);
1158    if (p == NULL)
1159	return krb5_enomem(context);
1160
1161    if (ivec)
1162	memcpy(p, ivec, et->blocksize);
1163    else
1164	memset(p, 0, et->blocksize);
1165    memcpy(&p[et->blocksize], data, len);
1166
1167    cksum.checksum.data   = (unsigned char *)data + len;
1168    cksum.checksum.length = checksum_sz;
1169    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1170
1171    ret = verify_checksum(context,
1172			  crypto,
1173			  INTEGRITY_USAGE(usage),
1174			  p,
1175			  et->blocksize + len,
1176			  &cksum);
1177    if(ret) {
1178	free(p);
1179	return ret;
1180    }
1181
1182    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1183    if(ret) {
1184	free(p);
1185	return ret;
1186    }
1187    ret = _key_schedule(context, dkey);
1188    if(ret) {
1189	free(p);
1190	return ret;
1191    }
1192    ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec);
1193    if (ret) {
1194	free(p);
1195	return ret;
1196    }
1197
1198    l = len - et->confoundersize;
1199    memmove(p, p + et->blocksize + et->confoundersize, l);
1200    result->data = realloc(p, l);
1201    if(result->data == NULL && l != 0) {
1202	free(p);
1203	return krb5_enomem(context);
1204    }
1205    result->length = l;
1206    return 0;
1207}
1208
1209static krb5_error_code
1210decrypt_internal(krb5_context context,
1211		 krb5_crypto crypto,
1212		 void *data,
1213		 size_t len,
1214		 krb5_data *result,
1215		 void *ivec)
1216{
1217    krb5_error_code ret;
1218    unsigned char *p;
1219    Checksum cksum;
1220    size_t checksum_sz, l;
1221    struct _krb5_encryption_type *et = crypto->et;
1222
1223    if ((len % et->padsize) != 0) {
1224	krb5_clear_error_message(context);
1225	return KRB5_BAD_MSIZE;
1226    }
1227    checksum_sz = CHECKSUMSIZE(et->checksum);
1228    if (len < checksum_sz + et->confoundersize) {
1229	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1230			       N_("Encrypted data shorter then "
1231				  "checksum + confunder", ""));
1232	return KRB5_BAD_MSIZE;
1233    }
1234
1235    p = malloc(len);
1236    if (len != 0 && p == NULL)
1237	return krb5_enomem(context);
1238    memcpy(p, data, len);
1239
1240    ret = _key_schedule(context, &crypto->key);
1241    if(ret) {
1242	free(p);
1243	return ret;
1244    }
1245    ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1246    if (ret) {
1247	free(p);
1248	return ret;
1249    }
1250    ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1251    if(ret) {
1252 	free(p);
1253 	return ret;
1254    }
1255    memset(p + et->confoundersize, 0, checksum_sz);
1256    cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1257    ret = verify_checksum(context, NULL, 0, p, len, &cksum);
1258    free_Checksum(&cksum);
1259    if(ret) {
1260	free(p);
1261	return ret;
1262    }
1263    l = len - et->confoundersize - checksum_sz;
1264    memmove(p, p + et->confoundersize + checksum_sz, l);
1265    result->data = realloc(p, l);
1266    if(result->data == NULL && l != 0) {
1267	free(p);
1268	return krb5_enomem(context);
1269    }
1270    result->length = l;
1271    return 0;
1272}
1273
1274static krb5_error_code
1275decrypt_internal_special(krb5_context context,
1276			 krb5_crypto crypto,
1277			 int usage,
1278			 void *data,
1279			 size_t len,
1280			 krb5_data *result,
1281			 void *ivec)
1282{
1283    struct _krb5_encryption_type *et = crypto->et;
1284    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1285    size_t sz = len - cksum_sz - et->confoundersize;
1286    unsigned char *p;
1287    krb5_error_code ret;
1288
1289    if ((len % et->padsize) != 0) {
1290	krb5_clear_error_message(context);
1291	return KRB5_BAD_MSIZE;
1292    }
1293    if (len < cksum_sz + et->confoundersize) {
1294	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1295			       N_("Encrypted data shorter then "
1296				  "checksum + confunder", ""));
1297	return KRB5_BAD_MSIZE;
1298    }
1299
1300    p = malloc (len);
1301    if (p == NULL)
1302	return krb5_enomem(context);
1303    memcpy(p, data, len);
1304
1305    ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1306    if (ret) {
1307	free(p);
1308	return ret;
1309    }
1310
1311    memmove (p, p + cksum_sz + et->confoundersize, sz);
1312    result->data = realloc(p, sz);
1313    if(result->data == NULL && sz != 0) {
1314	free(p);
1315	return krb5_enomem(context);
1316    }
1317    result->length = sz;
1318    return 0;
1319}
1320
1321static krb5_crypto_iov *
1322iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type)
1323{
1324    size_t i;
1325    for (i = 0; i < num_data; i++)
1326	if (data[i].flags == type)
1327	    return &data[i];
1328    return NULL;
1329}
1330
1331static size_t
1332iov_enc_data_len(krb5_crypto_iov *data, int num_data)
1333{
1334    size_t i, len;
1335
1336    for (len = 0, i = 0; i < num_data; i++) {
1337	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1338	    continue;
1339	len += data[i].data.length;
1340    }
1341
1342    return len;
1343}
1344
1345static size_t
1346iov_sign_data_len(krb5_crypto_iov *data, int num_data)
1347{
1348    size_t i, len;
1349
1350    for (len = 0, i = 0; i < num_data; i++) {
1351	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1352	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1353	    continue;
1354	len += data[i].data.length;
1355    }
1356
1357    return len;
1358}
1359
1360static krb5_error_code
1361iov_coalesce(krb5_context context,
1362	     krb5_data *prefix,
1363	     krb5_crypto_iov *data,
1364	     int num_data,
1365	     krb5_boolean inc_sign_data,
1366	     krb5_data *out)
1367{
1368    unsigned char *p, *q;
1369    krb5_crypto_iov *hiv, *piv;
1370    size_t len;
1371    unsigned int i;
1372
1373    hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1374
1375    piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1376
1377    len = 0;
1378    if (prefix)
1379	len += prefix->length;
1380    len += hiv->data.length;
1381    if (inc_sign_data)
1382	len += iov_sign_data_len(data, num_data);
1383    else
1384	len += iov_enc_data_len(data, num_data);
1385    if (piv)
1386	len += piv->data.length;
1387
1388    p = q = malloc(len);
1389    if (p == NULL)
1390	return krb5_enomem(context);
1391
1392    if (prefix) {
1393	memcpy(q, prefix->data, prefix->length);
1394	q += prefix->length;
1395    }
1396    memcpy(q, hiv->data.data, hiv->data.length);
1397    q += hiv->data.length;
1398    for (i = 0; i < num_data; i++) {
1399	if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1400	    (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) {
1401	    memcpy(q, data[i].data.data, data[i].data.length);
1402	    q += data[i].data.length;
1403	}
1404    }
1405    if (piv)
1406	memset(q, 0, piv->data.length);
1407
1408    out->length = len;
1409    out->data = p;
1410
1411    return 0;
1412}
1413
1414static krb5_error_code
1415iov_uncoalesce(krb5_context context,
1416	       krb5_data *enc_data,
1417	       krb5_crypto_iov *data,
1418	       int num_data)
1419{
1420    unsigned char *q = enc_data->data;
1421    krb5_crypto_iov *hiv, *piv;
1422    unsigned int i;
1423
1424    hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1425
1426    piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1427
1428    memcpy(hiv->data.data, q, hiv->data.length);
1429    q += hiv->data.length;
1430
1431    for (i = 0; i < num_data; i++) {
1432	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1433	    continue;
1434	memcpy(data[i].data.data, q, data[i].data.length);
1435	q += data[i].data.length;
1436    }
1437    if (piv)
1438	memcpy(piv->data.data, q, piv->data.length);
1439
1440    return 0;
1441}
1442
1443static krb5_error_code
1444iov_pad_validate(const struct _krb5_encryption_type *et,
1445		 krb5_crypto_iov *data,
1446		 int num_data,
1447		 krb5_crypto_iov **ppiv)
1448{
1449    krb5_crypto_iov *piv;
1450    size_t sz, headersz, block_sz, pad_sz, len;
1451
1452    len = iov_enc_data_len(data, num_data);
1453
1454    headersz = et->confoundersize;
1455
1456    sz = headersz + len;
1457    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1458
1459    pad_sz = block_sz - sz;
1460
1461    piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1462    /* its ok to have no TYPE_PADDING if there is no padding */
1463    if (piv == NULL && pad_sz != 0)
1464	return KRB5_BAD_MSIZE;
1465    if (piv) {
1466	if (piv->data.length < pad_sz)
1467	    return KRB5_BAD_MSIZE;
1468	piv->data.length = pad_sz;
1469	if (pad_sz)
1470	    memset(piv->data.data, pad_sz, pad_sz);
1471	else
1472	    piv = NULL;
1473    }
1474
1475    *ppiv = piv;
1476    return 0;
1477}
1478
1479/**
1480 * Inline encrypt a kerberos message
1481 *
1482 * @param context Kerberos context
1483 * @param crypto Kerberos crypto context
1484 * @param usage Key usage for this buffer
1485 * @param data array of buffers to process
1486 * @param num_data length of array
1487 * @param ivec initial cbc/cts vector
1488 *
1489 * @return Return an error code or 0.
1490 * @ingroup krb5_crypto
1491 *
1492 * Kerberos encrypted data look like this:
1493 *
1494 * 1. KRB5_CRYPTO_TYPE_HEADER
1495 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1496 *    KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1497 *    have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1498 *    commonly used headers and trailers.
1499 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1500 * 4. KRB5_CRYPTO_TYPE_TRAILER
1501 */
1502
1503KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1504krb5_encrypt_iov_ivec(krb5_context context,
1505		      krb5_crypto crypto,
1506		      unsigned usage,
1507		      krb5_crypto_iov *data,
1508		      int num_data,
1509		      void *ivec)
1510{
1511    size_t headersz, trailersz;
1512    Checksum cksum;
1513    krb5_data enc_data, sign_data;
1514    krb5_error_code ret;
1515    struct _krb5_key_data *dkey;
1516    const struct _krb5_encryption_type *et = crypto->et;
1517    krb5_crypto_iov *tiv, *piv, *hiv;
1518
1519    if (num_data < 0) {
1520        krb5_clear_error_message(context);
1521	return KRB5_CRYPTO_INTERNAL;
1522    }
1523
1524    if(!derived_crypto(context, crypto)) {
1525	krb5_clear_error_message(context);
1526	return KRB5_CRYPTO_INTERNAL;
1527    }
1528
1529    krb5_data_zero(&enc_data);
1530    krb5_data_zero(&sign_data);
1531
1532    headersz = et->confoundersize;
1533    trailersz = CHECKSUMSIZE(et->keyed_checksum);
1534
1535    /* header */
1536    hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1537    if (hiv == NULL || hiv->data.length != headersz)
1538	return KRB5_BAD_MSIZE;
1539    krb5_generate_random_block(hiv->data.data, hiv->data.length);
1540
1541    /* padding */
1542    ret = iov_pad_validate(et, data, num_data, &piv);
1543    if(ret)
1544	goto cleanup;
1545
1546    /* trailer */
1547    tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1548    if (tiv == NULL || tiv->data.length != trailersz) {
1549	ret = KRB5_BAD_MSIZE;
1550	goto cleanup;
1551    }
1552
1553    if (et->flags & F_ENC_THEN_CKSUM) {
1554	unsigned char old_ivec[EVP_MAX_IV_LENGTH];
1555	krb5_data ivec_data;
1556
1557	ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1558	if(ret)
1559	    goto cleanup;
1560
1561	ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1562	if(ret)
1563	    goto cleanup;
1564
1565	ret = _key_schedule(context, dkey);
1566	if(ret)
1567	    goto cleanup;
1568
1569	heim_assert(et->blocksize <= sizeof(old_ivec),
1570		    "blocksize too big for ivec buffer");
1571
1572	if (ivec)
1573	    memcpy(old_ivec, ivec, et->blocksize);
1574	else
1575	    memset(old_ivec, 0, et->blocksize);
1576
1577	ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1578			     1, usage, ivec);
1579	if(ret)
1580	    goto cleanup;
1581
1582	ret = iov_uncoalesce(context, &enc_data, data, num_data);
1583	if(ret)
1584	    goto cleanup;
1585
1586	ivec_data.length = et->blocksize;
1587	ivec_data.data = old_ivec;
1588
1589	ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1590	if(ret)
1591	    goto cleanup;
1592    } else {
1593	ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data);
1594	if(ret)
1595	    goto cleanup;
1596    }
1597
1598    ret = create_checksum(context,
1599			  et->keyed_checksum,
1600			  crypto,
1601			  INTEGRITY_USAGE(usage),
1602			  sign_data.data,
1603			  sign_data.length,
1604			  &cksum);
1605    if(ret == 0 && cksum.checksum.length != trailersz) {
1606	free_Checksum (&cksum);
1607	krb5_clear_error_message (context);
1608	ret = KRB5_CRYPTO_INTERNAL;
1609    }
1610    if(ret)
1611	goto cleanup;
1612
1613    /* save cksum at end */
1614    memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1615    free_Checksum (&cksum);
1616
1617    if (!(et->flags & F_ENC_THEN_CKSUM)) {
1618	ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1619	if(ret)
1620	    goto cleanup;
1621
1622	ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1623	if(ret)
1624	    goto cleanup;
1625
1626	ret = _key_schedule(context, dkey);
1627	if(ret)
1628	    goto cleanup;
1629
1630	ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1631			     1, usage, ivec);
1632	if(ret)
1633	    goto cleanup;
1634
1635	ret = iov_uncoalesce(context, &enc_data, data, num_data);
1636	if(ret)
1637	    goto cleanup;
1638    }
1639
1640cleanup:
1641    if (enc_data.data) {
1642	memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1643	krb5_data_free(&enc_data);
1644    }
1645    if (sign_data.data) {
1646	memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1647	krb5_data_free(&sign_data);
1648    }
1649    return ret;
1650}
1651
1652/**
1653 * Inline decrypt a Kerberos message.
1654 *
1655 * @param context Kerberos context
1656 * @param crypto Kerberos crypto context
1657 * @param usage Key usage for this buffer
1658 * @param data array of buffers to process
1659 * @param num_data length of array
1660 * @param ivec initial cbc/cts vector
1661 *
1662 * @return Return an error code or 0.
1663 * @ingroup krb5_crypto
1664 *
1665 * 1. KRB5_CRYPTO_TYPE_HEADER
1666 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1667 *  any order, however the receiver have to aware of the
1668 *  order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1669 *  protocol headers and trailers. The output data will be of same
1670 *  size as the input data or shorter.
1671 */
1672
1673KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1674krb5_decrypt_iov_ivec(krb5_context context,
1675		      krb5_crypto crypto,
1676		      unsigned usage,
1677		      krb5_crypto_iov *data,
1678		      unsigned int num_data,
1679		      void *ivec)
1680{
1681    Checksum cksum;
1682    krb5_data enc_data, sign_data;
1683    krb5_error_code ret;
1684    struct _krb5_key_data *dkey;
1685    struct _krb5_encryption_type *et = crypto->et;
1686    krb5_crypto_iov *tiv, *hiv;
1687
1688    if(!derived_crypto(context, crypto)) {
1689	krb5_clear_error_message(context);
1690	return KRB5_CRYPTO_INTERNAL;
1691    }
1692
1693    /* header */
1694    hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1695    if (hiv == NULL || hiv->data.length != et->confoundersize)
1696	return KRB5_BAD_MSIZE;
1697
1698    /* trailer */
1699    tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1700    if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum))
1701	return KRB5_BAD_MSIZE;
1702
1703    /* padding */
1704    if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) {
1705	krb5_clear_error_message(context);
1706	return KRB5_BAD_MSIZE;
1707    }
1708
1709    krb5_data_zero(&enc_data);
1710    krb5_data_zero(&sign_data);
1711
1712    if (!(et->flags & F_ENC_THEN_CKSUM)) {
1713	ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1714	if(ret)
1715	    goto cleanup;
1716
1717	ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1718	if(ret)
1719	    goto cleanup;
1720
1721	ret = _key_schedule(context, dkey);
1722	if(ret)
1723	    goto cleanup;
1724
1725	ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1726			     0, usage, ivec);
1727	if(ret)
1728	    goto cleanup;
1729
1730	ret = iov_uncoalesce(context, &enc_data, data, num_data);
1731	if(ret)
1732	    goto cleanup;
1733
1734	ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data);
1735	if(ret)
1736	    goto cleanup;
1737    } else {
1738	krb5_data ivec_data;
1739	static unsigned char zero_ivec[EVP_MAX_IV_LENGTH];
1740
1741	heim_assert(et->blocksize <= sizeof(zero_ivec),
1742		    "blocksize too big for ivec buffer");
1743
1744	ivec_data.length = et->blocksize;
1745	ivec_data.data = ivec ? ivec : zero_ivec;
1746
1747	ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1748	if(ret)
1749	    goto cleanup;
1750    }
1751
1752    cksum.checksum.data   = tiv->data.data;
1753    cksum.checksum.length = tiv->data.length;
1754    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1755
1756    ret = verify_checksum(context,
1757			  crypto,
1758			  INTEGRITY_USAGE(usage),
1759			  sign_data.data,
1760			  sign_data.length,
1761			  &cksum);
1762    if(ret)
1763	goto cleanup;
1764
1765    if (et->flags & F_ENC_THEN_CKSUM) {
1766	ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1767	if(ret)
1768	    goto cleanup;
1769
1770	ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1771	if(ret)
1772	    goto cleanup;
1773
1774	ret = _key_schedule(context, dkey);
1775	if(ret)
1776	    goto cleanup;
1777
1778	ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1779			     0, usage, ivec);
1780	if(ret)
1781	    goto cleanup;
1782
1783	ret = iov_uncoalesce(context, &enc_data, data, num_data);
1784	if(ret)
1785	    goto cleanup;
1786    }
1787
1788cleanup:
1789    if (enc_data.data) {
1790	memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1791	krb5_data_free(&enc_data);
1792    }
1793    if (sign_data.data) {
1794	memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1795	krb5_data_free(&sign_data);
1796    }
1797    return ret;
1798}
1799
1800/**
1801 * Create a Kerberos message checksum.
1802 *
1803 * @param context Kerberos context
1804 * @param crypto Kerberos crypto context
1805 * @param usage Key usage for this buffer
1806 * @param data array of buffers to process
1807 * @param num_data length of array
1808 * @param type output data
1809 *
1810 * @return Return an error code or 0.
1811 * @ingroup krb5_crypto
1812 */
1813
1814KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1815krb5_create_checksum_iov(krb5_context context,
1816			 krb5_crypto crypto,
1817			 unsigned usage,
1818			 krb5_crypto_iov *data,
1819			 unsigned int num_data,
1820			 krb5_cksumtype *type)
1821{
1822    Checksum cksum;
1823    krb5_crypto_iov *civ;
1824    krb5_error_code ret;
1825    size_t i;
1826    size_t len;
1827    char *p, *q;
1828
1829    if(!derived_crypto(context, crypto)) {
1830	krb5_clear_error_message(context);
1831	return KRB5_CRYPTO_INTERNAL;
1832    }
1833
1834    civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1835    if (civ == NULL)
1836	return KRB5_BAD_MSIZE;
1837
1838    len = 0;
1839    for (i = 0; i < num_data; i++) {
1840	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1841	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1842	    continue;
1843	len += data[i].data.length;
1844    }
1845
1846    p = q = malloc(len);
1847
1848    for (i = 0; i < num_data; i++) {
1849	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1850	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1851	    continue;
1852	memcpy(q, data[i].data.data, data[i].data.length);
1853	q += data[i].data.length;
1854    }
1855
1856    ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1857    free(p);
1858    if (ret)
1859	return ret;
1860
1861    if (type)
1862	*type = cksum.cksumtype;
1863
1864    if (cksum.checksum.length > civ->data.length) {
1865	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1866			       N_("Checksum larger then input buffer", ""));
1867	free_Checksum(&cksum);
1868	return KRB5_BAD_MSIZE;
1869    }
1870
1871    civ->data.length = cksum.checksum.length;
1872    memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1873    free_Checksum(&cksum);
1874
1875    return 0;
1876}
1877
1878/**
1879 * Verify a Kerberos message checksum.
1880 *
1881 * @param context Kerberos context
1882 * @param crypto Kerberos crypto context
1883 * @param usage Key usage for this buffer
1884 * @param data array of buffers to process
1885 * @param num_data length of array
1886 * @param type return checksum type if not NULL
1887 *
1888 * @return Return an error code or 0.
1889 * @ingroup krb5_crypto
1890 */
1891
1892KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1893krb5_verify_checksum_iov(krb5_context context,
1894			 krb5_crypto crypto,
1895			 unsigned usage,
1896			 krb5_crypto_iov *data,
1897			 unsigned int num_data,
1898			 krb5_cksumtype *type)
1899{
1900    struct _krb5_encryption_type *et = crypto->et;
1901    Checksum cksum;
1902    krb5_crypto_iov *civ;
1903    krb5_error_code ret;
1904    size_t i;
1905    size_t len;
1906    char *p, *q;
1907
1908    if(!derived_crypto(context, crypto)) {
1909	krb5_clear_error_message(context);
1910	return KRB5_CRYPTO_INTERNAL;
1911    }
1912
1913    civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1914    if (civ == NULL)
1915	return KRB5_BAD_MSIZE;
1916
1917    len = 0;
1918    for (i = 0; i < num_data; i++) {
1919	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1920	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1921	    continue;
1922	len += data[i].data.length;
1923    }
1924
1925    p = q = malloc(len);
1926
1927    for (i = 0; i < num_data; i++) {
1928	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1929	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1930	    continue;
1931	memcpy(q, data[i].data.data, data[i].data.length);
1932	q += data[i].data.length;
1933    }
1934
1935    cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1936    cksum.checksum.length = civ->data.length;
1937    cksum.checksum.data = civ->data.data;
1938
1939    ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1940    free(p);
1941
1942    if (ret == 0 && type)
1943	*type = cksum.cksumtype;
1944
1945    return ret;
1946}
1947
1948
1949KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1950krb5_crypto_length(krb5_context context,
1951		   krb5_crypto crypto,
1952		   int type,
1953		   size_t *len)
1954{
1955    if (!derived_crypto(context, crypto)) {
1956	krb5_set_error_message(context, EINVAL, "not a derived crypto");
1957	return EINVAL;
1958    }
1959
1960    switch(type) {
1961    case KRB5_CRYPTO_TYPE_EMPTY:
1962	*len = 0;
1963	return 0;
1964    case KRB5_CRYPTO_TYPE_HEADER:
1965	*len = crypto->et->blocksize;
1966	return 0;
1967    case KRB5_CRYPTO_TYPE_DATA:
1968    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1969	/* len must already been filled in */
1970	return 0;
1971    case KRB5_CRYPTO_TYPE_PADDING:
1972	if (crypto->et->padsize > 1)
1973	    *len = crypto->et->padsize;
1974	else
1975	    *len = 0;
1976	return 0;
1977    case KRB5_CRYPTO_TYPE_TRAILER:
1978	*len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1979	return 0;
1980    case KRB5_CRYPTO_TYPE_CHECKSUM:
1981	if (crypto->et->keyed_checksum)
1982	    *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1983	else
1984	    *len = CHECKSUMSIZE(crypto->et->checksum);
1985	return 0;
1986    }
1987    krb5_set_error_message(context, EINVAL,
1988			   "%d not a supported type", type);
1989    return EINVAL;
1990}
1991
1992
1993KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1994krb5_crypto_length_iov(krb5_context context,
1995		       krb5_crypto crypto,
1996		       krb5_crypto_iov *data,
1997		       unsigned int num_data)
1998{
1999    krb5_error_code ret;
2000    size_t i;
2001
2002    for (i = 0; i < num_data; i++) {
2003	ret = krb5_crypto_length(context, crypto,
2004				 data[i].flags,
2005				 &data[i].data.length);
2006	if (ret)
2007	    return ret;
2008    }
2009    return 0;
2010}
2011
2012
2013KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2014krb5_encrypt_ivec(krb5_context context,
2015		  krb5_crypto crypto,
2016		  unsigned usage,
2017		  const void *data,
2018		  size_t len,
2019		  krb5_data *result,
2020		  void *ivec)
2021{
2022    krb5_error_code ret;
2023
2024    switch (crypto->et->flags & F_CRYPTO_MASK) {
2025    case F_RFC3961_ENC:
2026	ret = encrypt_internal_derived(context, crypto, usage,
2027				       data, len, result, ivec);
2028	break;
2029    case F_SPECIAL:
2030	ret = encrypt_internal_special (context, crypto, usage,
2031					data, len, result, ivec);
2032	break;
2033    case F_ENC_THEN_CKSUM:
2034	ret = encrypt_internal_enc_then_cksum(context, crypto, usage,
2035					      data, len, result, ivec);
2036	break;
2037    default:
2038	ret = encrypt_internal(context, crypto, data, len, result, ivec);
2039	break;
2040    }
2041
2042    return ret;
2043}
2044
2045KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2046krb5_encrypt(krb5_context context,
2047	     krb5_crypto crypto,
2048	     unsigned usage,
2049	     const void *data,
2050	     size_t len,
2051	     krb5_data *result)
2052{
2053    return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
2054}
2055
2056KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2057krb5_encrypt_EncryptedData(krb5_context context,
2058			   krb5_crypto crypto,
2059			   unsigned usage,
2060			   void *data,
2061			   size_t len,
2062			   int kvno,
2063			   EncryptedData *result)
2064{
2065    result->etype = CRYPTO_ETYPE(crypto);
2066    if(kvno){
2067	ALLOC(result->kvno, 1);
2068	*result->kvno = kvno;
2069    }else
2070	result->kvno = NULL;
2071    return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
2072}
2073
2074KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2075krb5_decrypt_ivec(krb5_context context,
2076		  krb5_crypto crypto,
2077		  unsigned usage,
2078		  void *data,
2079		  size_t len,
2080		  krb5_data *result,
2081		  void *ivec)
2082{
2083    krb5_error_code ret;
2084
2085    switch (crypto->et->flags & F_CRYPTO_MASK) {
2086    case F_RFC3961_ENC:
2087	ret = decrypt_internal_derived(context, crypto, usage,
2088				data, len, result, ivec);
2089	break;
2090    case F_SPECIAL:
2091	ret = decrypt_internal_special(context, crypto, usage,
2092				       data, len, result, ivec);
2093	break;
2094    case F_ENC_THEN_CKSUM:
2095	ret = decrypt_internal_enc_then_cksum(context, crypto, usage,
2096					      data, len, result, ivec);
2097	break;
2098    default:
2099	ret = decrypt_internal(context, crypto, data, len, result, ivec);
2100	break;
2101    }
2102
2103    return ret;
2104}
2105
2106KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2107krb5_decrypt(krb5_context context,
2108	     krb5_crypto crypto,
2109	     unsigned usage,
2110	     void *data,
2111	     size_t len,
2112	     krb5_data *result)
2113{
2114    return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
2115			      NULL);
2116}
2117
2118KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2119krb5_decrypt_EncryptedData(krb5_context context,
2120			   krb5_crypto crypto,
2121			   unsigned usage,
2122			   const EncryptedData *e,
2123			   krb5_data *result)
2124{
2125    return krb5_decrypt(context, crypto, usage,
2126			e->cipher.data, e->cipher.length, result);
2127}
2128
2129/************************************************************
2130 *                                                          *
2131 ************************************************************/
2132
2133static krb5_error_code
2134derive_key_rfc3961(krb5_context context,
2135		   struct _krb5_encryption_type *et,
2136		   struct _krb5_key_data *key,
2137		   const void *constant,
2138		   size_t len)
2139{
2140
2141    unsigned char *k = NULL;
2142    unsigned int nblocks = 0, i;
2143    krb5_error_code ret = 0;
2144    struct _krb5_key_type *kt = et->keytype;
2145
2146    if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
2147	nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
2148	k = malloc(nblocks * et->blocksize);
2149	if(k == NULL) {
2150	    ret = krb5_enomem(context);
2151	    goto out;
2152	}
2153	ret = _krb5_n_fold(constant, len, k, et->blocksize);
2154	if (ret) {
2155	    krb5_enomem(context);
2156	    goto out;
2157	}
2158
2159	for(i = 0; i < nblocks; i++) {
2160	    if(i > 0)
2161		memcpy(k + i * et->blocksize,
2162		       k + (i - 1) * et->blocksize,
2163		       et->blocksize);
2164	    (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
2165			   1, 0, NULL);
2166	}
2167    } else {
2168	/* this case is probably broken, but won't be run anyway */
2169	void *c = malloc(len);
2170	size_t res_len = (kt->bits + 7) / 8;
2171
2172	if(len != 0 && c == NULL) {
2173	    ret = krb5_enomem(context);
2174	    goto out;
2175	}
2176	memcpy(c, constant, len);
2177	(*et->encrypt)(context, key, c, len, 1, 0, NULL);
2178	k = malloc(res_len);
2179	if(res_len != 0 && k == NULL) {
2180	    free(c);
2181	    ret = krb5_enomem(context);
2182	    goto out;
2183	}
2184	ret = _krb5_n_fold(c, len, k, res_len);
2185	free(c);
2186	if (ret) {
2187	    krb5_enomem(context);
2188	    goto out;
2189	}
2190    }
2191
2192    if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1)
2193	_krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
2194    else
2195	memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
2196
2197 out:
2198    if (k) {
2199	memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize);
2200	free(k);
2201    }
2202    return ret;
2203}
2204
2205static krb5_error_code
2206derive_key_sp800_hmac(krb5_context context,
2207		      struct _krb5_encryption_type *et,
2208		      struct _krb5_key_data *key,
2209		      const void *constant,
2210		      size_t len)
2211{
2212    krb5_error_code ret;
2213    struct _krb5_key_type *kt = et->keytype;
2214    krb5_data label;
2215    const EVP_MD *md = NULL;
2216    const unsigned char *c = constant;
2217    size_t key_len;
2218    krb5_data K1;
2219
2220    ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md);
2221    if (ret)
2222	return ret;
2223
2224    /*
2225     * PRF usage: not handled here (output cannot be longer)
2226     * Integrity usage: truncated hash (half length)
2227     * Encryption usage: base key length
2228     */
2229    if (len == 5 && (c[4] == 0x99 || c[4] == 0x55))
2230	key_len = EVP_MD_size(md) / 2;
2231    else
2232	key_len = kt->size;
2233
2234    ret = krb5_data_alloc(&K1, key_len);
2235    if (ret)
2236	return ret;
2237
2238    label.data = (void *)constant;
2239    label.length = len;
2240
2241    ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue,
2242				   &label, NULL, md, &K1);
2243    if (ret == 0) {
2244	if (key->key->keyvalue.length > key_len)
2245	    key->key->keyvalue.length = key_len;
2246	memcpy(key->key->keyvalue.data, K1.data, key_len);
2247    }
2248
2249    memset_s(K1.data, K1.length, 0, K1.length);
2250    krb5_data_free(&K1);
2251
2252    return ret;
2253}
2254
2255KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2256_krb5_derive_key(krb5_context context,
2257		 struct _krb5_encryption_type *et,
2258		 struct _krb5_key_data *key,
2259		 const void *constant,
2260		 size_t len)
2261{
2262    krb5_error_code ret;
2263
2264    ret = _key_schedule(context, key);
2265    if(ret)
2266	return ret;
2267
2268    switch (et->flags & F_KDF_MASK) {
2269    case F_RFC3961_KDF:
2270	ret = derive_key_rfc3961(context, et, key, constant, len);
2271	break;
2272    case F_SP800_108_HMAC_KDF:
2273	ret = derive_key_sp800_hmac(context, et, key, constant, len);
2274	break;
2275    default:
2276	ret = KRB5_CRYPTO_INTERNAL;
2277	krb5_set_error_message(context, ret,
2278			       N_("derive_key() called with unknown keytype (%u)", ""),
2279			       et->keytype->type);
2280	break;
2281    }
2282
2283    if (key->schedule) {
2284	free_key_schedule(context, key, et);
2285	key->schedule = NULL;
2286    }
2287
2288    return ret;
2289}
2290
2291static struct _krb5_key_data *
2292_new_derived_key(krb5_crypto crypto, unsigned usage)
2293{
2294    struct _krb5_key_usage *d = crypto->key_usage;
2295    d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
2296    if(d == NULL)
2297	return NULL;
2298    crypto->key_usage = d;
2299    d += crypto->num_key_usage++;
2300    memset(d, 0, sizeof(*d));
2301    d->usage = usage;
2302    return &d->key;
2303}
2304
2305KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2306krb5_derive_key(krb5_context context,
2307		const krb5_keyblock *key,
2308		krb5_enctype etype,
2309		const void *constant,
2310		size_t constant_len,
2311		krb5_keyblock **derived_key)
2312{
2313    krb5_error_code ret;
2314    struct _krb5_encryption_type *et;
2315    struct _krb5_key_data d;
2316
2317    *derived_key = NULL;
2318
2319    et = _krb5_find_enctype (etype);
2320    if (et == NULL) {
2321        return unsupported_enctype (context, etype);
2322    }
2323
2324    ret = krb5_copy_keyblock(context, key, &d.key);
2325    if (ret)
2326	return ret;
2327
2328    d.schedule = NULL;
2329    ret = _krb5_derive_key(context, et, &d, constant, constant_len);
2330    if (ret == 0)
2331	ret = krb5_copy_keyblock(context, d.key, derived_key);
2332    _krb5_free_key_data(context, &d, et);
2333    return ret;
2334}
2335
2336static krb5_error_code
2337_get_derived_key(krb5_context context,
2338		 krb5_crypto crypto,
2339		 unsigned usage,
2340		 struct _krb5_key_data **key)
2341{
2342    int i;
2343    struct _krb5_key_data *d;
2344    unsigned char constant[5];
2345
2346    *key = NULL;
2347    for(i = 0; i < crypto->num_key_usage; i++)
2348	if(crypto->key_usage[i].usage == usage) {
2349	    *key = &crypto->key_usage[i].key;
2350	    return 0;
2351	}
2352    d = _new_derived_key(crypto, usage);
2353    if (d == NULL)
2354	return krb5_enomem(context);
2355    *key = d;
2356    krb5_copy_keyblock(context, crypto->key.key, &d->key);
2357    _krb5_put_int(constant, usage, sizeof(constant));
2358    return _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2359}
2360
2361/**
2362 * Create a crypto context used for all encryption and signature
2363 * operation. The encryption type to use is taken from the key, but
2364 * can be overridden with the enctype parameter.  This can be useful
2365 * for encryptions types which is compatiable (DES for example).
2366 *
2367 * To free the crypto context, use krb5_crypto_destroy().
2368 *
2369 * @param context Kerberos context
2370 * @param key the key block information with all key data
2371 * @param etype the encryption type
2372 * @param crypto the resulting crypto context
2373 *
2374 * @return Return an error code or 0.
2375 *
2376 * @ingroup krb5_crypto
2377 */
2378
2379KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2380krb5_crypto_init(krb5_context context,
2381		 const krb5_keyblock *key,
2382		 krb5_enctype etype,
2383		 krb5_crypto *crypto)
2384{
2385    krb5_error_code ret;
2386    ALLOC(*crypto, 1);
2387    if (*crypto == NULL)
2388	return krb5_enomem(context);
2389    if(etype == (krb5_enctype)ETYPE_NULL)
2390	etype = key->keytype;
2391    (*crypto)->et = _krb5_find_enctype(etype);
2392    if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2393	free(*crypto);
2394	*crypto = NULL;
2395	return unsupported_enctype(context, etype);
2396    }
2397    if((*crypto)->et->keytype->size != key->keyvalue.length) {
2398	free(*crypto);
2399	*crypto = NULL;
2400	krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2401				"encryption key has bad length");
2402	return KRB5_BAD_KEYSIZE;
2403    }
2404    ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2405    if(ret) {
2406	free(*crypto);
2407	*crypto = NULL;
2408	return ret;
2409    }
2410    (*crypto)->key.schedule = NULL;
2411    (*crypto)->num_key_usage = 0;
2412    (*crypto)->key_usage = NULL;
2413    return 0;
2414}
2415
2416static void
2417free_key_schedule(krb5_context context,
2418		  struct _krb5_key_data *key,
2419		  struct _krb5_encryption_type *et)
2420{
2421    if (et->keytype->cleanup)
2422	(*et->keytype->cleanup)(context, key);
2423    memset(key->schedule->data, 0, key->schedule->length);
2424    krb5_free_data(context, key->schedule);
2425}
2426
2427KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2428_krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2429	      struct _krb5_encryption_type *et)
2430{
2431    krb5_free_keyblock(context, key->key);
2432    if(key->schedule) {
2433	free_key_schedule(context, key, et);
2434	key->schedule = NULL;
2435    }
2436}
2437
2438static void
2439free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2440	       struct _krb5_encryption_type *et)
2441{
2442    _krb5_free_key_data(context, &ku->key, et);
2443}
2444
2445/**
2446 * Free a crypto context created by krb5_crypto_init().
2447 *
2448 * @param context Kerberos context
2449 * @param crypto crypto context to free
2450 *
2451 * @return Return an error code or 0.
2452 *
2453 * @ingroup krb5_crypto
2454 */
2455
2456KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2457krb5_crypto_destroy(krb5_context context,
2458		    krb5_crypto crypto)
2459{
2460    int i;
2461
2462    for(i = 0; i < crypto->num_key_usage; i++)
2463	free_key_usage(context, &crypto->key_usage[i], crypto->et);
2464    free(crypto->key_usage);
2465    _krb5_free_key_data(context, &crypto->key, crypto->et);
2466    free (crypto);
2467    return 0;
2468}
2469
2470/**
2471 * Return the blocksize used algorithm referenced by the crypto context
2472 *
2473 * @param context Kerberos context
2474 * @param crypto crypto context to query
2475 * @param blocksize the resulting blocksize
2476 *
2477 * @return Return an error code or 0.
2478 *
2479 * @ingroup krb5_crypto
2480 */
2481
2482KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2483krb5_crypto_getblocksize(krb5_context context,
2484			 krb5_crypto crypto,
2485			 size_t *blocksize)
2486{
2487    *blocksize = crypto->et->blocksize;
2488    return 0;
2489}
2490
2491/**
2492 * Return the encryption type used by the crypto context
2493 *
2494 * @param context Kerberos context
2495 * @param crypto crypto context to query
2496 * @param enctype the resulting encryption type
2497 *
2498 * @return Return an error code or 0.
2499 *
2500 * @ingroup krb5_crypto
2501 */
2502
2503KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2504krb5_crypto_getenctype(krb5_context context,
2505		       krb5_crypto crypto,
2506		       krb5_enctype *enctype)
2507{
2508    *enctype = crypto->et->type;
2509    return 0;
2510}
2511
2512/**
2513 * Return the padding size used by the crypto context
2514 *
2515 * @param context Kerberos context
2516 * @param crypto crypto context to query
2517 * @param padsize the return padding size
2518 *
2519 * @return Return an error code or 0.
2520 *
2521 * @ingroup krb5_crypto
2522 */
2523
2524KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2525krb5_crypto_getpadsize(krb5_context context,
2526                       krb5_crypto crypto,
2527                       size_t *padsize)
2528{
2529    *padsize = crypto->et->padsize;
2530    return 0;
2531}
2532
2533/**
2534 * Return the confounder size used by the crypto context
2535 *
2536 * @param context Kerberos context
2537 * @param crypto crypto context to query
2538 * @param confoundersize the returned confounder size
2539 *
2540 * @return Return an error code or 0.
2541 *
2542 * @ingroup krb5_crypto
2543 */
2544
2545KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2546krb5_crypto_getconfoundersize(krb5_context context,
2547                              krb5_crypto crypto,
2548                              size_t *confoundersize)
2549{
2550    *confoundersize = crypto->et->confoundersize;
2551    return 0;
2552}
2553
2554
2555/**
2556 * Disable encryption type
2557 *
2558 * @param context Kerberos 5 context
2559 * @param enctype encryption type to disable
2560 *
2561 * @return Return an error code or 0.
2562 *
2563 * @ingroup krb5_crypto
2564 */
2565
2566KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2567krb5_enctype_disable(krb5_context context,
2568		     krb5_enctype enctype)
2569{
2570    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2571    if(et == NULL) {
2572	if (context)
2573	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2574				    N_("encryption type %d not supported", ""),
2575				    enctype);
2576	return KRB5_PROG_ETYPE_NOSUPP;
2577    }
2578    et->flags |= F_DISABLED;
2579    return 0;
2580}
2581
2582/**
2583 * Enable encryption type
2584 *
2585 * @param context Kerberos 5 context
2586 * @param enctype encryption type to enable
2587 *
2588 * @return Return an error code or 0.
2589 *
2590 * @ingroup krb5_crypto
2591 */
2592
2593KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2594krb5_enctype_enable(krb5_context context,
2595		    krb5_enctype enctype)
2596{
2597    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2598    if(et == NULL) {
2599	if (context)
2600	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2601				    N_("encryption type %d not supported", ""),
2602				    enctype);
2603	return KRB5_PROG_ETYPE_NOSUPP;
2604    }
2605    et->flags &= ~F_DISABLED;
2606    return 0;
2607}
2608
2609/**
2610 * Enable or disable all weak encryption types
2611 *
2612 * @param context Kerberos 5 context
2613 * @param enable true to enable, false to disable
2614 *
2615 * @return Return an error code or 0.
2616 *
2617 * @ingroup krb5_crypto
2618 */
2619
2620KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2621krb5_allow_weak_crypto(krb5_context context,
2622		       krb5_boolean enable)
2623{
2624    int i;
2625
2626    for(i = 0; i < _krb5_num_etypes; i++)
2627	if(_krb5_etypes[i]->flags & F_WEAK) {
2628	    if(enable)
2629		_krb5_etypes[i]->flags &= ~F_DISABLED;
2630	    else
2631		_krb5_etypes[i]->flags |= F_DISABLED;
2632	}
2633    return 0;
2634}
2635
2636/**
2637 * Returns is the encryption is strong or weak
2638 *
2639 * @param context Kerberos 5 context
2640 * @param enctype encryption type to probe
2641 *
2642 * @return Returns true if encryption type is weak or is not supported.
2643 *
2644 * @ingroup krb5_crypto
2645 */
2646
2647KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2648krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype)
2649{
2650    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2651    if(et == NULL || (et->flags & F_WEAK))
2652	return TRUE;
2653    return FALSE;
2654}
2655
2656/**
2657 * Returns whether the encryption type should use randomly generated salts
2658 *
2659 * @param context Kerberos 5 context
2660 * @param enctype encryption type to probe
2661 *
2662 * @return Returns true if generated salts should have random component
2663 *
2664 * @ingroup krb5_crypto
2665 */
2666KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2667_krb5_enctype_requires_random_salt(krb5_context context,
2668				   krb5_enctype enctype)
2669{
2670    struct _krb5_encryption_type *et;
2671
2672    et = _krb5_find_enctype (enctype);
2673
2674    return et && (et->flags & F_SP800_108_HMAC_KDF);
2675}
2676
2677static size_t
2678wrapped_length (krb5_context context,
2679		krb5_crypto  crypto,
2680		size_t       data_len)
2681{
2682    struct _krb5_encryption_type *et = crypto->et;
2683    size_t padsize = et->padsize;
2684    size_t checksumsize = CHECKSUMSIZE(et->checksum);
2685    size_t res;
2686
2687    res =  et->confoundersize + checksumsize + data_len;
2688    res =  (res + padsize - 1) / padsize * padsize;
2689    return res;
2690}
2691
2692static size_t
2693wrapped_length_dervied (krb5_context context,
2694			krb5_crypto  crypto,
2695			size_t       data_len)
2696{
2697    struct _krb5_encryption_type *et = crypto->et;
2698    size_t padsize = et->padsize;
2699    size_t res;
2700
2701    res =  et->confoundersize + data_len;
2702    res =  (res + padsize - 1) / padsize * padsize;
2703    if (et->keyed_checksum)
2704	res += et->keyed_checksum->checksumsize;
2705    else
2706	res += et->checksum->checksumsize;
2707    return res;
2708}
2709
2710/*
2711 * Return the size of an encrypted packet of length `data_len'
2712 */
2713
2714KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2715krb5_get_wrapped_length (krb5_context context,
2716			 krb5_crypto  crypto,
2717			 size_t       data_len)
2718{
2719    if (derived_crypto (context, crypto))
2720	return wrapped_length_dervied (context, crypto, data_len);
2721    else
2722	return wrapped_length (context, crypto, data_len);
2723}
2724
2725/*
2726 * Return the size of an encrypted packet of length `data_len'
2727 */
2728
2729static size_t
2730crypto_overhead (krb5_context context,
2731		 krb5_crypto  crypto)
2732{
2733    struct _krb5_encryption_type *et = crypto->et;
2734    size_t res;
2735
2736    res = CHECKSUMSIZE(et->checksum);
2737    res += et->confoundersize;
2738    if (et->padsize > 1)
2739	res += et->padsize;
2740    return res;
2741}
2742
2743static size_t
2744crypto_overhead_dervied (krb5_context context,
2745			 krb5_crypto  crypto)
2746{
2747    struct _krb5_encryption_type *et = crypto->et;
2748    size_t res;
2749
2750    if (et->keyed_checksum)
2751	res = CHECKSUMSIZE(et->keyed_checksum);
2752    else
2753	res = CHECKSUMSIZE(et->checksum);
2754    res += et->confoundersize;
2755    if (et->padsize > 1)
2756	res += et->padsize;
2757    return res;
2758}
2759
2760KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2761krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2762{
2763    if (derived_crypto (context, crypto))
2764	return crypto_overhead_dervied (context, crypto);
2765    else
2766	return crypto_overhead (context, crypto);
2767}
2768
2769/**
2770 * Converts the random bytestring to a protocol key according to
2771 * Kerberos crypto frame work. It may be assumed that all the bits of
2772 * the input string are equally random, even though the entropy
2773 * present in the random source may be limited.
2774 *
2775 * @param context Kerberos 5 context
2776 * @param type the enctype resulting key will be of
2777 * @param data input random data to convert to a key
2778 * @param size size of input random data, at least krb5_enctype_keysize() long
2779 * @param key key, output key, free with krb5_free_keyblock_contents()
2780 *
2781 * @return Return an error code or 0.
2782 *
2783 * @ingroup krb5_crypto
2784 */
2785
2786KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2787krb5_random_to_key(krb5_context context,
2788		   krb5_enctype type,
2789		   const void *data,
2790		   size_t size,
2791		   krb5_keyblock *key)
2792{
2793    krb5_error_code ret;
2794    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2795    if(et == NULL) {
2796	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2797			       N_("encryption type %d not supported", ""),
2798			       type);
2799	return KRB5_PROG_ETYPE_NOSUPP;
2800    }
2801    if ((et->keytype->bits + 7) / 8 > size) {
2802	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2803			       N_("encryption key %s needs %d bytes "
2804				  "of random to make an encryption key "
2805				  "out of it", ""),
2806			       et->name, (int)et->keytype->size);
2807	return KRB5_PROG_ETYPE_NOSUPP;
2808    }
2809    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2810    if(ret)
2811	return ret;
2812    key->keytype = type;
2813    if (et->keytype->random_to_key)
2814 	(*et->keytype->random_to_key)(context, key, data, size);
2815    else
2816	memcpy(key->keyvalue.data, data, et->keytype->size);
2817
2818    return 0;
2819}
2820
2821
2822
2823KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2824krb5_crypto_prf_length(krb5_context context,
2825		       krb5_enctype type,
2826		       size_t *length)
2827{
2828    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2829
2830    if(et == NULL || et->prf_length == 0) {
2831	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2832			       N_("encryption type %d not supported", ""),
2833			       type);
2834	return KRB5_PROG_ETYPE_NOSUPP;
2835    }
2836
2837    *length = et->prf_length;
2838    return 0;
2839}
2840
2841KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2842krb5_crypto_prf(krb5_context context,
2843		const krb5_crypto crypto,
2844		const krb5_data *input,
2845		krb5_data *output)
2846{
2847    struct _krb5_encryption_type *et = crypto->et;
2848
2849    krb5_data_zero(output);
2850
2851    if(et->prf == NULL) {
2852	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2853			       "kerberos prf for %s not supported",
2854			       et->name);
2855	return KRB5_PROG_ETYPE_NOSUPP;
2856    }
2857
2858    return (*et->prf)(context, crypto, input, output);
2859}
2860
2861static krb5_error_code
2862krb5_crypto_prfplus(krb5_context context,
2863		    const krb5_crypto crypto,
2864		    const krb5_data *input,
2865		    size_t length,
2866		    krb5_data *output)
2867{
2868    krb5_error_code ret;
2869    krb5_data input2;
2870    unsigned char i = 1;
2871    unsigned char *p;
2872
2873    krb5_data_zero(&input2);
2874    krb5_data_zero(output);
2875
2876    krb5_clear_error_message(context);
2877
2878    ret = krb5_data_alloc(output, length);
2879    if (ret) goto out;
2880    ret = krb5_data_alloc(&input2, input->length + 1);
2881    if (ret) goto out;
2882
2883    krb5_clear_error_message(context);
2884
2885    memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2886
2887    p = output->data;
2888
2889    while (length) {
2890	krb5_data block;
2891
2892	((unsigned char *)input2.data)[0] = i++;
2893
2894	ret = krb5_crypto_prf(context, crypto, &input2, &block);
2895	if (ret)
2896	    goto out;
2897
2898	if (block.length < length) {
2899	    memcpy(p, block.data, block.length);
2900	    length -= block.length;
2901	} else {
2902	    memcpy(p, block.data, length);
2903	    length = 0;
2904	}
2905	p += block.length;
2906	krb5_data_free(&block);
2907    }
2908
2909 out:
2910    krb5_data_free(&input2);
2911    if (ret)
2912	krb5_data_free(output);
2913    return ret;
2914}
2915
2916/**
2917 * The FX-CF2 key derivation function, used in FAST and preauth framework.
2918 *
2919 * @param context Kerberos 5 context
2920 * @param crypto1 first key to combine
2921 * @param crypto2 second key to combine
2922 * @param pepper1 factor to combine with first key to garante uniqueness
2923 * @param pepper2 factor to combine with second key to garante uniqueness
2924 * @param enctype the encryption type of the resulting key
2925 * @param res allocated key, free with krb5_free_keyblock_contents()
2926 *
2927 * @return Return an error code or 0.
2928 *
2929 * @ingroup krb5_crypto
2930 */
2931
2932KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2933krb5_crypto_fx_cf2(krb5_context context,
2934		   const krb5_crypto crypto1,
2935		   const krb5_crypto crypto2,
2936		   krb5_data *pepper1,
2937		   krb5_data *pepper2,
2938		   krb5_enctype enctype,
2939		   krb5_keyblock *res)
2940{
2941    krb5_error_code ret;
2942    krb5_data os1, os2;
2943    size_t i, keysize;
2944
2945    memset(res, 0, sizeof(*res));
2946    krb5_data_zero(&os1);
2947    krb5_data_zero(&os2);
2948
2949    ret = krb5_enctype_keybits(context, enctype, &keysize);
2950    if (ret)
2951	return ret;
2952    keysize = (keysize + 7) / 8;
2953
2954    ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2955    if (ret)
2956	goto out;
2957    ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2958    if (ret)
2959	goto out;
2960
2961    res->keytype = enctype;
2962    {
2963	unsigned char *p1 = os1.data, *p2 = os2.data;
2964	for (i = 0; i < keysize; i++)
2965	    p1[i] ^= p2[i];
2966    }
2967    ret = krb5_random_to_key(context, enctype, os1.data, keysize, res);
2968 out:
2969    krb5_data_free(&os1);
2970    krb5_data_free(&os2);
2971
2972    return ret;
2973}
2974
2975
2976
2977#ifndef HEIMDAL_SMALLER
2978
2979/**
2980 * Deprecated: keytypes doesn't exists, they are really enctypes.
2981 *
2982 * @ingroup krb5_deprecated
2983 */
2984
2985KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2986krb5_keytype_to_enctypes (krb5_context context,
2987			  krb5_keytype keytype,
2988			  unsigned *len,
2989			  krb5_enctype **val)
2990    KRB5_DEPRECATED_FUNCTION("Use X instead")
2991{
2992    int i;
2993    unsigned n = 0;
2994    krb5_enctype *ret;
2995
2996    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2997	if (_krb5_etypes[i]->keytype->type == keytype
2998	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2999	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3000	    ++n;
3001    }
3002    if (n == 0) {
3003	krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
3004			       "Keytype have no mapping");
3005	return KRB5_PROG_KEYTYPE_NOSUPP;
3006    }
3007
3008    ret = malloc(n * sizeof(*ret));
3009    if (ret == NULL && n != 0)
3010	return krb5_enomem(context);
3011    n = 0;
3012    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3013	if (_krb5_etypes[i]->keytype->type == keytype
3014	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
3015	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3016	    ret[n++] = _krb5_etypes[i]->type;
3017    }
3018    *len = n;
3019    *val = ret;
3020    return 0;
3021}
3022
3023/**
3024 * Deprecated: keytypes doesn't exists, they are really enctypes.
3025 *
3026 * @ingroup krb5_deprecated
3027 */
3028
3029/* if two enctypes have compatible keys */
3030KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
3031krb5_enctypes_compatible_keys(krb5_context context,
3032			      krb5_enctype etype1,
3033			      krb5_enctype etype2)
3034    KRB5_DEPRECATED_FUNCTION("Use X instead")
3035{
3036    struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
3037    struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
3038    return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
3039}
3040
3041#endif /* HEIMDAL_SMALLER */
3042