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