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