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