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