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