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