2502cc672f50774160e21d9a92d2b579b52de145
[ira/wip.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 #define KRB5_DEPRECATED
35
36 #include "krb5_locl.h"
37 #include <pkinit_asn1.h>
38
39 #ifndef HEIMDAL_SMALLER
40 #define DES3_OLD_ENCTYPE 1
41 #endif
42
43 struct key_data {
44     krb5_keyblock *key;
45     krb5_data *schedule;
46 };
47
48 struct key_usage {
49     unsigned usage;
50     struct key_data key;
51 };
52
53 struct krb5_crypto_data {
54     struct encryption_type *et;
55     struct key_data key;
56     int num_key_usage;
57     struct key_usage *key_usage;
58 };
59
60 #define CRYPTO_ETYPE(C) ((C)->et->type)
61
62 /* bits for `flags' below */
63 #define F_KEYED          1      /* checksum is keyed */
64 #define F_CPROOF         2      /* checksum is collision proof */
65 #define F_DERIVED        4      /* uses derived keys */
66 #define F_VARIANT        8      /* uses `variant' keys (6.4.3) */
67 #define F_PSEUDO        16      /* not a real protocol type */
68 #define F_SPECIAL       32      /* backwards */
69 #define F_DISABLED      64      /* enctype/checksum disabled */
70 #define F_WEAK         128      /* enctype is considered weak */
71
72 struct salt_type {
73     krb5_salttype type;
74     const char *name;
75     krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data,
76                                      krb5_salt, krb5_data, krb5_keyblock*);
77 };
78
79 struct key_type {
80     krb5_keytype type; /* XXX */
81     const char *name;
82     size_t bits;
83     size_t size;
84     size_t schedule_size;
85     void (*random_key)(krb5_context, krb5_keyblock*);
86     void (*schedule)(krb5_context, struct key_type *, struct key_data *);
87     struct salt_type *string_to_key;
88     void (*random_to_key)(krb5_context, krb5_keyblock*, const void*, size_t);
89     void (*cleanup)(krb5_context, struct key_data *);
90     const EVP_CIPHER *(*evp)(void);
91 };
92
93 struct checksum_type {
94     krb5_cksumtype type;
95     const char *name;
96     size_t blocksize;
97     size_t checksumsize;
98     unsigned flags;
99     krb5_error_code (*checksum)(krb5_context context,
100                                 struct key_data *key,
101                                 const void *buf, size_t len,
102                                 unsigned usage,
103                                 Checksum *csum);
104     krb5_error_code (*verify)(krb5_context context,
105                               struct key_data *key,
106                               const void *buf, size_t len,
107                               unsigned usage,
108                               Checksum *csum);
109 };
110
111 struct encryption_type {
112     krb5_enctype type;
113     const char *name;
114     size_t blocksize;
115     size_t padsize;
116     size_t confoundersize;
117     struct key_type *keytype;
118     struct checksum_type *checksum;
119     struct checksum_type *keyed_checksum;
120     unsigned flags;
121     krb5_error_code (*encrypt)(krb5_context context,
122                                struct key_data *key,
123                                void *data, size_t len,
124                                krb5_boolean encryptp,
125                                int usage,
126                                void *ivec);
127     size_t prf_length;
128     krb5_error_code (*prf)(krb5_context,
129                            krb5_crypto, const krb5_data *, krb5_data *);
130 };
131
132 #define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
133 #define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)
134 #define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)
135
136 static struct checksum_type *_find_checksum(krb5_cksumtype type);
137 static struct encryption_type *_find_enctype(krb5_enctype type);
138 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
139                                         unsigned, struct key_data**);
140 static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
141 static krb5_error_code derive_key(krb5_context context,
142                                   struct encryption_type *et,
143                                   struct key_data *key,
144                                   const void *constant,
145                                   size_t len);
146 static krb5_error_code hmac(krb5_context context,
147                             struct checksum_type *cm,
148                             const void *data,
149                             size_t len,
150                             unsigned usage,
151                             struct key_data *keyblock,
152                             Checksum *result);
153 static void free_key_data(krb5_context,
154                           struct key_data *,
155                           struct encryption_type *);
156 static void free_key_schedule(krb5_context,
157                               struct key_data *,
158                               struct encryption_type *);
159 static krb5_error_code usage2arcfour (krb5_context, unsigned *);
160 static void xor (DES_cblock *, const unsigned char *);
161
162 /************************************************************
163  *                                                          *
164  ************************************************************/
165
166 struct evp_schedule {
167     EVP_CIPHER_CTX ectx;
168     EVP_CIPHER_CTX dctx;
169 };
170
171
172 static HEIMDAL_MUTEX crypto_mutex = HEIMDAL_MUTEX_INITIALIZER;
173
174 #ifdef HEIM_WEAK_CRYPTO
175 static void
176 krb5_DES_random_key(krb5_context context,
177                     krb5_keyblock *key)
178 {
179     DES_cblock *k = key->keyvalue.data;
180     do {
181         krb5_generate_random_block(k, sizeof(DES_cblock));
182         DES_set_odd_parity(k);
183     } while(DES_is_weak_key(k));
184 }
185
186 static void
187 krb5_DES_schedule_old(krb5_context context,
188                       struct key_type *kt,
189                       struct key_data *key)
190 {
191     DES_set_key_unchecked(key->key->keyvalue.data, key->schedule->data);
192 }
193
194 #ifdef ENABLE_AFS_STRING_TO_KEY
195
196 /* This defines the Andrew string_to_key function.  It accepts a password
197  * string as input and converts it via a one-way encryption algorithm to a DES
198  * encryption key.  It is compatible with the original Andrew authentication
199  * service password database.
200  */
201
202 /*
203  * Short passwords, i.e 8 characters or less.
204  */
205 static void
206 krb5_DES_AFS3_CMU_string_to_key (krb5_data pw,
207                                  krb5_data cell,
208                                  DES_cblock *key)
209 {
210     char  password[8+1];        /* crypt is limited to 8 chars anyway */
211     int   i;
212
213     for(i = 0; i < 8; i++) {
214         char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^
215             ((i < cell.length) ?
216              tolower(((unsigned char*)cell.data)[i]) : 0);
217         password[i] = c ? c : 'X';
218     }
219     password[8] = '\0';
220
221     memcpy(key, crypt(password, "p1") + 2, sizeof(DES_cblock));
222
223     /* parity is inserted into the LSB so left shift each byte up one
224        bit. This allows ascii characters with a zero MSB to retain as
225        much significance as possible. */
226     for (i = 0; i < sizeof(DES_cblock); i++)
227         ((unsigned char*)key)[i] <<= 1;
228     DES_set_odd_parity (key);
229 }
230
231 /*
232  * Long passwords, i.e 9 characters or more.
233  */
234 static void
235 krb5_DES_AFS3_Transarc_string_to_key (krb5_data pw,
236                                       krb5_data cell,
237                                       DES_cblock *key)
238 {
239     DES_key_schedule schedule;
240     DES_cblock temp_key;
241     DES_cblock ivec;
242     char password[512];
243     size_t passlen;
244
245     memcpy(password, pw.data, min(pw.length, sizeof(password)));
246     if(pw.length < sizeof(password)) {
247         int len = min(cell.length, sizeof(password) - pw.length);
248         int i;
249
250         memcpy(password + pw.length, cell.data, len);
251         for (i = pw.length; i < pw.length + len; ++i)
252             password[i] = tolower((unsigned char)password[i]);
253     }
254     passlen = min(sizeof(password), pw.length + cell.length);
255     memcpy(&ivec, "kerberos", 8);
256     memcpy(&temp_key, "kerberos", 8);
257     DES_set_odd_parity (&temp_key);
258     DES_set_key_unchecked (&temp_key, &schedule);
259     DES_cbc_cksum ((void*)password, &ivec, passlen, &schedule, &ivec);
260
261     memcpy(&temp_key, &ivec, 8);
262     DES_set_odd_parity (&temp_key);
263     DES_set_key_unchecked (&temp_key, &schedule);
264     DES_cbc_cksum ((void*)password, key, passlen, &schedule, &ivec);
265     memset(&schedule, 0, sizeof(schedule));
266     memset(&temp_key, 0, sizeof(temp_key));
267     memset(&ivec, 0, sizeof(ivec));
268     memset(password, 0, sizeof(password));
269
270     DES_set_odd_parity (key);
271 }
272
273 static krb5_error_code
274 DES_AFS3_string_to_key(krb5_context context,
275                        krb5_enctype enctype,
276                        krb5_data password,
277                        krb5_salt salt,
278                        krb5_data opaque,
279                        krb5_keyblock *key)
280 {
281     DES_cblock tmp;
282     if(password.length > 8)
283         krb5_DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp);
284     else
285         krb5_DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp);
286     key->keytype = enctype;
287     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
288     memset(&key, 0, sizeof(key));
289     return 0;
290 }
291 #endif /* ENABLE_AFS_STRING_TO_KEY */
292
293 static void
294 DES_string_to_key_int(unsigned char *data, size_t length, DES_cblock *key)
295 {
296     DES_key_schedule schedule;
297     int i;
298     int reverse = 0;
299     unsigned char *p;
300
301     unsigned char swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
302                              0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
303     memset(key, 0, 8);
304
305     p = (unsigned char*)key;
306     for (i = 0; i < length; i++) {
307         unsigned char tmp = data[i];
308         if (!reverse)
309             *p++ ^= (tmp << 1);
310         else
311             *--p ^= (swap[tmp & 0xf] << 4) | swap[(tmp & 0xf0) >> 4];
312         if((i % 8) == 7)
313             reverse = !reverse;
314     }
315     DES_set_odd_parity(key);
316     if(DES_is_weak_key(key))
317         (*key)[7] ^= 0xF0;
318     DES_set_key_unchecked(key, &schedule);
319     DES_cbc_cksum((void*)data, key, length, &schedule, key);
320     memset(&schedule, 0, sizeof(schedule));
321     DES_set_odd_parity(key);
322     if(DES_is_weak_key(key))
323         (*key)[7] ^= 0xF0;
324 }
325
326 static krb5_error_code
327 krb5_DES_string_to_key(krb5_context context,
328                        krb5_enctype enctype,
329                        krb5_data password,
330                        krb5_salt salt,
331                        krb5_data opaque,
332                        krb5_keyblock *key)
333 {
334     unsigned char *s;
335     size_t len;
336     DES_cblock tmp;
337
338 #ifdef ENABLE_AFS_STRING_TO_KEY
339     if (opaque.length == 1) {
340         unsigned long v;
341         _krb5_get_int(opaque.data, &v, 1);
342         if (v == 1)
343             return DES_AFS3_string_to_key(context, enctype, password,
344                                           salt, opaque, key);
345     }
346 #endif
347
348     len = password.length + salt.saltvalue.length;
349     s = malloc(len);
350     if(len > 0 && s == NULL) {
351         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
352         return ENOMEM;
353     }
354     memcpy(s, password.data, password.length);
355     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
356     DES_string_to_key_int(s, len, &tmp);
357     key->keytype = enctype;
358     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
359     memset(&tmp, 0, sizeof(tmp));
360     memset(s, 0, len);
361     free(s);
362     return 0;
363 }
364
365 static void
366 krb5_DES_random_to_key(krb5_context context,
367                        krb5_keyblock *key,
368                        const void *data,
369                        size_t size)
370 {
371     DES_cblock *k = key->keyvalue.data;
372     memcpy(k, data, key->keyvalue.length);
373     DES_set_odd_parity(k);
374     if(DES_is_weak_key(k))
375         xor(k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
376 }
377 #endif
378
379 /*
380  *
381  */
382
383 static void
384 DES3_random_key(krb5_context context,
385                 krb5_keyblock *key)
386 {
387     DES_cblock *k = key->keyvalue.data;
388     do {
389         krb5_generate_random_block(k, 3 * sizeof(DES_cblock));
390         DES_set_odd_parity(&k[0]);
391         DES_set_odd_parity(&k[1]);
392         DES_set_odd_parity(&k[2]);
393     } while(DES_is_weak_key(&k[0]) ||
394             DES_is_weak_key(&k[1]) ||
395             DES_is_weak_key(&k[2]));
396 }
397
398 /*
399  * A = A xor B. A & B are 8 bytes.
400  */
401
402 static void
403 xor (DES_cblock *key, const unsigned char *b)
404 {
405     unsigned char *a = (unsigned char*)key;
406     a[0] ^= b[0];
407     a[1] ^= b[1];
408     a[2] ^= b[2];
409     a[3] ^= b[3];
410     a[4] ^= b[4];
411     a[5] ^= b[5];
412     a[6] ^= b[6];
413     a[7] ^= b[7];
414 }
415
416 #ifdef DES3_OLD_ENCTYPE
417 static krb5_error_code
418 DES3_string_to_key(krb5_context context,
419                    krb5_enctype enctype,
420                    krb5_data password,
421                    krb5_salt salt,
422                    krb5_data opaque,
423                    krb5_keyblock *key)
424 {
425     char *str;
426     size_t len;
427     unsigned char tmp[24];
428     DES_cblock keys[3];
429     krb5_error_code ret;
430
431     len = password.length + salt.saltvalue.length;
432     str = malloc(len);
433     if(len != 0 && str == NULL) {
434         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
435         return ENOMEM;
436     }
437     memcpy(str, password.data, password.length);
438     memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length);
439     {
440         DES_cblock ivec;
441         DES_key_schedule s[3];
442         int i;
443         
444         ret = _krb5_n_fold(str, len, tmp, 24);
445         if (ret) {
446             memset(str, 0, len);
447             free(str);
448             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
449             return ret;
450         }
451         
452         for(i = 0; i < 3; i++){
453             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
454             DES_set_odd_parity(keys + i);
455             if(DES_is_weak_key(keys + i))
456                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
457             DES_set_key_unchecked(keys + i, &s[i]);
458         }
459         memset(&ivec, 0, sizeof(ivec));
460         DES_ede3_cbc_encrypt(tmp,
461                              tmp, sizeof(tmp),
462                              &s[0], &s[1], &s[2], &ivec, DES_ENCRYPT);
463         memset(s, 0, sizeof(s));
464         memset(&ivec, 0, sizeof(ivec));
465         for(i = 0; i < 3; i++){
466             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
467             DES_set_odd_parity(keys + i);
468             if(DES_is_weak_key(keys + i))
469                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
470         }
471         memset(tmp, 0, sizeof(tmp));
472     }
473     key->keytype = enctype;
474     krb5_data_copy(&key->keyvalue, keys, sizeof(keys));
475     memset(keys, 0, sizeof(keys));
476     memset(str, 0, len);
477     free(str);
478     return 0;
479 }
480 #endif
481
482 static krb5_error_code
483 DES3_string_to_key_derived(krb5_context context,
484                            krb5_enctype enctype,
485                            krb5_data password,
486                            krb5_salt salt,
487                            krb5_data opaque,
488                            krb5_keyblock *key)
489 {
490     krb5_error_code ret;
491     size_t len = password.length + salt.saltvalue.length;
492     char *s;
493
494     s = malloc(len);
495     if(len != 0 && s == NULL) {
496         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
497         return ENOMEM;
498     }
499     memcpy(s, password.data, password.length);
500     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
501     ret = krb5_string_to_key_derived(context,
502                                      s,
503                                      len,
504                                      enctype,
505                                      key);
506     memset(s, 0, len);
507     free(s);
508     return ret;
509 }
510
511 static void
512 DES3_random_to_key(krb5_context context,
513                    krb5_keyblock *key,
514                    const void *data,
515                    size_t size)
516 {
517     unsigned char *x = key->keyvalue.data;
518     const u_char *q = data;
519     DES_cblock *k;
520     int i, j;
521
522     memset(x, 0, sizeof(x));
523     for (i = 0; i < 3; ++i) {
524         unsigned char foo;
525         for (j = 0; j < 7; ++j) {
526             unsigned char b = q[7 * i + j];
527
528             x[8 * i + j] = b;
529         }
530         foo = 0;
531         for (j = 6; j >= 0; --j) {
532             foo |= q[7 * i + j] & 1;
533             foo <<= 1;
534         }
535         x[8 * i + 7] = foo;
536     }
537     k = key->keyvalue.data;
538     for (i = 0; i < 3; i++) {
539         DES_set_odd_parity(&k[i]);
540         if(DES_is_weak_key(&k[i]))
541             xor(&k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
542     }
543 }
544
545 /*
546  * ARCFOUR
547  */
548
549 static krb5_error_code
550 ARCFOUR_string_to_key(krb5_context context,
551                       krb5_enctype enctype,
552                       krb5_data password,
553                       krb5_salt salt,
554                       krb5_data opaque,
555                       krb5_keyblock *key)
556 {
557     krb5_error_code ret;
558     uint16_t *s = NULL;
559     size_t len, i;
560     EVP_MD_CTX *m;
561
562     m = EVP_MD_CTX_create();
563     if (m == NULL) {
564         ret = ENOMEM;
565         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
566         goto out;
567     }
568
569     EVP_DigestInit_ex(m, EVP_md4(), NULL);
570
571     ret = wind_utf8ucs2_length(password.data, &len);
572     if (ret) {
573         krb5_set_error_message (context, ret,
574                                 N_("Password not an UCS2 string", ""));
575         goto out;
576     }
577         
578     s = malloc (len * sizeof(s[0]));
579     if (len != 0 && s == NULL) {
580         krb5_set_error_message (context, ENOMEM,
581                                 N_("malloc: out of memory", ""));
582         ret = ENOMEM;
583         goto out;
584     }
585
586     ret = wind_utf8ucs2(password.data, s, &len);
587     if (ret) {
588         krb5_set_error_message (context, ret,
589                                 N_("Password not an UCS2 string", ""));
590         goto out;
591     }
592
593     /* LE encoding */
594     for (i = 0; i < len; i++) {
595         unsigned char p;
596         p = (s[i] & 0xff);
597         EVP_DigestUpdate (m, &p, 1);
598         p = (s[i] >> 8) & 0xff;
599         EVP_DigestUpdate (m, &p, 1);
600     }
601
602     key->keytype = enctype;
603     ret = krb5_data_alloc (&key->keyvalue, 16);
604     if (ret) {
605         krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
606         goto out;
607     }
608     EVP_DigestFinal_ex (m, key->keyvalue.data, NULL);
609
610  out:
611     EVP_MD_CTX_destroy(m);
612     if (s)
613         memset (s, 0, len);
614     free (s);
615     return ret;
616 }
617
618 /*
619  * AES
620  */
621
622 int _krb5_AES_string_to_default_iterator = 4096;
623
624 static krb5_error_code
625 AES_string_to_key(krb5_context context,
626                   krb5_enctype enctype,
627                   krb5_data password,
628                   krb5_salt salt,
629                   krb5_data opaque,
630                   krb5_keyblock *key)
631 {
632     krb5_error_code ret;
633     uint32_t iter;
634     struct encryption_type *et;
635     struct key_data kd;
636
637     if (opaque.length == 0)
638         iter = _krb5_AES_string_to_default_iterator;
639     else if (opaque.length == 4) {
640         unsigned long v;
641         _krb5_get_int(opaque.data, &v, 4);
642         iter = ((uint32_t)v);
643     } else
644         return KRB5_PROG_KEYTYPE_NOSUPP; /* XXX */
645         
646     et = _find_enctype(enctype);
647     if (et == NULL)
648         return KRB5_PROG_KEYTYPE_NOSUPP;
649
650     kd.schedule = NULL;
651     ALLOC(kd.key, 1);
652     if(kd.key == NULL) {
653         krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
654         return ENOMEM;
655     }
656     kd.key->keytype = enctype;
657     ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
658     if (ret) {
659         krb5_set_error_message (context, ret, N_("malloc: out of memory", ""));
660         return ret;
661     }
662
663     ret = PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length,
664                                  salt.saltvalue.data, salt.saltvalue.length,
665                                  iter,
666                                  et->keytype->size, kd.key->keyvalue.data);
667     if (ret != 1) {
668         free_key_data(context, &kd, et);
669         krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
670                                "Error calculating s2k");
671         return KRB5_PROG_KEYTYPE_NOSUPP;
672     }
673
674     ret = derive_key(context, et, &kd, "kerberos", strlen("kerberos"));
675     if (ret == 0)
676         ret = krb5_copy_keyblock_contents(context, kd.key, key);
677     free_key_data(context, &kd, et);
678
679     return ret;
680 }
681
682 static void
683 evp_schedule(krb5_context context, struct key_type *kt, struct key_data *kd)
684 {
685     struct evp_schedule *key = kd->schedule->data;
686     const EVP_CIPHER *c = (*kt->evp)();
687
688     EVP_CIPHER_CTX_init(&key->ectx);
689     EVP_CIPHER_CTX_init(&key->dctx);
690
691     EVP_CipherInit_ex(&key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1);
692     EVP_CipherInit_ex(&key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0);
693 }
694
695 static void
696 evp_cleanup(krb5_context context, struct key_data *kd)
697 {
698     struct evp_schedule *key = kd->schedule->data;
699     EVP_CIPHER_CTX_cleanup(&key->ectx);
700     EVP_CIPHER_CTX_cleanup(&key->dctx);
701 }
702
703 /*
704  *
705  */
706
707 #ifdef HEIM_WEAK_CRYPTO
708 static struct salt_type des_salt[] = {
709     {
710         KRB5_PW_SALT,
711         "pw-salt",
712         krb5_DES_string_to_key
713     },
714 #ifdef ENABLE_AFS_STRING_TO_KEY
715     {
716         KRB5_AFS3_SALT,
717         "afs3-salt",
718         DES_AFS3_string_to_key
719     },
720 #endif
721     { 0 }
722 };
723 #endif
724
725 #ifdef DES3_OLD_ENCTYPE
726 static struct salt_type des3_salt[] = {
727     {
728         KRB5_PW_SALT,
729         "pw-salt",
730         DES3_string_to_key
731     },
732     { 0 }
733 };
734 #endif
735
736 static struct salt_type des3_salt_derived[] = {
737     {
738         KRB5_PW_SALT,
739         "pw-salt",
740         DES3_string_to_key_derived
741     },
742     { 0 }
743 };
744
745 static struct salt_type AES_salt[] = {
746     {
747         KRB5_PW_SALT,
748         "pw-salt",
749         AES_string_to_key
750     },
751     { 0 }
752 };
753
754 static struct salt_type arcfour_salt[] = {
755     {
756         KRB5_PW_SALT,
757         "pw-salt",
758         ARCFOUR_string_to_key
759     },
760     { 0 }
761 };
762
763 /*
764  *
765  */
766
767 static struct key_type keytype_null = {
768     KEYTYPE_NULL,
769     "null",
770     0,
771     0,
772     0,
773     NULL,
774     NULL,
775     NULL
776 };
777
778 #ifdef HEIM_WEAK_CRYPTO
779 static struct key_type keytype_des_old = {
780     KEYTYPE_DES,
781     "des-old",
782     56,
783     8,
784     sizeof(DES_key_schedule),
785     krb5_DES_random_key,
786     krb5_DES_schedule_old,
787     des_salt,
788     krb5_DES_random_to_key
789 };
790
791 static struct key_type keytype_des = {
792     KEYTYPE_DES,
793     "des",
794     56,
795     8,
796     sizeof(struct evp_schedule),
797     krb5_DES_random_key,
798     evp_schedule,
799     des_salt,
800     krb5_DES_random_to_key,
801     evp_cleanup,
802     EVP_des_cbc
803 };
804 #endif /* HEIM_WEAK_CRYPTO */
805
806 #ifdef DES3_OLD_ENCTYPE
807 static struct key_type keytype_des3 = {
808     KEYTYPE_DES3,
809     "des3",
810     168,
811     24,
812     sizeof(struct evp_schedule),
813     DES3_random_key,
814     evp_schedule,
815     des3_salt,
816     DES3_random_to_key,
817     evp_cleanup,
818     EVP_des_ede3_cbc
819 };
820 #endif
821
822 static struct key_type keytype_des3_derived = {
823     KEYTYPE_DES3,
824     "des3",
825     168,
826     24,
827     sizeof(struct evp_schedule),
828     DES3_random_key,
829     evp_schedule,
830     des3_salt_derived,
831     DES3_random_to_key,
832     evp_cleanup,
833     EVP_des_ede3_cbc
834 };
835
836 static struct key_type keytype_aes128 = {
837     KEYTYPE_AES128,
838     "aes-128",
839     128,
840     16,
841     sizeof(struct evp_schedule),
842     NULL,
843     evp_schedule,
844     AES_salt,
845     NULL,
846     evp_cleanup,
847     EVP_aes_128_cbc
848 };
849
850 static struct key_type keytype_aes256 = {
851     KEYTYPE_AES256,
852     "aes-256",
853     256,
854     32,
855     sizeof(struct evp_schedule),
856     NULL,
857     evp_schedule,
858     AES_salt,
859     NULL,
860     evp_cleanup,
861     EVP_aes_256_cbc
862 };
863
864 static struct key_type keytype_arcfour = {
865     KEYTYPE_ARCFOUR,
866     "arcfour",
867     128,
868     16,
869     sizeof(struct evp_schedule),
870     NULL,
871     evp_schedule,
872     arcfour_salt,
873     NULL,
874     evp_cleanup,
875     EVP_rc4
876 };
877
878 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
879 krb5_salttype_to_string (krb5_context context,
880                          krb5_enctype etype,
881                          krb5_salttype stype,
882                          char **string)
883 {
884     struct encryption_type *e;
885     struct salt_type *st;
886
887     e = _find_enctype (etype);
888     if (e == NULL) {
889         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
890                                "encryption type %d not supported",
891                                etype);
892         return KRB5_PROG_ETYPE_NOSUPP;
893     }
894     for (st = e->keytype->string_to_key; st && st->type; st++) {
895         if (st->type == stype) {
896             *string = strdup (st->name);
897             if (*string == NULL) {
898                 krb5_set_error_message (context, ENOMEM,
899                                         N_("malloc: out of memory", ""));
900                 return ENOMEM;
901             }
902             return 0;
903         }
904     }
905     krb5_set_error_message (context, HEIM_ERR_SALTTYPE_NOSUPP,
906                             "salttype %d not supported", stype);
907     return HEIM_ERR_SALTTYPE_NOSUPP;
908 }
909
910 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
911 krb5_string_to_salttype (krb5_context context,
912                          krb5_enctype etype,
913                          const char *string,
914                          krb5_salttype *salttype)
915 {
916     struct encryption_type *e;
917     struct salt_type *st;
918
919     e = _find_enctype (etype);
920     if (e == NULL) {
921         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
922                                N_("encryption type %d not supported", ""),
923                                etype);
924         return KRB5_PROG_ETYPE_NOSUPP;
925     }
926     for (st = e->keytype->string_to_key; st && st->type; st++) {
927         if (strcasecmp (st->name, string) == 0) {
928             *salttype = st->type;
929             return 0;
930         }
931     }
932     krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
933                            N_("salttype %s not supported", ""), string);
934     return HEIM_ERR_SALTTYPE_NOSUPP;
935 }
936
937 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
938 krb5_get_pw_salt(krb5_context context,
939                  krb5_const_principal principal,
940                  krb5_salt *salt)
941 {
942     size_t len;
943     int i;
944     krb5_error_code ret;
945     char *p;
946
947     salt->salttype = KRB5_PW_SALT;
948     len = strlen(principal->realm);
949     for (i = 0; i < principal->name.name_string.len; ++i)
950         len += strlen(principal->name.name_string.val[i]);
951     ret = krb5_data_alloc (&salt->saltvalue, len);
952     if (ret)
953         return ret;
954     p = salt->saltvalue.data;
955     memcpy (p, principal->realm, strlen(principal->realm));
956     p += strlen(principal->realm);
957     for (i = 0; i < principal->name.name_string.len; ++i) {
958         memcpy (p,
959                 principal->name.name_string.val[i],
960                 strlen(principal->name.name_string.val[i]));
961         p += strlen(principal->name.name_string.val[i]);
962     }
963     return 0;
964 }
965
966 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
967 krb5_free_salt(krb5_context context,
968                krb5_salt salt)
969 {
970     krb5_data_free(&salt.saltvalue);
971     return 0;
972 }
973
974 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
975 krb5_string_to_key_data (krb5_context context,
976                          krb5_enctype enctype,
977                          krb5_data password,
978                          krb5_principal principal,
979                          krb5_keyblock *key)
980 {
981     krb5_error_code ret;
982     krb5_salt salt;
983
984     ret = krb5_get_pw_salt(context, principal, &salt);
985     if(ret)
986         return ret;
987     ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
988     krb5_free_salt(context, salt);
989     return ret;
990 }
991
992 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
993 krb5_string_to_key (krb5_context context,
994                     krb5_enctype enctype,
995                     const char *password,
996                     krb5_principal principal,
997                     krb5_keyblock *key)
998 {
999     krb5_data pw;
1000     pw.data = rk_UNCONST(password);
1001     pw.length = strlen(password);
1002     return krb5_string_to_key_data(context, enctype, pw, principal, key);
1003 }
1004
1005 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1006 krb5_string_to_key_data_salt (krb5_context context,
1007                               krb5_enctype enctype,
1008                               krb5_data password,
1009                               krb5_salt salt,
1010                               krb5_keyblock *key)
1011 {
1012     krb5_data opaque;
1013     krb5_data_zero(&opaque);
1014     return krb5_string_to_key_data_salt_opaque(context, enctype, password,
1015                                                salt, opaque, key);
1016 }
1017
1018 /*
1019  * Do a string -> key for encryption type `enctype' operation on
1020  * `password' (with salt `salt' and the enctype specific data string
1021  * `opaque'), returning the resulting key in `key'
1022  */
1023
1024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1025 krb5_string_to_key_data_salt_opaque (krb5_context context,
1026                                      krb5_enctype enctype,
1027                                      krb5_data password,
1028                                      krb5_salt salt,
1029                                      krb5_data opaque,
1030                                      krb5_keyblock *key)
1031 {
1032     struct encryption_type *et =_find_enctype(enctype);
1033     struct salt_type *st;
1034     if(et == NULL) {
1035         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
1036                                N_("encryption type %d not supported", ""),
1037                                enctype);
1038         return KRB5_PROG_ETYPE_NOSUPP;
1039     }
1040     for(st = et->keytype->string_to_key; st && st->type; st++)
1041         if(st->type == salt.salttype)
1042             return (*st->string_to_key)(context, enctype, password,
1043                                         salt, opaque, key);
1044     krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
1045                            N_("salt type %d not supported", ""),
1046                            salt.salttype);
1047     return HEIM_ERR_SALTTYPE_NOSUPP;
1048 }
1049
1050 /*
1051  * Do a string -> key for encryption type `enctype' operation on the
1052  * string `password' (with salt `salt'), returning the resulting key
1053  * in `key'
1054  */
1055
1056 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1057 krb5_string_to_key_salt (krb5_context context,
1058                          krb5_enctype enctype,
1059                          const char *password,
1060                          krb5_salt salt,
1061                          krb5_keyblock *key)
1062 {
1063     krb5_data pw;
1064     pw.data = rk_UNCONST(password);
1065     pw.length = strlen(password);
1066     return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
1067 }
1068
1069 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1070 krb5_string_to_key_salt_opaque (krb5_context context,
1071                                 krb5_enctype enctype,
1072                                 const char *password,
1073                                 krb5_salt salt,
1074                                 krb5_data opaque,
1075                                 krb5_keyblock *key)
1076 {
1077     krb5_data pw;
1078     pw.data = rk_UNCONST(password);
1079     pw.length = strlen(password);
1080     return krb5_string_to_key_data_salt_opaque(context, enctype,
1081                                                pw, salt, opaque, key);
1082 }
1083
1084 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1085 krb5_enctype_keysize(krb5_context context,
1086                      krb5_enctype type,
1087                      size_t *keysize)
1088 {
1089     struct encryption_type *et = _find_enctype(type);
1090     if(et == NULL) {
1091         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
1092                                N_("encryption type %d not supported", ""),
1093                                type);
1094         return KRB5_PROG_ETYPE_NOSUPP;
1095     }
1096     *keysize = et->keytype->size;
1097     return 0;
1098 }
1099
1100 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1101 krb5_enctype_keybits(krb5_context context,
1102                      krb5_enctype type,
1103                      size_t *keybits)
1104 {
1105     struct encryption_type *et = _find_enctype(type);
1106     if(et == NULL) {
1107         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
1108                                "encryption type %d not supported",
1109                                type);
1110         return KRB5_PROG_ETYPE_NOSUPP;
1111     }
1112     *keybits = et->keytype->bits;
1113     return 0;
1114 }
1115
1116 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1117 krb5_generate_random_keyblock(krb5_context context,
1118                               krb5_enctype type,
1119                               krb5_keyblock *key)
1120 {
1121     krb5_error_code ret;
1122     struct encryption_type *et = _find_enctype(type);
1123     if(et == NULL) {
1124         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
1125                                N_("encryption type %d not supported", ""),
1126                                type);
1127         return KRB5_PROG_ETYPE_NOSUPP;
1128     }
1129     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
1130     if(ret)
1131         return ret;
1132     key->keytype = type;
1133     if(et->keytype->random_key)
1134         (*et->keytype->random_key)(context, key);
1135     else
1136         krb5_generate_random_block(key->keyvalue.data,
1137                                    key->keyvalue.length);
1138     return 0;
1139 }
1140
1141 static krb5_error_code
1142 _key_schedule(krb5_context context,
1143               struct key_data *key)
1144 {
1145     krb5_error_code ret;
1146     struct encryption_type *et = _find_enctype(key->key->keytype);
1147     struct key_type *kt;
1148
1149     if (et == NULL) {
1150         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
1151                                 N_("encryption type %d not supported", ""),
1152                                 key->key->keytype);
1153         return KRB5_PROG_ETYPE_NOSUPP;
1154     }
1155
1156     kt = et->keytype;
1157
1158     if(kt->schedule == NULL)
1159         return 0;
1160     if (key->schedule != NULL)
1161         return 0;
1162     ALLOC(key->schedule, 1);
1163     if(key->schedule == NULL) {
1164         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1165         return ENOMEM;
1166     }
1167     ret = krb5_data_alloc(key->schedule, kt->schedule_size);
1168     if(ret) {
1169         free(key->schedule);
1170         key->schedule = NULL;
1171         return ret;
1172     }
1173     (*kt->schedule)(context, kt, key);
1174     return 0;
1175 }
1176
1177 /************************************************************
1178  *                                                          *
1179  ************************************************************/
1180
1181 static krb5_error_code
1182 NONE_checksum(krb5_context context,
1183               struct key_data *key,
1184               const void *data,
1185               size_t len,
1186               unsigned usage,
1187               Checksum *C)
1188 {
1189     return 0;
1190 }
1191
1192 #if defined(DES3_OLD_ENCTYPE) || defined(HEIM_WEAK_CRYPTO)
1193
1194 static krb5_error_code
1195 des_checksum(krb5_context context,
1196              const EVP_MD *evp_md,
1197              struct key_data *key,
1198              const void *data,
1199              size_t len,
1200              Checksum *cksum)
1201 {
1202     struct evp_schedule *ctx = key->schedule->data;
1203     EVP_MD_CTX *m;
1204     DES_cblock ivec;
1205     unsigned char *p = cksum->checksum.data;
1206
1207     krb5_generate_random_block(p, 8);
1208
1209     m = EVP_MD_CTX_create();
1210     if (m == NULL) {
1211         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1212         return ENOMEM;
1213     }
1214
1215     EVP_DigestInit_ex(m, evp_md, NULL);
1216     EVP_DigestUpdate(m, p, 8);
1217     EVP_DigestUpdate(m, data, len);
1218     EVP_DigestFinal_ex (m, p + 8, NULL);
1219     EVP_MD_CTX_destroy(m);
1220     memset (&ivec, 0, sizeof(ivec));
1221     EVP_CipherInit_ex(&ctx->ectx, NULL, NULL, NULL, (void *)&ivec, -1);
1222     EVP_Cipher(&ctx->ectx, p, p, 24);
1223
1224     return 0;
1225 }
1226
1227 static krb5_error_code
1228 des_verify(krb5_context context,
1229            const EVP_MD *evp_md,
1230            struct key_data *key,
1231            const void *data,
1232            size_t len,
1233            Checksum *C)
1234 {
1235     struct evp_schedule *ctx = key->schedule->data;
1236     EVP_MD_CTX *m;
1237     unsigned char tmp[24];
1238     unsigned char res[16];
1239     DES_cblock ivec;
1240     krb5_error_code ret = 0;
1241
1242     m = EVP_MD_CTX_create();
1243     if (m == NULL) {
1244         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1245         return ENOMEM;
1246     }
1247
1248     memset(&ivec, 0, sizeof(ivec));
1249     EVP_CipherInit_ex(&ctx->dctx, NULL, NULL, NULL, (void *)&ivec, -1);
1250     EVP_Cipher(&ctx->dctx, tmp, C->checksum.data, 24);
1251
1252     EVP_DigestInit_ex(m, evp_md, NULL);
1253     EVP_DigestUpdate(m, tmp, 8); /* confounder */
1254     EVP_DigestUpdate(m, data, len);
1255     EVP_DigestFinal_ex (m, res, NULL);
1256     EVP_MD_CTX_destroy(m);
1257     if(ct_memcmp(res, tmp + 8, sizeof(res)) != 0) {
1258         krb5_clear_error_message (context);
1259         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1260     }
1261     memset(tmp, 0, sizeof(tmp));
1262     memset(res, 0, sizeof(res));
1263     return ret;
1264 }
1265
1266 #endif
1267
1268 #ifdef HEIM_WEAK_CRYPTO
1269
1270 static krb5_error_code
1271 CRC32_checksum(krb5_context context,
1272                struct key_data *key,
1273                const void *data,
1274                size_t len,
1275                unsigned usage,
1276                Checksum *C)
1277 {
1278     uint32_t crc;
1279     unsigned char *r = C->checksum.data;
1280     _krb5_crc_init_table ();
1281     crc = _krb5_crc_update (data, len, 0);
1282     r[0] = crc & 0xff;
1283     r[1] = (crc >> 8)  & 0xff;
1284     r[2] = (crc >> 16) & 0xff;
1285     r[3] = (crc >> 24) & 0xff;
1286     return 0;
1287 }
1288
1289 static krb5_error_code
1290 RSA_MD4_checksum(krb5_context context,
1291                  struct key_data *key,
1292                  const void *data,
1293                  size_t len,
1294                  unsigned usage,
1295                  Checksum *C)
1296 {
1297     if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_md4(), NULL) != 1)
1298         krb5_abortx(context, "md4 checksum failed");
1299     return 0;
1300 }
1301
1302 static krb5_error_code
1303 RSA_MD4_DES_checksum(krb5_context context,
1304                      struct key_data *key,
1305                      const void *data,
1306                      size_t len,
1307                      unsigned usage,
1308                      Checksum *cksum)
1309 {
1310     return des_checksum(context, EVP_md4(), key, data, len, cksum);
1311 }
1312
1313 static krb5_error_code
1314 RSA_MD4_DES_verify(krb5_context context,
1315                    struct key_data *key,
1316                    const void *data,
1317                    size_t len,
1318                    unsigned usage,
1319                    Checksum *C)
1320 {
1321     return des_verify(context, EVP_md5(), key, data, len, C);
1322 }
1323
1324 static krb5_error_code
1325 RSA_MD5_DES_checksum(krb5_context context,
1326                      struct key_data *key,
1327                      const void *data,
1328                      size_t len,
1329                      unsigned usage,
1330                      Checksum *C)
1331 {
1332     return des_checksum(context, EVP_md5(), key, data, len, C);
1333 }
1334
1335 static krb5_error_code
1336 RSA_MD5_DES_verify(krb5_context context,
1337                    struct key_data *key,
1338                    const void *data,
1339                    size_t len,
1340                    unsigned usage,
1341                    Checksum *C)
1342 {
1343     return des_verify(context, EVP_md5(), key, data, len, C);
1344 }
1345
1346 #endif /* HEIM_WEAK_CRYPTO */
1347
1348 #ifdef DES3_OLD_ENCTYPE
1349 static krb5_error_code
1350 RSA_MD5_DES3_checksum(krb5_context context,
1351                       struct key_data *key,
1352                       const void *data,
1353                       size_t len,
1354                       unsigned usage,
1355                       Checksum *C)
1356 {
1357     return des_checksum(context, EVP_md5(), key, data, len, C);
1358 }
1359
1360 static krb5_error_code
1361 RSA_MD5_DES3_verify(krb5_context context,
1362                     struct key_data *key,
1363                     const void *data,
1364                     size_t len,
1365                     unsigned usage,
1366                     Checksum *C)
1367 {
1368     return des_verify(context, EVP_md5(), key, data, len, C);
1369 }
1370 #endif
1371
1372 static krb5_error_code
1373 SHA1_checksum(krb5_context context,
1374               struct key_data *key,
1375               const void *data,
1376               size_t len,
1377               unsigned usage,
1378               Checksum *C)
1379 {
1380     if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
1381         krb5_abortx(context, "sha1 checksum failed");
1382     return 0;
1383 }
1384
1385 /* HMAC according to RFC2104 */
1386 static krb5_error_code
1387 hmac(krb5_context context,
1388      struct checksum_type *cm,
1389      const void *data,
1390      size_t len,
1391      unsigned usage,
1392      struct key_data *keyblock,
1393      Checksum *result)
1394 {
1395     unsigned char *ipad, *opad;
1396     unsigned char *key;
1397     size_t key_len;
1398     int i;
1399
1400     ipad = malloc(cm->blocksize + len);
1401     if (ipad == NULL)
1402         return ENOMEM;
1403     opad = malloc(cm->blocksize + cm->checksumsize);
1404     if (opad == NULL) {
1405         free(ipad);
1406         return ENOMEM;
1407     }
1408     memset(ipad, 0x36, cm->blocksize);
1409     memset(opad, 0x5c, cm->blocksize);
1410
1411     if(keyblock->key->keyvalue.length > cm->blocksize){
1412         (*cm->checksum)(context,
1413                         keyblock,
1414                         keyblock->key->keyvalue.data,
1415                         keyblock->key->keyvalue.length,
1416                         usage,
1417                         result);
1418         key = result->checksum.data;
1419         key_len = result->checksum.length;
1420     } else {
1421         key = keyblock->key->keyvalue.data;
1422         key_len = keyblock->key->keyvalue.length;
1423     }
1424     for(i = 0; i < key_len; i++){
1425         ipad[i] ^= key[i];
1426         opad[i] ^= key[i];
1427     }
1428     memcpy(ipad + cm->blocksize, data, len);
1429     (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
1430                     usage, result);
1431     memcpy(opad + cm->blocksize, result->checksum.data,
1432            result->checksum.length);
1433     (*cm->checksum)(context, keyblock, opad,
1434                     cm->blocksize + cm->checksumsize, usage, result);
1435     memset(ipad, 0, cm->blocksize + len);
1436     free(ipad);
1437     memset(opad, 0, cm->blocksize + cm->checksumsize);
1438     free(opad);
1439
1440     return 0;
1441 }
1442
1443 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1444 krb5_hmac(krb5_context context,
1445           krb5_cksumtype cktype,
1446           const void *data,
1447           size_t len,
1448           unsigned usage,
1449           krb5_keyblock *key,
1450           Checksum *result)
1451 {
1452     struct checksum_type *c = _find_checksum(cktype);
1453     struct key_data kd;
1454     krb5_error_code ret;
1455
1456     if (c == NULL) {
1457         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1458                                 N_("checksum type %d not supported", ""),
1459                                 cktype);
1460         return KRB5_PROG_SUMTYPE_NOSUPP;
1461     }
1462
1463     kd.key = key;
1464     kd.schedule = NULL;
1465
1466     ret = hmac(context, c, data, len, usage, &kd, result);
1467
1468     if (kd.schedule)
1469         krb5_free_data(context, kd.schedule);
1470
1471     return ret;
1472 }
1473
1474 static krb5_error_code
1475 SP_HMAC_SHA1_checksum(krb5_context context,
1476                       struct key_data *key,
1477                       const void *data,
1478                       size_t len,
1479                       unsigned usage,
1480                       Checksum *result)
1481 {
1482     struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1);
1483     Checksum res;
1484     char sha1_data[20];
1485     krb5_error_code ret;
1486
1487     res.checksum.data = sha1_data;
1488     res.checksum.length = sizeof(sha1_data);
1489
1490     ret = hmac(context, c, data, len, usage, key, &res);
1491     if (ret)
1492         krb5_abortx(context, "hmac failed");
1493     memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
1494     return 0;
1495 }
1496
1497 /*
1498  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
1499  */
1500
1501 static krb5_error_code
1502 HMAC_MD5_checksum(krb5_context context,
1503                   struct key_data *key,
1504                   const void *data,
1505                   size_t len,
1506                   unsigned usage,
1507                   Checksum *result)
1508 {
1509     EVP_MD_CTX *m;
1510     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1511     const char signature[] = "signaturekey";
1512     Checksum ksign_c;
1513     struct key_data ksign;
1514     krb5_keyblock kb;
1515     unsigned char t[4];
1516     unsigned char tmp[16];
1517     unsigned char ksign_c_data[16];
1518     krb5_error_code ret;
1519
1520     m = EVP_MD_CTX_create();
1521     if (m == NULL) {
1522         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1523         return ENOMEM;
1524     }
1525     ksign_c.checksum.length = sizeof(ksign_c_data);
1526     ksign_c.checksum.data   = ksign_c_data;
1527     ret = hmac(context, c, signature, sizeof(signature), 0, key, &ksign_c);
1528     if (ret) {
1529         EVP_MD_CTX_destroy(m);
1530         return ret;
1531     }
1532     ksign.key = &kb;
1533     kb.keyvalue = ksign_c.checksum;
1534     EVP_DigestInit_ex(m, EVP_md5(), NULL);
1535     t[0] = (usage >>  0) & 0xFF;
1536     t[1] = (usage >>  8) & 0xFF;
1537     t[2] = (usage >> 16) & 0xFF;
1538     t[3] = (usage >> 24) & 0xFF;
1539     EVP_DigestUpdate(m, t, 4);
1540     EVP_DigestUpdate(m, data, len);
1541     EVP_DigestFinal_ex (m, tmp, NULL);
1542     EVP_MD_CTX_destroy(m);
1543
1544     ret = hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
1545     if (ret)
1546         return ret;
1547     return 0;
1548 }
1549
1550 static struct checksum_type checksum_none = {
1551     CKSUMTYPE_NONE,
1552     "none",
1553     1,
1554     0,
1555     0,
1556     NONE_checksum,
1557     NULL
1558 };
1559 #ifdef HEIM_WEAK_CRYPTO
1560 static struct checksum_type checksum_crc32 = {
1561     CKSUMTYPE_CRC32,
1562     "crc32",
1563     1,
1564     4,
1565     0,
1566     CRC32_checksum,
1567     NULL
1568 };
1569 static struct checksum_type checksum_rsa_md4 = {
1570     CKSUMTYPE_RSA_MD4,
1571     "rsa-md4",
1572     64,
1573     16,
1574     F_CPROOF,
1575     RSA_MD4_checksum,
1576     NULL
1577 };
1578 static struct checksum_type checksum_rsa_md4_des = {
1579     CKSUMTYPE_RSA_MD4_DES,
1580     "rsa-md4-des",
1581     64,
1582     24,
1583     F_KEYED | F_CPROOF | F_VARIANT,
1584     RSA_MD4_DES_checksum,
1585     RSA_MD4_DES_verify
1586 };
1587 static struct checksum_type checksum_rsa_md5_des = {
1588     CKSUMTYPE_RSA_MD5_DES,
1589     "rsa-md5-des",
1590     64,
1591     24,
1592     F_KEYED | F_CPROOF | F_VARIANT,
1593     RSA_MD5_DES_checksum,
1594     RSA_MD5_DES_verify
1595 };
1596 #endif /* HEIM_WEAK_CRYPTO */
1597
1598 static krb5_error_code
1599 RSA_MD5_checksum(krb5_context context,
1600                  struct key_data *key,
1601                  const void *data,
1602                  size_t len,
1603                  unsigned usage,
1604                  Checksum *C)
1605 {
1606     if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_md5(), NULL) != 1)
1607         krb5_abortx(context, "md5 checksum failed");
1608     return 0;
1609 }
1610
1611 static struct checksum_type checksum_rsa_md5 = {
1612     CKSUMTYPE_RSA_MD5,
1613     "rsa-md5",
1614     64,
1615     16,
1616     F_CPROOF,
1617     RSA_MD5_checksum,
1618     NULL
1619 };
1620
1621 #ifdef DES3_OLD_ENCTYPE
1622 static struct checksum_type checksum_rsa_md5_des3 = {
1623     CKSUMTYPE_RSA_MD5_DES3,
1624     "rsa-md5-des3",
1625     64,
1626     24,
1627     F_KEYED | F_CPROOF | F_VARIANT,
1628     RSA_MD5_DES3_checksum,
1629     RSA_MD5_DES3_verify
1630 };
1631 #endif
1632 static struct checksum_type checksum_sha1 = {
1633     CKSUMTYPE_SHA1,
1634     "sha1",
1635     64,
1636     20,
1637     F_CPROOF,
1638     SHA1_checksum,
1639     NULL
1640 };
1641 static struct checksum_type checksum_hmac_sha1_des3 = {
1642     CKSUMTYPE_HMAC_SHA1_DES3,
1643     "hmac-sha1-des3",
1644     64,
1645     20,
1646     F_KEYED | F_CPROOF | F_DERIVED,
1647     SP_HMAC_SHA1_checksum,
1648     NULL
1649 };
1650
1651 static struct checksum_type checksum_hmac_sha1_aes128 = {
1652     CKSUMTYPE_HMAC_SHA1_96_AES_128,
1653     "hmac-sha1-96-aes128",
1654     64,
1655     12,
1656     F_KEYED | F_CPROOF | F_DERIVED,
1657     SP_HMAC_SHA1_checksum,
1658     NULL
1659 };
1660
1661 static struct checksum_type checksum_hmac_sha1_aes256 = {
1662     CKSUMTYPE_HMAC_SHA1_96_AES_256,
1663     "hmac-sha1-96-aes256",
1664     64,
1665     12,
1666     F_KEYED | F_CPROOF | F_DERIVED,
1667     SP_HMAC_SHA1_checksum,
1668     NULL
1669 };
1670
1671 static struct checksum_type checksum_hmac_md5 = {
1672     CKSUMTYPE_HMAC_MD5,
1673     "hmac-md5",
1674     64,
1675     16,
1676     F_KEYED | F_CPROOF,
1677     HMAC_MD5_checksum,
1678     NULL
1679 };
1680
1681 static struct checksum_type *checksum_types[] = {
1682     &checksum_none,
1683 #ifdef HEIM_WEAK_CRYPTO
1684     &checksum_crc32,
1685     &checksum_rsa_md4,
1686     &checksum_rsa_md4_des,
1687     &checksum_rsa_md5_des,
1688 #endif
1689 #ifdef DES3_OLD_ENCTYPE
1690     &checksum_rsa_md5_des3,
1691 #endif
1692     &checksum_rsa_md5,
1693     &checksum_sha1,
1694     &checksum_hmac_sha1_des3,
1695     &checksum_hmac_sha1_aes128,
1696     &checksum_hmac_sha1_aes256,
1697     &checksum_hmac_md5
1698 };
1699
1700 static int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]);
1701
1702 static struct checksum_type *
1703 _find_checksum(krb5_cksumtype type)
1704 {
1705     int i;
1706     for(i = 0; i < num_checksums; i++)
1707         if(checksum_types[i]->type == type)
1708             return checksum_types[i];
1709     return NULL;
1710 }
1711
1712 static krb5_error_code
1713 get_checksum_key(krb5_context context,
1714                  krb5_crypto crypto,
1715                  unsigned usage,  /* not krb5_key_usage */
1716                  struct checksum_type *ct,
1717                  struct key_data **key)
1718 {
1719     krb5_error_code ret = 0;
1720
1721     if(ct->flags & F_DERIVED)
1722         ret = _get_derived_key(context, crypto, usage, key);
1723     else if(ct->flags & F_VARIANT) {
1724         int i;
1725
1726         *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
1727         if(*key == NULL) {
1728             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1729             return ENOMEM;
1730         }
1731         ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
1732         if(ret)
1733             return ret;
1734         for(i = 0; i < (*key)->key->keyvalue.length; i++)
1735             ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
1736     } else {
1737         *key = &crypto->key;
1738     }
1739     if(ret == 0)
1740         ret = _key_schedule(context, *key);
1741     return ret;
1742 }
1743
1744 static krb5_error_code
1745 create_checksum (krb5_context context,
1746                  struct checksum_type *ct,
1747                  krb5_crypto crypto,
1748                  unsigned usage,
1749                  void *data,
1750                  size_t len,
1751                  Checksum *result)
1752 {
1753     krb5_error_code ret;
1754     struct key_data *dkey;
1755     int keyed_checksum;
1756
1757     if (ct->flags & F_DISABLED) {
1758         krb5_clear_error_message (context);
1759         return KRB5_PROG_SUMTYPE_NOSUPP;
1760     }
1761     keyed_checksum = (ct->flags & F_KEYED) != 0;
1762     if(keyed_checksum && crypto == NULL) {
1763         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1764                                 N_("Checksum type %s is keyed but no "
1765                                    "crypto context (key) was passed in", ""),
1766                                 ct->name);
1767         return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1768     }
1769     if(keyed_checksum) {
1770         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1771         if (ret)
1772             return ret;
1773     } else
1774         dkey = NULL;
1775     result->cksumtype = ct->type;
1776     ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
1777     if (ret)
1778         return (ret);
1779     return (*ct->checksum)(context, dkey, data, len, usage, result);
1780 }
1781
1782 static int
1783 arcfour_checksum_p(struct checksum_type *ct, krb5_crypto crypto)
1784 {
1785     return (ct->type == CKSUMTYPE_HMAC_MD5) &&
1786         (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
1787 }
1788
1789 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1790 krb5_create_checksum(krb5_context context,
1791                      krb5_crypto crypto,
1792                      krb5_key_usage usage,
1793                      int type,
1794                      void *data,
1795                      size_t len,
1796                      Checksum *result)
1797 {
1798     struct checksum_type *ct = NULL;
1799     unsigned keyusage;
1800
1801     /* type 0 -> pick from crypto */
1802     if (type) {
1803         ct = _find_checksum(type);
1804     } else if (crypto) {
1805         ct = crypto->et->keyed_checksum;
1806         if (ct == NULL)
1807             ct = crypto->et->checksum;
1808     }
1809
1810     if(ct == NULL) {
1811         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1812                                 N_("checksum type %d not supported", ""),
1813                                 type);
1814         return KRB5_PROG_SUMTYPE_NOSUPP;
1815     }
1816
1817     if (arcfour_checksum_p(ct, crypto)) {
1818         keyusage = usage;
1819         usage2arcfour(context, &keyusage);
1820     } else
1821         keyusage = CHECKSUM_USAGE(usage);
1822
1823     return create_checksum(context, ct, crypto, keyusage,
1824                            data, len, result);
1825 }
1826
1827 static krb5_error_code
1828 verify_checksum(krb5_context context,
1829                 krb5_crypto crypto,
1830                 unsigned usage, /* not krb5_key_usage */
1831                 void *data,
1832                 size_t len,
1833                 Checksum *cksum)
1834 {
1835     krb5_error_code ret;
1836     struct key_data *dkey;
1837     int keyed_checksum;
1838     Checksum c;
1839     struct checksum_type *ct;
1840
1841     ct = _find_checksum(cksum->cksumtype);
1842     if (ct == NULL || (ct->flags & F_DISABLED)) {
1843         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1844                                 N_("checksum type %d not supported", ""),
1845                                 cksum->cksumtype);
1846         return KRB5_PROG_SUMTYPE_NOSUPP;
1847     }
1848     if(ct->checksumsize != cksum->checksum.length) {
1849         krb5_clear_error_message (context);
1850         krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
1851                                N_("Decrypt integrity check failed for checksum type %s, "
1852                                   "length was %u, expected %u", ""),
1853                                ct->name, (unsigned)cksum->checksum.length,
1854                                (unsigned)ct->checksumsize);
1855
1856         return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
1857     }
1858     keyed_checksum = (ct->flags & F_KEYED) != 0;
1859     if(keyed_checksum) {
1860         struct checksum_type *kct;
1861         if (crypto == NULL) {
1862             krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
1863                                    N_("Checksum type %s is keyed but no "
1864                                       "crypto context (key) was passed in", ""),
1865                                    ct->name);
1866             return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1867         }
1868         kct = crypto->et->keyed_checksum;
1869         if (kct != NULL && kct->type != ct->type) {
1870             krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
1871                                    N_("Checksum type %s is keyed, but "
1872                                       "the key type %s passed didnt have that checksum "
1873                                       "type as the keyed type", ""),
1874                                     ct->name, crypto->et->name);
1875             return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1876         }
1877
1878         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1879         if (ret)
1880             return ret;
1881     } else
1882         dkey = NULL;
1883
1884     /*
1885      * If checksum have a verify function, lets use that instead of
1886      * calling ->checksum and then compare result.
1887      */
1888
1889     if(ct->verify) {
1890         ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
1891         if (ret)
1892             krb5_set_error_message(context, ret, 
1893                                    N_("Decrypt integrity check failed for checksum "
1894                                       "type %s, key type %s", ""),
1895                                    ct->name, crypto->et->name);
1896         return ret;
1897     }
1898
1899     ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
1900     if (ret)
1901         return ret;
1902
1903     ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
1904     if (ret) {
1905         krb5_data_free(&c.checksum);
1906         return ret;
1907     }
1908
1909     if(c.checksum.length != cksum->checksum.length ||
1910        ct_memcmp(c.checksum.data, cksum->checksum.data, c.checksum.length)) {
1911         krb5_clear_error_message (context);
1912         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1913         krb5_set_error_message(context, ret,
1914                                N_("Decrypt integrity check failed for checksum "
1915                                   "type %s, key type %s", ""),
1916                                ct->name, crypto->et->name);
1917     } else {
1918         ret = 0;
1919     }
1920     krb5_data_free (&c.checksum);
1921     return ret;
1922 }
1923
1924 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1925 krb5_verify_checksum(krb5_context context,
1926                      krb5_crypto crypto,
1927                      krb5_key_usage usage,
1928                      void *data,
1929                      size_t len,
1930                      Checksum *cksum)
1931 {
1932     struct checksum_type *ct;
1933     unsigned keyusage;
1934
1935     ct = _find_checksum(cksum->cksumtype);
1936     if(ct == NULL) {
1937         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1938                                 N_("checksum type %d not supported", ""),
1939                                 cksum->cksumtype);
1940         return KRB5_PROG_SUMTYPE_NOSUPP;
1941     }
1942
1943     if (arcfour_checksum_p(ct, crypto)) {
1944         keyusage = usage;
1945         usage2arcfour(context, &keyusage);
1946     } else
1947         keyusage = CHECKSUM_USAGE(usage);
1948
1949     return verify_checksum(context, crypto, keyusage,
1950                            data, len, cksum);
1951 }
1952
1953 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1954 krb5_crypto_get_checksum_type(krb5_context context,
1955                               krb5_crypto crypto,
1956                               krb5_cksumtype *type)
1957 {
1958     struct checksum_type *ct = NULL;
1959
1960     if (crypto != NULL) {
1961         ct = crypto->et->keyed_checksum;
1962         if (ct == NULL)
1963             ct = crypto->et->checksum;
1964     }
1965
1966     if (ct == NULL) {
1967         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1968                                 N_("checksum type not found", ""));
1969         return KRB5_PROG_SUMTYPE_NOSUPP;
1970     }
1971
1972     *type = ct->type;
1973
1974     return 0;
1975 }
1976
1977
1978 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1979 krb5_checksumsize(krb5_context context,
1980                   krb5_cksumtype type,
1981                   size_t *size)
1982 {
1983     struct checksum_type *ct = _find_checksum(type);
1984     if(ct == NULL) {
1985         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
1986                                 N_("checksum type %d not supported", ""),
1987                                 type);
1988         return KRB5_PROG_SUMTYPE_NOSUPP;
1989     }
1990     *size = ct->checksumsize;
1991     return 0;
1992 }
1993
1994 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1995 krb5_checksum_is_keyed(krb5_context context,
1996                        krb5_cksumtype type)
1997 {
1998     struct checksum_type *ct = _find_checksum(type);
1999     if(ct == NULL) {
2000         if (context)
2001             krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2002                                     N_("checksum type %d not supported", ""),
2003                                     type);
2004         return KRB5_PROG_SUMTYPE_NOSUPP;
2005     }
2006     return ct->flags & F_KEYED;
2007 }
2008
2009 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2010 krb5_checksum_is_collision_proof(krb5_context context,
2011                                  krb5_cksumtype type)
2012 {
2013     struct checksum_type *ct = _find_checksum(type);
2014     if(ct == NULL) {
2015         if (context)
2016             krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2017                                     N_("checksum type %d not supported", ""),
2018                                     type);
2019         return KRB5_PROG_SUMTYPE_NOSUPP;
2020     }
2021     return ct->flags & F_CPROOF;
2022 }
2023
2024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2025 krb5_checksum_disable(krb5_context context,
2026                       krb5_cksumtype type)
2027 {
2028     struct checksum_type *ct = _find_checksum(type);
2029     if(ct == NULL) {
2030         if (context)
2031             krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2032                                     N_("checksum type %d not supported", ""),
2033                                     type);
2034         return KRB5_PROG_SUMTYPE_NOSUPP;
2035     }
2036     ct->flags |= F_DISABLED;
2037     return 0;
2038 }
2039
2040 /************************************************************
2041  *                                                          *
2042  ************************************************************/
2043
2044 static krb5_error_code
2045 NULL_encrypt(krb5_context context,
2046              struct key_data *key,
2047              void *data,
2048              size_t len,
2049              krb5_boolean encryptp,
2050              int usage,
2051              void *ivec)
2052 {
2053     return 0;
2054 }
2055
2056 static krb5_error_code
2057 evp_encrypt(krb5_context context,
2058             struct key_data *key,
2059             void *data,
2060             size_t len,
2061             krb5_boolean encryptp,
2062             int usage,
2063             void *ivec)
2064 {
2065     struct evp_schedule *ctx = key->schedule->data;
2066     EVP_CIPHER_CTX *c;
2067     c = encryptp ? &ctx->ectx : &ctx->dctx;
2068     if (ivec == NULL) {
2069         /* alloca ? */
2070         size_t len2 = EVP_CIPHER_CTX_iv_length(c);
2071         void *loiv = malloc(len2);
2072         if (loiv == NULL) {
2073             krb5_clear_error_message(context);
2074             return ENOMEM;
2075         }
2076         memset(loiv, 0, len2);
2077         EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1);
2078         free(loiv);
2079     } else
2080         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
2081     EVP_Cipher(c, data, data, len);
2082     return 0;
2083 }
2084
2085 static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };
2086
2087 static krb5_error_code
2088 evp_encrypt_cts(krb5_context context,
2089                 struct key_data *key,
2090                 void *data,
2091                 size_t len,
2092                 krb5_boolean encryptp,
2093                 int usage,
2094                 void *ivec)
2095 {
2096     size_t i, blocksize;
2097     struct evp_schedule *ctx = key->schedule->data;
2098     char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
2099     EVP_CIPHER_CTX *c;
2100     unsigned char *p;
2101
2102     c = encryptp ? &ctx->ectx : &ctx->dctx;
2103
2104     blocksize = EVP_CIPHER_CTX_block_size(c);
2105
2106     if (len < blocksize) {
2107         krb5_set_error_message(context, EINVAL,
2108                                "message block too short");
2109         return EINVAL;
2110     } else if (len == blocksize) {
2111         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
2112         EVP_Cipher(c, data, data, len);
2113         return 0;
2114     }
2115
2116     if (ivec)
2117         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
2118     else
2119         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
2120
2121     if (encryptp) {
2122
2123         p = data;
2124         i = ((len - 1) / blocksize) * blocksize;
2125         EVP_Cipher(c, p, p, i);
2126         p += i - blocksize;
2127         len -= i;
2128         memcpy(ivec2, p, blocksize);
2129
2130         for (i = 0; i < len; i++)
2131             tmp[i] = p[i + blocksize] ^ ivec2[i];
2132         for (; i < blocksize; i++)
2133             tmp[i] = 0 ^ ivec2[i];
2134         
2135         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
2136         EVP_Cipher(c, p, tmp, blocksize);
2137         
2138         memcpy(p + blocksize, ivec2, len);
2139         if (ivec)
2140             memcpy(ivec, p, blocksize);
2141     } else { 
2142         char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH];
2143
2144         p = data;
2145         if (len > blocksize * 2) {
2146             /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */
2147             i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize);
2148             memcpy(ivec2, p + i - blocksize, blocksize);
2149             EVP_Cipher(c, p, p, i);
2150             p += i;
2151             len -= i + blocksize;
2152         } else {
2153             if (ivec)
2154                 memcpy(ivec2, ivec, blocksize);
2155             else
2156                 memcpy(ivec2, zero_ivec, blocksize);
2157             len -= blocksize;
2158         }
2159
2160         memcpy(tmp, p, blocksize);
2161         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
2162         EVP_Cipher(c, tmp2, p, blocksize);
2163
2164         memcpy(tmp3, p + blocksize, len);
2165         memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */
2166
2167         for (i = 0; i < len; i++)
2168             p[i + blocksize] = tmp2[i] ^ tmp3[i];
2169
2170         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
2171         EVP_Cipher(c, p, tmp3, blocksize);
2172
2173         for (i = 0; i < blocksize; i++)
2174             p[i] ^= ivec2[i];
2175         if (ivec)
2176             memcpy(ivec, tmp, blocksize);
2177     }
2178     return 0;
2179 }
2180
2181 #ifdef HEIM_WEAK_CRYPTO
2182 static krb5_error_code
2183 evp_des_encrypt_null_ivec(krb5_context context,
2184                           struct key_data *key,
2185                           void *data,
2186                           size_t len,
2187                           krb5_boolean encryptp,
2188                           int usage,
2189                           void *ignore_ivec)
2190 {
2191     struct evp_schedule *ctx = key->schedule->data;
2192     EVP_CIPHER_CTX *c;
2193     DES_cblock ivec;
2194     memset(&ivec, 0, sizeof(ivec));
2195     c = encryptp ? &ctx->ectx : &ctx->dctx;
2196     EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1);
2197     EVP_Cipher(c, data, data, len);
2198     return 0;
2199 }
2200
2201 static krb5_error_code
2202 evp_des_encrypt_key_ivec(krb5_context context,
2203                          struct key_data *key,
2204                          void *data,
2205                          size_t len,
2206                          krb5_boolean encryptp,
2207                          int usage,
2208                          void *ignore_ivec)
2209 {
2210     struct evp_schedule *ctx = key->schedule->data;
2211     EVP_CIPHER_CTX *c;
2212     DES_cblock ivec;
2213     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
2214     c = encryptp ? &ctx->ectx : &ctx->dctx;
2215     EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1);
2216     EVP_Cipher(c, data, data, len);
2217     return 0;
2218 }
2219
2220 static krb5_error_code
2221 DES_CFB64_encrypt_null_ivec(krb5_context context,
2222                             struct key_data *key,
2223                             void *data,
2224                             size_t len,
2225                             krb5_boolean encryptp,
2226                             int usage,
2227                             void *ignore_ivec)
2228 {
2229     DES_cblock ivec;
2230     int num = 0;
2231     DES_key_schedule *s = key->schedule->data;
2232     memset(&ivec, 0, sizeof(ivec));
2233
2234     DES_cfb64_encrypt(data, data, len, s, &ivec, &num, encryptp);
2235     return 0;
2236 }
2237
2238 static krb5_error_code
2239 DES_PCBC_encrypt_key_ivec(krb5_context context,
2240                           struct key_data *key,
2241                           void *data,
2242                           size_t len,
2243                           krb5_boolean encryptp,
2244                           int usage,
2245                           void *ignore_ivec)
2246 {
2247     DES_cblock ivec;
2248     DES_key_schedule *s = key->schedule->data;
2249     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
2250
2251     DES_pcbc_encrypt(data, data, len, s, &ivec, encryptp);
2252     return 0;
2253 }
2254 #endif
2255
2256 /*
2257  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
2258  *
2259  * warning: not for small children
2260  */
2261
2262 static krb5_error_code
2263 ARCFOUR_subencrypt(krb5_context context,
2264                    struct key_data *key,
2265                    void *data,
2266                    size_t len,
2267                    unsigned usage,
2268                    void *ivec)
2269 {
2270     EVP_CIPHER_CTX ctx;
2271     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
2272     Checksum k1_c, k2_c, k3_c, cksum;
2273     struct key_data ke;
2274     krb5_keyblock kb;
2275     unsigned char t[4];
2276     unsigned char *cdata = data;
2277     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
2278     krb5_error_code ret;
2279
2280     t[0] = (usage >>  0) & 0xFF;
2281     t[1] = (usage >>  8) & 0xFF;
2282     t[2] = (usage >> 16) & 0xFF;
2283     t[3] = (usage >> 24) & 0xFF;
2284
2285     k1_c.checksum.length = sizeof(k1_c_data);
2286     k1_c.checksum.data   = k1_c_data;
2287
2288     ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
2289     if (ret)
2290         krb5_abortx(context, "hmac failed");
2291
2292     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
2293
2294     k2_c.checksum.length = sizeof(k2_c_data);
2295     k2_c.checksum.data   = k2_c_data;
2296
2297     ke.key = &kb;
2298     kb.keyvalue = k2_c.checksum;
2299
2300     cksum.checksum.length = 16;
2301     cksum.checksum.data   = data;
2302
2303     ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
2304     if (ret)
2305         krb5_abortx(context, "hmac failed");
2306
2307     ke.key = &kb;
2308     kb.keyvalue = k1_c.checksum;
2309
2310     k3_c.checksum.length = sizeof(k3_c_data);
2311     k3_c.checksum.data   = k3_c_data;
2312
2313     ret = hmac(NULL, c, data, 16, 0, &ke, &k3_c);
2314     if (ret)
2315         krb5_abortx(context, "hmac failed");
2316
2317     EVP_CIPHER_CTX_init(&ctx);
2318
2319     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
2320     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
2321     EVP_CIPHER_CTX_cleanup(&ctx);
2322
2323     memset (k1_c_data, 0, sizeof(k1_c_data));
2324     memset (k2_c_data, 0, sizeof(k2_c_data));
2325     memset (k3_c_data, 0, sizeof(k3_c_data));
2326     return 0;
2327 }
2328
2329 static krb5_error_code
2330 ARCFOUR_subdecrypt(krb5_context context,
2331                    struct key_data *key,
2332                    void *data,
2333                    size_t len,
2334                    unsigned usage,
2335                    void *ivec)
2336 {
2337     EVP_CIPHER_CTX ctx;
2338     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
2339     Checksum k1_c, k2_c, k3_c, cksum;
2340     struct key_data ke;
2341     krb5_keyblock kb;
2342     unsigned char t[4];
2343     unsigned char *cdata = data;
2344     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
2345     unsigned char cksum_data[16];
2346     krb5_error_code ret;
2347
2348     t[0] = (usage >>  0) & 0xFF;
2349     t[1] = (usage >>  8) & 0xFF;
2350     t[2] = (usage >> 16) & 0xFF;
2351     t[3] = (usage >> 24) & 0xFF;
2352
2353     k1_c.checksum.length = sizeof(k1_c_data);
2354     k1_c.checksum.data   = k1_c_data;
2355
2356     ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
2357     if (ret)
2358         krb5_abortx(context, "hmac failed");
2359
2360     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
2361
2362     k2_c.checksum.length = sizeof(k2_c_data);
2363     k2_c.checksum.data   = k2_c_data;
2364
2365     ke.key = &kb;
2366     kb.keyvalue = k1_c.checksum;
2367
2368     k3_c.checksum.length = sizeof(k3_c_data);
2369     k3_c.checksum.data   = k3_c_data;
2370
2371     ret = hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
2372     if (ret)
2373         krb5_abortx(context, "hmac failed");
2374
2375     EVP_CIPHER_CTX_init(&ctx);
2376     EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
2377     EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
2378     EVP_CIPHER_CTX_cleanup(&ctx);
2379
2380     ke.key = &kb;
2381     kb.keyvalue = k2_c.checksum;
2382
2383     cksum.checksum.length = 16;
2384     cksum.checksum.data   = cksum_data;
2385
2386     ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
2387     if (ret)
2388         krb5_abortx(context, "hmac failed");
2389
2390     memset (k1_c_data, 0, sizeof(k1_c_data));
2391     memset (k2_c_data, 0, sizeof(k2_c_data));
2392     memset (k3_c_data, 0, sizeof(k3_c_data));
2393
2394     if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
2395         krb5_clear_error_message (context);
2396         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
2397     } else {
2398         return 0;
2399     }
2400 }
2401
2402 /*
2403  * convert the usage numbers used in
2404  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
2405  * draft-brezak-win2k-krb-rc4-hmac-04.txt
2406  */
2407
2408 static krb5_error_code
2409 usage2arcfour (krb5_context context, unsigned *usage)
2410 {
2411     switch (*usage) {
2412     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
2413         *usage = 8;
2414         return 0;
2415     case KRB5_KU_USAGE_SEAL :  /* 22 */
2416         *usage = 13;
2417         return 0;
2418     case KRB5_KU_USAGE_SIGN : /* 23 */
2419         *usage = 15;
2420         return 0;
2421     case KRB5_KU_USAGE_SEQ: /* 24 */
2422         *usage = 0;
2423         return 0;
2424     default :
2425         return 0;
2426     }
2427 }
2428
2429 static krb5_error_code
2430 ARCFOUR_encrypt(krb5_context context,
2431                 struct key_data *key,
2432                 void *data,
2433                 size_t len,
2434                 krb5_boolean encryptp,
2435                 int usage,
2436                 void *ivec)
2437 {
2438     krb5_error_code ret;
2439     unsigned keyusage = usage;
2440
2441     if((ret = usage2arcfour (context, &keyusage)) != 0)
2442         return ret;
2443
2444     if (encryptp)
2445         return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
2446     else
2447         return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
2448 }
2449
2450
2451 /*
2452  *
2453  */
2454
2455 static krb5_error_code
2456 AES_PRF(krb5_context context,
2457         krb5_crypto crypto,
2458         const krb5_data *in,
2459         krb5_data *out)
2460 {
2461     struct checksum_type *ct = crypto->et->checksum;
2462     krb5_error_code ret;
2463     Checksum result;
2464     krb5_keyblock *derived;
2465
2466     result.cksumtype = ct->type;
2467     ret = krb5_data_alloc(&result.checksum, ct->checksumsize);
2468     if (ret) {
2469         krb5_set_error_message(context, ret, N_("malloc: out memory", ""));
2470         return ret;
2471     }
2472
2473     ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result);
2474     if (ret) {
2475         krb5_data_free(&result.checksum);
2476         return ret;
2477     }
2478
2479     if (result.checksum.length < crypto->et->blocksize)
2480         krb5_abortx(context, "internal prf error");
2481
2482     derived = NULL;
2483     ret = krb5_derive_key(context, crypto->key.key,
2484                           crypto->et->type, "prf", 3, &derived);
2485     if (ret)
2486         krb5_abortx(context, "krb5_derive_key");
2487
2488     ret = krb5_data_alloc(out, crypto->et->blocksize);
2489     if (ret)
2490         krb5_abortx(context, "malloc failed");
2491
2492     {
2493         const EVP_CIPHER *c = (*crypto->et->keytype->evp)();
2494         EVP_CIPHER_CTX ctx;
2495
2496         EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */
2497         EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1);
2498         EVP_Cipher(&ctx, out->data, result.checksum.data,
2499                    crypto->et->blocksize);
2500         EVP_CIPHER_CTX_cleanup(&ctx);
2501     }
2502
2503     krb5_data_free(&result.checksum);
2504     krb5_free_keyblock(context, derived);
2505
2506     return ret;
2507 }
2508
2509 /*
2510  * these should currently be in reverse preference order.
2511  * (only relevant for !F_PSEUDO) */
2512
2513 static struct encryption_type enctype_null = {
2514     ETYPE_NULL,
2515     "null",
2516     1,
2517     1,
2518     0,
2519     &keytype_null,
2520     &checksum_none,
2521     NULL,
2522     F_DISABLED,
2523     NULL_encrypt,
2524     0,
2525     NULL
2526 };
2527 static struct encryption_type enctype_arcfour_hmac_md5 = {
2528     ETYPE_ARCFOUR_HMAC_MD5,
2529     "arcfour-hmac-md5",
2530     1,
2531     1,
2532     8,
2533     &keytype_arcfour,
2534     &checksum_hmac_md5,
2535     NULL,
2536     F_SPECIAL,
2537     ARCFOUR_encrypt,
2538     0,
2539     NULL
2540 };
2541 #ifdef DES3_OLD_ENCTYPE
2542 static struct encryption_type enctype_des3_cbc_md5 = {
2543     ETYPE_DES3_CBC_MD5,
2544     "des3-cbc-md5",
2545     8,
2546     8,
2547     8,
2548     &keytype_des3,
2549     &checksum_rsa_md5,
2550     &checksum_rsa_md5_des3,
2551     0,
2552     evp_encrypt,
2553     0,
2554     NULL
2555 };
2556 #endif
2557 static struct encryption_type enctype_des3_cbc_sha1 = {
2558     ETYPE_DES3_CBC_SHA1,
2559     "des3-cbc-sha1",
2560     8,
2561     8,
2562     8,
2563     &keytype_des3_derived,
2564     &checksum_sha1,
2565     &checksum_hmac_sha1_des3,
2566     F_DERIVED,
2567     evp_encrypt,
2568     0,
2569     NULL
2570 };
2571 #ifdef DES3_OLD_ENCTYPE
2572 static struct encryption_type enctype_old_des3_cbc_sha1 = {
2573     ETYPE_OLD_DES3_CBC_SHA1,
2574     "old-des3-cbc-sha1",
2575     8,
2576     8,
2577     8,
2578     &keytype_des3,
2579     &checksum_sha1,
2580     &checksum_hmac_sha1_des3,
2581     0,
2582     evp_encrypt,
2583     0,
2584     NULL
2585 };
2586 #endif
2587 static struct encryption_type enctype_aes128_cts_hmac_sha1 = {
2588     ETYPE_AES128_CTS_HMAC_SHA1_96,
2589     "aes128-cts-hmac-sha1-96",
2590     16,
2591     1,
2592     16,
2593     &keytype_aes128,
2594     &checksum_sha1,
2595     &checksum_hmac_sha1_aes128,
2596     F_DERIVED,
2597     evp_encrypt_cts,
2598     16,
2599     AES_PRF
2600 };
2601 static struct encryption_type enctype_aes256_cts_hmac_sha1 = {
2602     ETYPE_AES256_CTS_HMAC_SHA1_96,
2603     "aes256-cts-hmac-sha1-96",
2604     16,
2605     1,
2606     16,
2607     &keytype_aes256,
2608     &checksum_sha1,
2609     &checksum_hmac_sha1_aes256,
2610     F_DERIVED,
2611     evp_encrypt_cts,
2612     16,
2613     AES_PRF
2614 };
2615 static struct encryption_type enctype_des3_cbc_none = {
2616     ETYPE_DES3_CBC_NONE,
2617     "des3-cbc-none",
2618     8,
2619     8,
2620     0,
2621     &keytype_des3_derived,
2622     &checksum_none,
2623     NULL,
2624     F_PSEUDO,
2625     evp_encrypt,
2626     0,
2627     NULL
2628 };
2629 #ifdef HEIM_WEAK_CRYPTO
2630 static struct encryption_type enctype_des_cbc_crc = {
2631     ETYPE_DES_CBC_CRC,
2632     "des-cbc-crc",
2633     8,
2634     8,
2635     8,
2636     &keytype_des,
2637     &checksum_crc32,
2638     NULL,
2639     F_DISABLED|F_WEAK,
2640     evp_des_encrypt_key_ivec,
2641     0,
2642     NULL
2643 };
2644 static struct encryption_type enctype_des_cbc_md4 = {
2645     ETYPE_DES_CBC_MD4,
2646     "des-cbc-md4",
2647     8,
2648     8,
2649     8,
2650     &keytype_des,
2651     &checksum_rsa_md4,
2652     &checksum_rsa_md4_des,
2653     F_DISABLED|F_WEAK,
2654     evp_des_encrypt_null_ivec,
2655     0,
2656     NULL
2657 };
2658 static struct encryption_type enctype_des_cbc_md5 = {
2659     ETYPE_DES_CBC_MD5,
2660     "des-cbc-md5",
2661     8,
2662     8,
2663     8,
2664     &keytype_des,
2665     &checksum_rsa_md5,
2666     &checksum_rsa_md5_des,
2667     F_DISABLED|F_WEAK,
2668     evp_des_encrypt_null_ivec,
2669     0,
2670     NULL
2671 };
2672 static struct encryption_type enctype_des_cbc_none = {
2673     ETYPE_DES_CBC_NONE,
2674     "des-cbc-none",
2675     8,
2676     8,
2677     0,
2678     &keytype_des,
2679     &checksum_none,
2680     NULL,
2681     F_PSEUDO|F_DISABLED|F_WEAK,
2682     evp_des_encrypt_null_ivec,
2683     0,
2684     NULL
2685 };
2686 static struct encryption_type enctype_des_cfb64_none = {
2687     ETYPE_DES_CFB64_NONE,
2688     "des-cfb64-none",
2689     1,
2690     1,
2691     0,
2692     &keytype_des_old,
2693     &checksum_none,
2694     NULL,
2695     F_PSEUDO|F_DISABLED|F_WEAK,
2696     DES_CFB64_encrypt_null_ivec,
2697     0,
2698     NULL
2699 };
2700 static struct encryption_type enctype_des_pcbc_none = {
2701     ETYPE_DES_PCBC_NONE,
2702     "des-pcbc-none",
2703     8,
2704     8,
2705     0,
2706     &keytype_des_old,
2707     &checksum_none,
2708     NULL,
2709     F_PSEUDO|F_DISABLED|F_WEAK,
2710     DES_PCBC_encrypt_key_ivec,
2711     0,
2712     NULL
2713 };
2714 #endif /* HEIM_WEAK_CRYPTO */
2715
2716 static struct encryption_type *etypes[] = {
2717     &enctype_aes256_cts_hmac_sha1,
2718     &enctype_aes128_cts_hmac_sha1,
2719     &enctype_des3_cbc_sha1,
2720     &enctype_des3_cbc_none, /* used by the gss-api mech */
2721     &enctype_arcfour_hmac_md5,
2722 #ifdef DES3_OLD_ENCTYPE
2723     &enctype_des3_cbc_md5,
2724     &enctype_old_des3_cbc_sha1,
2725 #endif
2726 #ifdef HEIM_WEAK_CRYPTO
2727     &enctype_des_cbc_crc,
2728     &enctype_des_cbc_md4,
2729     &enctype_des_cbc_md5,
2730     &enctype_des_cbc_none,
2731     &enctype_des_cfb64_none,
2732     &enctype_des_pcbc_none,
2733 #endif
2734     &enctype_null
2735 };
2736
2737 static unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]);
2738
2739
2740 static struct encryption_type *
2741 _find_enctype(krb5_enctype type)
2742 {
2743     int i;
2744     for(i = 0; i < num_etypes; i++)
2745         if(etypes[i]->type == type)
2746             return etypes[i];
2747     return NULL;
2748 }
2749
2750
2751 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2752 krb5_enctype_to_string(krb5_context context,
2753                        krb5_enctype etype,
2754                        char **string)
2755 {
2756     struct encryption_type *e;
2757     e = _find_enctype(etype);
2758     if(e == NULL) {
2759         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2760                                 N_("encryption type %d not supported", ""),
2761                                 etype);
2762         *string = NULL;
2763         return KRB5_PROG_ETYPE_NOSUPP;
2764     }
2765     *string = strdup(e->name);
2766     if(*string == NULL) {
2767         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2768         return ENOMEM;
2769     }
2770     return 0;
2771 }
2772
2773 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2774 krb5_string_to_enctype(krb5_context context,
2775                        const char *string,
2776                        krb5_enctype *etype)
2777 {
2778     int i;
2779     for(i = 0; i < num_etypes; i++)
2780         if(strcasecmp(etypes[i]->name, string) == 0){
2781             *etype = etypes[i]->type;
2782             return 0;
2783         }
2784     krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2785                             N_("encryption type %s not supported", ""),
2786                             string);
2787     return KRB5_PROG_ETYPE_NOSUPP;
2788 }
2789
2790 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2791 krb5_enctype_to_keytype(krb5_context context,
2792                         krb5_enctype etype,
2793                         krb5_keytype *keytype)
2794 {
2795     struct encryption_type *e = _find_enctype(etype);
2796     if(e == NULL) {
2797         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2798                                 N_("encryption type %d not supported", ""),
2799                                 etype);
2800         return KRB5_PROG_ETYPE_NOSUPP;
2801     }
2802     *keytype = e->keytype->type; /* XXX */
2803     return 0;
2804 }
2805
2806 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2807 krb5_enctype_valid(krb5_context context,
2808                    krb5_enctype etype)
2809 {
2810     struct encryption_type *e = _find_enctype(etype);
2811     if(e == NULL) {
2812         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2813                                 N_("encryption type %d not supported", ""),
2814                                 etype);
2815         return KRB5_PROG_ETYPE_NOSUPP;
2816     }
2817     if (e->flags & F_DISABLED) {
2818         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2819                                 N_("encryption type %s is disabled", ""),
2820                                 e->name);
2821         return KRB5_PROG_ETYPE_NOSUPP;
2822     }
2823     return 0;
2824 }
2825
2826 /**
2827  * Return the coresponding encryption type for a checksum type.
2828  *
2829  * @param context Kerberos context
2830  * @param ctype The checksum type to get the result enctype for
2831  * @param etype The returned encryption, when the matching etype is
2832  * not found, etype is set to ETYPE_NULL.
2833  *
2834  * @return Return an error code for an failure or 0 on success.
2835  * @ingroup krb5_crypto
2836  */
2837
2838
2839 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2840 krb5_cksumtype_to_enctype(krb5_context context,
2841                           krb5_cksumtype ctype,
2842                           krb5_enctype *etype)
2843 {
2844     int i;
2845
2846     *etype = ETYPE_NULL;
2847
2848     for(i = 0; i < num_etypes; i++) {
2849         if(etypes[i]->keyed_checksum &&
2850            etypes[i]->keyed_checksum->type == ctype)
2851             {
2852                 *etype = etypes[i]->type;
2853                 return 0;
2854             }
2855     }
2856
2857     krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2858                             N_("checksum type %d not supported", ""),
2859                             (int)ctype);
2860     return KRB5_PROG_SUMTYPE_NOSUPP;
2861 }
2862
2863
2864 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2865 krb5_cksumtype_valid(krb5_context context,
2866                      krb5_cksumtype ctype)
2867 {
2868     struct checksum_type *c = _find_checksum(ctype);
2869     if (c == NULL) {
2870         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2871                                 N_("checksum type %d not supported", ""),
2872                                 ctype);
2873         return KRB5_PROG_SUMTYPE_NOSUPP;
2874     }
2875     if (c->flags & F_DISABLED) {
2876         krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2877                                 N_("checksum type %s is disabled", ""),
2878                                 c->name);
2879         return KRB5_PROG_SUMTYPE_NOSUPP;
2880     }
2881     return 0;
2882 }
2883
2884
2885 static krb5_boolean
2886 derived_crypto(krb5_context context,
2887                krb5_crypto crypto)
2888 {
2889     return (crypto->et->flags & F_DERIVED) != 0;
2890 }
2891
2892 static krb5_boolean
2893 special_crypto(krb5_context context,
2894                krb5_crypto crypto)
2895 {
2896     return (crypto->et->flags & F_SPECIAL) != 0;
2897 }
2898
2899 #define CHECKSUMSIZE(C) ((C)->checksumsize)
2900 #define CHECKSUMTYPE(C) ((C)->type)
2901
2902 static krb5_error_code
2903 encrypt_internal_derived(krb5_context context,
2904                          krb5_crypto crypto,
2905                          unsigned usage,
2906                          const void *data,
2907                          size_t len,
2908                          krb5_data *result,
2909                          void *ivec)
2910 {
2911     size_t sz, block_sz, checksum_sz, total_sz;
2912     Checksum cksum;
2913     unsigned char *p, *q;
2914     krb5_error_code ret;
2915     struct key_data *dkey;
2916     const struct encryption_type *et = crypto->et;
2917
2918     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
2919
2920     sz = et->confoundersize + len;
2921     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
2922     total_sz = block_sz + checksum_sz;
2923     p = calloc(1, total_sz);
2924     if(p == NULL) {
2925         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2926         return ENOMEM;
2927     }
2928
2929     q = p;
2930     krb5_generate_random_block(q, et->confoundersize); /* XXX */
2931     q += et->confoundersize;
2932     memcpy(q, data, len);
2933
2934     ret = create_checksum(context,
2935                           et->keyed_checksum,
2936                           crypto,
2937                           INTEGRITY_USAGE(usage),
2938                           p,
2939                           block_sz,
2940                           &cksum);
2941     if(ret == 0 && cksum.checksum.length != checksum_sz) {
2942         free_Checksum (&cksum);
2943         krb5_clear_error_message (context);
2944         ret = KRB5_CRYPTO_INTERNAL;
2945     }
2946     if(ret)
2947         goto fail;
2948     memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
2949     free_Checksum (&cksum);
2950     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
2951     if(ret)
2952         goto fail;
2953     ret = _key_schedule(context, dkey);
2954     if(ret)
2955         goto fail;
2956     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
2957     if (ret)
2958         goto fail;
2959     result->data = p;
2960     result->length = total_sz;
2961     return 0;
2962  fail:
2963     memset(p, 0, total_sz);
2964     free(p);
2965     return ret;
2966 }
2967
2968
2969 static krb5_error_code
2970 encrypt_internal(krb5_context context,
2971                  krb5_crypto crypto,
2972                  const void *data,
2973                  size_t len,
2974                  krb5_data *result,
2975                  void *ivec)
2976 {
2977     size_t sz, block_sz, checksum_sz;
2978     Checksum cksum;
2979     unsigned char *p, *q;
2980     krb5_error_code ret;
2981     const struct encryption_type *et = crypto->et;
2982
2983     checksum_sz = CHECKSUMSIZE(et->checksum);
2984
2985     sz = et->confoundersize + checksum_sz + len;
2986     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
2987     p = calloc(1, block_sz);
2988     if(p == NULL) {
2989         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2990         return ENOMEM;
2991     }
2992
2993     q = p;
2994     krb5_generate_random_block(q, et->confoundersize); /* XXX */
2995     q += et->confoundersize;
2996     memset(q, 0, checksum_sz);
2997     q += checksum_sz;
2998     memcpy(q, data, len);
2999
3000     ret = create_checksum(context,
3001                           et->checksum,
3002                           crypto,
3003                           0,
3004                           p,
3005                           block_sz,
3006                           &cksum);
3007     if(ret == 0 && cksum.checksum.length != checksum_sz) {
3008         krb5_clear_error_message (context);
3009         free_Checksum(&cksum);
3010         ret = KRB5_CRYPTO_INTERNAL;
3011     }
3012     if(ret)
3013         goto fail;
3014     memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
3015     free_Checksum(&cksum);
3016     ret = _key_schedule(context, &crypto->key);
3017     if(ret)
3018         goto fail;
3019     ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
3020     if (ret) {
3021         memset(p, 0, block_sz);
3022         free(p);
3023         return ret;
3024     }
3025     result->data = p;
3026     result->length = block_sz;
3027     return 0;
3028  fail:
3029     memset(p, 0, block_sz);
3030     free(p);
3031     return ret;
3032 }
3033
3034 static krb5_error_code
3035 encrypt_internal_special(krb5_context context,
3036                          krb5_crypto crypto,
3037                          int usage,
3038                          const void *data,
3039                          size_t len,
3040                          krb5_data *result,
3041                          void *ivec)
3042 {
3043     struct encryption_type *et = crypto->et;
3044     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
3045     size_t sz = len + cksum_sz + et->confoundersize;
3046     char *tmp, *p;
3047     krb5_error_code ret;
3048
3049     tmp = malloc (sz);
3050     if (tmp == NULL) {
3051         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3052         return ENOMEM;
3053     }
3054     p = tmp;
3055     memset (p, 0, cksum_sz);
3056     p += cksum_sz;
3057     krb5_generate_random_block(p, et->confoundersize);
3058     p += et->confoundersize;
3059     memcpy (p, data, len);
3060     ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
3061     if (ret) {
3062         memset(tmp, 0, sz);
3063         free(tmp);
3064         return ret;
3065     }
3066     result->data   = tmp;
3067     result->length = sz;
3068     return 0;
3069 }
3070
3071 static krb5_error_code
3072 decrypt_internal_derived(krb5_context context,
3073                          krb5_crypto crypto,
3074                          unsigned usage,
3075                          void *data,
3076                          size_t len,
3077                          krb5_data *result,
3078                          void *ivec)
3079 {
3080     size_t checksum_sz;
3081     Checksum cksum;
3082     unsigned char *p;
3083     krb5_error_code ret;
3084     struct key_data *dkey;
3085     struct encryption_type *et = crypto->et;
3086     unsigned long l;
3087
3088     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
3089     if (len < checksum_sz + et->confoundersize) {
3090         krb5_set_error_message(context, KRB5_BAD_MSIZE,
3091                                N_("Encrypted data shorter then "
3092                                   "checksum + confunder", ""));
3093         return KRB5_BAD_MSIZE;
3094     }
3095
3096     if (((len - checksum_sz) % et->padsize) != 0) {
3097         krb5_clear_error_message(context);
3098         return KRB5_BAD_MSIZE;
3099     }
3100
3101     p = malloc(len);
3102     if(len != 0 && p == NULL) {
3103         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3104         return ENOMEM;
3105     }
3106     memcpy(p, data, len);
3107
3108     len -= checksum_sz;
3109
3110     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
3111     if(ret) {
3112         free(p);
3113         return ret;
3114     }
3115     ret = _key_schedule(context, dkey);
3116     if(ret) {
3117         free(p);
3118         return ret;
3119     }
3120     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
3121     if (ret) {
3122         free(p);
3123         return ret;
3124     }
3125
3126     cksum.checksum.data   = p + len;
3127     cksum.checksum.length = checksum_sz;
3128     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
3129
3130     ret = verify_checksum(context,
3131                           crypto,
3132                           INTEGRITY_USAGE(usage),
3133                           p,
3134                           len,
3135                           &cksum);
3136     if(ret) {
3137         free(p);
3138         return ret;
3139     }
3140     l = len - et->confoundersize;
3141     memmove(p, p + et->confoundersize, l);
3142     result->data = realloc(p, l);
3143     if(result->data == NULL && l != 0) {
3144         free(p);
3145         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3146         return ENOMEM;
3147     }
3148     result->length = l;
3149     return 0;
3150 }
3151
3152 static krb5_error_code
3153 decrypt_internal(krb5_context context,
3154                  krb5_crypto crypto,
3155                  void *data,
3156                  size_t len,
3157                  krb5_data *result,
3158                  void *ivec)
3159 {
3160     krb5_error_code ret;
3161     unsigned char *p;
3162     Checksum cksum;
3163     size_t checksum_sz, l;
3164     struct encryption_type *et = crypto->et;
3165
3166     if ((len % et->padsize) != 0) {
3167         krb5_clear_error_message(context);
3168         return KRB5_BAD_MSIZE;
3169     }
3170     checksum_sz = CHECKSUMSIZE(et->checksum);
3171     if (len < checksum_sz + et->confoundersize) {
3172         krb5_set_error_message(context, KRB5_BAD_MSIZE,
3173                                N_("Encrypted data shorter then "
3174                                   "checksum + confunder", ""));
3175         return KRB5_BAD_MSIZE;
3176     }
3177
3178     p = malloc(len);
3179     if(len != 0 && p == NULL) {
3180         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3181         return ENOMEM;
3182     }
3183     memcpy(p, data, len);
3184
3185     ret = _key_schedule(context, &crypto->key);
3186     if(ret) {
3187         free(p);
3188         return ret;
3189     }
3190     ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
3191     if (ret) {
3192         free(p);
3193         return ret;
3194     }
3195     ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
3196     if(ret) {
3197         free(p);
3198         return ret;
3199     }
3200     memset(p + et->confoundersize, 0, checksum_sz);
3201     cksum.cksumtype = CHECKSUMTYPE(et->checksum);
3202     ret = verify_checksum(context, NULL, 0, p, len, &cksum);
3203     free_Checksum(&cksum);
3204     if(ret) {
3205         free(p);
3206         return ret;
3207     }
3208     l = len - et->confoundersize - checksum_sz;
3209     memmove(p, p + et->confoundersize + checksum_sz, l);
3210     result->data = realloc(p, l);
3211     if(result->data == NULL && l != 0) {
3212         free(p);
3213         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3214         return ENOMEM;
3215     }
3216     result->length = l;
3217     return 0;
3218 }
3219
3220 static krb5_error_code
3221 decrypt_internal_special(krb5_context context,
3222                          krb5_crypto crypto,
3223                          int usage,
3224                          void *data,
3225                          size_t len,
3226                          krb5_data *result,
3227                          void *ivec)
3228 {
3229     struct encryption_type *et = crypto->et;
3230     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
3231     size_t sz = len - cksum_sz - et->confoundersize;
3232     unsigned char *p;
3233     krb5_error_code ret;
3234
3235     if ((len % et->padsize) != 0) {
3236         krb5_clear_error_message(context);
3237         return KRB5_BAD_MSIZE;
3238     }
3239     if (len < cksum_sz + et->confoundersize) {
3240         krb5_set_error_message(context, KRB5_BAD_MSIZE,
3241                                N_("Encrypted data shorter then "
3242                                   "checksum + confunder", ""));
3243         return KRB5_BAD_MSIZE;
3244     }
3245
3246     p = malloc (len);
3247     if (p == NULL) {
3248         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3249         return ENOMEM;
3250     }
3251     memcpy(p, data, len);
3252
3253     ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
3254     if (ret) {
3255         free(p);
3256         return ret;
3257     }
3258
3259     memmove (p, p + cksum_sz + et->confoundersize, sz);
3260     result->data = realloc(p, sz);
3261     if(result->data == NULL && sz != 0) {
3262         free(p);
3263         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
3264         return ENOMEM;
3265     }
3266     result->length = sz;
3267     return 0;
3268 }
3269
3270 static krb5_crypto_iov *
3271 find_iv(krb5_crypto_iov *data, int num_data, int type)
3272 {
3273     int i;
3274     for (i = 0; i < num_data; i++)
3275         if (data[i].flags == type)
3276             return &data[i];
3277     return NULL;
3278 }
3279
3280 /**
3281  * Inline encrypt a kerberos message
3282  *
3283  * @param context Kerberos context
3284  * @param crypto Kerberos crypto context
3285  * @param usage Key usage for this buffer
3286  * @param data array of buffers to process
3287  * @param num_data length of array
3288  * @param ivec initial cbc/cts vector
3289  *
3290  * @return Return an error code or 0.
3291  * @ingroup krb5_crypto
3292  *
3293  * Kerberos encrypted data look like this:
3294  *
3295  * 1. KRB5_CRYPTO_TYPE_HEADER
3296  * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
3297  *    KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
3298  *    have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
3299  *    commonly used headers and trailers.
3300  * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
3301  * 4. KRB5_CRYPTO_TYPE_TRAILER
3302  */
3303
3304 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3305 krb5_encrypt_iov_ivec(krb5_context context,
3306                       krb5_crypto crypto,
3307                       unsigned usage,
3308                       krb5_crypto_iov *data,
3309                       int num_data,
3310                       void *ivec)
3311 {
3312     size_t headersz, trailersz, len;
3313     int i;
3314     size_t sz, block_sz, pad_sz;
3315     Checksum cksum;
3316     unsigned char *p, *q;
3317     krb5_error_code ret;
3318     struct key_data *dkey;
3319     const struct encryption_type *et = crypto->et;
3320     krb5_crypto_iov *tiv, *piv, *hiv;
3321
3322     if (num_data < 0) {
3323         krb5_clear_error_message(context);
3324         return KRB5_CRYPTO_INTERNAL;
3325     }
3326
3327     if(!derived_crypto(context, crypto)) {
3328         krb5_clear_error_message(context);
3329         return KRB5_CRYPTO_INTERNAL;
3330     }
3331
3332     headersz = et->confoundersize;
3333     trailersz = CHECKSUMSIZE(et->keyed_checksum);
3334
3335     for (len = 0, i = 0; i < num_data; i++) {
3336         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3337             continue;
3338         len += data[i].data.length;
3339     }
3340
3341     sz = headersz + len;
3342     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
3343
3344     pad_sz = block_sz - sz;
3345
3346     /* header */
3347
3348     hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
3349     if (hiv == NULL || hiv->data.length != headersz)
3350         return KRB5_BAD_MSIZE;
3351
3352     krb5_generate_random_block(hiv->data.data, hiv->data.length);
3353
3354     /* padding */
3355     piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
3356     /* its ok to have no TYPE_PADDING if there is no padding */
3357     if (piv == NULL && pad_sz != 0)
3358         return KRB5_BAD_MSIZE;
3359     if (piv) {
3360         if (piv->data.length < pad_sz)
3361             return KRB5_BAD_MSIZE;
3362         piv->data.length = pad_sz;
3363         if (pad_sz)
3364             memset(piv->data.data, pad_sz, pad_sz);
3365         else
3366             piv = NULL;
3367     }
3368
3369     /* trailer */
3370     tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
3371     if (tiv == NULL || tiv->data.length != trailersz)
3372         return KRB5_BAD_MSIZE;
3373
3374     /*
3375      * XXX replace with EVP_Sign? at least make create_checksum an iov
3376      * function.
3377      * XXX CTS EVP is broken, can't handle multi buffers :(
3378      */
3379
3380     len = block_sz;
3381     for (i = 0; i < num_data; i++) {
3382         if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3383             continue;
3384         len += data[i].data.length;
3385     }
3386
3387     p = q = malloc(len);
3388
3389     memcpy(q, hiv->data.data, hiv->data.length);
3390     q += hiv->data.length;
3391     for (i = 0; i < num_data; i++) {
3392         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3393             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3394             continue;
3395         memcpy(q, data[i].data.data, data[i].data.length);
3396         q += data[i].data.length;
3397     }
3398     if (piv)
3399         memset(q, 0, piv->data.length);
3400
3401     ret = create_checksum(context,
3402                           et->keyed_checksum,
3403                           crypto,
3404                           INTEGRITY_USAGE(usage),
3405                           p,
3406                           len,
3407                           &cksum);
3408     free(p);
3409     if(ret == 0 && cksum.checksum.length != trailersz) {
3410         free_Checksum (&cksum);
3411         krb5_clear_error_message (context);
3412         ret = KRB5_CRYPTO_INTERNAL;
3413     }
3414     if(ret)
3415         return ret;
3416
3417     /* save cksum at end */
3418     memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
3419     free_Checksum (&cksum);
3420
3421     /* XXX replace with EVP_Cipher */
3422     p = q = malloc(block_sz);
3423     if(p == NULL)
3424         return ENOMEM;
3425
3426     memcpy(q, hiv->data.data, hiv->data.length);
3427     q += hiv->data.length;
3428
3429     for (i = 0; i < num_data; i++) {
3430         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3431             continue;
3432         memcpy(q, data[i].data.data, data[i].data.length);
3433         q += data[i].data.length;
3434     }
3435     if (piv)
3436         memset(q, 0, piv->data.length);
3437
3438
3439     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
3440     if(ret) {
3441         free(p);
3442         return ret;
3443     }
3444     ret = _key_schedule(context, dkey);
3445     if(ret) {
3446         free(p);
3447         return ret;
3448     }
3449
3450     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
3451     if (ret) {
3452         free(p);
3453         return ret;
3454     }
3455
3456     /* now copy data back to buffers */
3457     q = p;
3458
3459     memcpy(hiv->data.data, q, hiv->data.length);
3460     q += hiv->data.length;
3461
3462     for (i = 0; i < num_data; i++) {
3463         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3464             continue;
3465         memcpy(data[i].data.data, q, data[i].data.length);
3466         q += data[i].data.length;
3467     }
3468     if (piv)
3469         memcpy(piv->data.data, q, pad_sz);
3470
3471     free(p);
3472
3473     return ret;
3474 }
3475
3476 /**
3477  * Inline decrypt a Kerberos message.
3478  *
3479  * @param context Kerberos context
3480  * @param crypto Kerberos crypto context
3481  * @param usage Key usage for this buffer
3482  * @param data array of buffers to process
3483  * @param num_data length of array
3484  * @param ivec initial cbc/cts vector
3485  *
3486  * @return Return an error code or 0.
3487  * @ingroup krb5_crypto
3488  *
3489  * 1. KRB5_CRYPTO_TYPE_HEADER
3490  * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
3491  *  any order, however the receiver have to aware of the
3492  *  order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
3493  *  protocol headers and trailers. The output data will be of same
3494  *  size as the input data or shorter.
3495  */
3496
3497 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3498 krb5_decrypt_iov_ivec(krb5_context context,
3499                       krb5_crypto crypto,
3500                       unsigned usage,
3501                       krb5_crypto_iov *data,
3502                       unsigned int num_data,
3503                       void *ivec)
3504 {
3505     unsigned int i;
3506     size_t headersz, trailersz, len;
3507     Checksum cksum;
3508     unsigned char *p, *q;
3509     krb5_error_code ret;
3510     struct key_data *dkey;
3511     struct encryption_type *et = crypto->et;
3512     krb5_crypto_iov *tiv, *hiv;
3513
3514     if (num_data < 0) {
3515         krb5_clear_error_message(context);
3516         return KRB5_CRYPTO_INTERNAL;
3517     }
3518
3519     if(!derived_crypto(context, crypto)) {
3520         krb5_clear_error_message(context);
3521         return KRB5_CRYPTO_INTERNAL;
3522     }
3523
3524     headersz = et->confoundersize;
3525
3526     hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
3527     if (hiv == NULL || hiv->data.length != headersz)
3528         return KRB5_BAD_MSIZE;
3529
3530     /* trailer */
3531     trailersz = CHECKSUMSIZE(et->keyed_checksum);
3532
3533     tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
3534     if (tiv->data.length != trailersz)
3535         return KRB5_BAD_MSIZE;
3536
3537     /* Find length of data we will decrypt */
3538
3539     len = headersz;
3540     for (i = 0; i < num_data; i++) {
3541         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3542             continue;
3543         len += data[i].data.length;
3544     }
3545
3546     if ((len % et->padsize) != 0) {
3547         krb5_clear_error_message(context);
3548         return KRB5_BAD_MSIZE;
3549     }
3550
3551     /* XXX replace with EVP_Cipher */
3552
3553     p = q = malloc(len);
3554     if (p == NULL)
3555         return ENOMEM;
3556
3557     memcpy(q, hiv->data.data, hiv->data.length);
3558     q += hiv->data.length;
3559
3560     for (i = 0; i < num_data; i++) {
3561         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3562             continue;
3563         memcpy(q, data[i].data.data, data[i].data.length);
3564         q += data[i].data.length;
3565     }
3566
3567     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
3568     if(ret) {
3569         free(p);
3570         return ret;
3571     }
3572     ret = _key_schedule(context, dkey);
3573     if(ret) {
3574         free(p);
3575         return ret;
3576     }
3577
3578     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
3579     if (ret) {
3580         free(p);
3581         return ret;
3582     }
3583
3584     /* copy data back to buffers */
3585     memcpy(hiv->data.data, p, hiv->data.length);
3586     q = p + hiv->data.length;
3587     for (i = 0; i < num_data; i++) {
3588         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
3589             continue;
3590         memcpy(data[i].data.data, q, data[i].data.length);
3591         q += data[i].data.length;
3592     }
3593
3594     free(p);
3595
3596     /* check signature */
3597     for (i = 0; i < num_data; i++) {
3598         if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3599             continue;
3600         len += data[i].data.length;
3601     }
3602
3603     p = q = malloc(len);
3604     if (p == NULL)
3605         return ENOMEM;
3606
3607     memcpy(q, hiv->data.data, hiv->data.length);
3608     q += hiv->data.length;
3609     for (i = 0; i < num_data; i++) {
3610         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3611             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3612             continue;
3613         memcpy(q, data[i].data.data, data[i].data.length);
3614         q += data[i].data.length;
3615     }
3616
3617     cksum.checksum.data   = tiv->data.data;
3618     cksum.checksum.length = tiv->data.length;
3619     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
3620
3621     ret = verify_checksum(context,
3622                           crypto,
3623                           INTEGRITY_USAGE(usage),
3624                           p,
3625                           len,
3626                           &cksum);
3627     free(p);
3628     return ret;
3629 }
3630
3631 /**
3632  * Create a Kerberos message checksum.
3633  *
3634  * @param context Kerberos context
3635  * @param crypto Kerberos crypto context
3636  * @param usage Key usage for this buffer
3637  * @param data array of buffers to process
3638  * @param num_data length of array
3639  * @param type output data
3640  *
3641  * @return Return an error code or 0.
3642  * @ingroup krb5_crypto
3643  */
3644
3645 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3646 krb5_create_checksum_iov(krb5_context context,
3647                          krb5_crypto crypto,
3648                          unsigned usage,
3649                          krb5_crypto_iov *data,
3650                          unsigned int num_data,
3651                          krb5_cksumtype *type)
3652 {
3653     Checksum cksum;
3654     krb5_crypto_iov *civ;
3655     krb5_error_code ret;
3656     int i;
3657     size_t len;
3658     char *p, *q;
3659
3660     if (num_data < 0) {
3661         krb5_clear_error_message(context);
3662         return KRB5_CRYPTO_INTERNAL;
3663     }
3664
3665     if(!derived_crypto(context, crypto)) {
3666         krb5_clear_error_message(context);
3667         return KRB5_CRYPTO_INTERNAL;
3668     }
3669
3670     civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
3671     if (civ == NULL)
3672         return KRB5_BAD_MSIZE;
3673
3674     len = 0;
3675     for (i = 0; i < num_data; i++) {
3676         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3677             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3678             continue;
3679         len += data[i].data.length;
3680     }
3681
3682     p = q = malloc(len);
3683
3684     for (i = 0; i < num_data; i++) {
3685         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3686             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3687             continue;
3688         memcpy(q, data[i].data.data, data[i].data.length);
3689         q += data[i].data.length;
3690     }
3691
3692     ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
3693     free(p);
3694     if (ret)
3695         return ret;
3696
3697     if (type)
3698         *type = cksum.cksumtype;
3699
3700     if (cksum.checksum.length > civ->data.length) {
3701         krb5_set_error_message(context, KRB5_BAD_MSIZE,
3702                                N_("Checksum larger then input buffer", ""));
3703         free_Checksum(&cksum);
3704         return KRB5_BAD_MSIZE;
3705     }
3706
3707     civ->data.length = cksum.checksum.length;
3708     memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
3709     free_Checksum(&cksum);
3710
3711     return 0;
3712 }
3713
3714 /**
3715  * Verify a Kerberos message checksum.
3716  *
3717  * @param context Kerberos context
3718  * @param crypto Kerberos crypto context
3719  * @param usage Key usage for this buffer
3720  * @param data array of buffers to process
3721  * @param num_data length of array
3722  * @param type return checksum type if not NULL
3723  *
3724  * @return Return an error code or 0.
3725  * @ingroup krb5_crypto
3726  */
3727
3728 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3729 krb5_verify_checksum_iov(krb5_context context,
3730                          krb5_crypto crypto,
3731                          unsigned usage,
3732                          krb5_crypto_iov *data,
3733                          unsigned int num_data,
3734                          krb5_cksumtype *type)
3735 {
3736     struct encryption_type *et = crypto->et;
3737     Checksum cksum;
3738     krb5_crypto_iov *civ;
3739     krb5_error_code ret;
3740     int i;
3741     size_t len;
3742     char *p, *q;
3743
3744     if (num_data < 0) {
3745         krb5_clear_error_message(context);
3746         return KRB5_CRYPTO_INTERNAL;
3747     }
3748
3749     if(!derived_crypto(context, crypto)) {
3750         krb5_clear_error_message(context);
3751         return KRB5_CRYPTO_INTERNAL;
3752     }
3753
3754     civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
3755     if (civ == NULL)
3756         return KRB5_BAD_MSIZE;
3757
3758     len = 0;
3759     for (i = 0; i < num_data; i++) {
3760         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3761             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3762             continue;
3763         len += data[i].data.length;
3764     }
3765
3766     p = q = malloc(len);
3767
3768     for (i = 0; i < num_data; i++) {
3769         if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
3770             data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
3771             continue;
3772         memcpy(q, data[i].data.data, data[i].data.length);
3773         q += data[i].data.length;
3774     }
3775
3776     cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
3777     cksum.checksum.length = civ->data.length;
3778     cksum.checksum.data = civ->data.data;
3779
3780     ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
3781     free(p);
3782
3783     if (ret == 0 && type)
3784         *type = cksum.cksumtype;
3785
3786     return ret;
3787 }
3788
3789
3790 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3791 krb5_crypto_length(krb5_context context,
3792                    krb5_crypto crypto,
3793                    int type,
3794                    size_t *len)
3795 {
3796     if (!derived_crypto(context, crypto)) {
3797         krb5_set_error_message(context, EINVAL, "not a derived crypto");
3798         return EINVAL;
3799     }
3800         
3801     switch(type) {
3802     case KRB5_CRYPTO_TYPE_EMPTY:
3803         *len = 0;
3804         return 0;
3805     case KRB5_CRYPTO_TYPE_HEADER:
3806         *len = crypto->et->blocksize;
3807         return 0;
3808     case KRB5_CRYPTO_TYPE_DATA:
3809     case KRB5_CRYPTO_TYPE_SIGN_ONLY:
3810         /* len must already been filled in */
3811         return 0;
3812     case KRB5_CRYPTO_TYPE_PADDING:
3813         if (crypto->et->padsize > 1)
3814             *len = crypto->et->padsize;
3815         else
3816             *len = 0;
3817         return 0;
3818     case KRB5_CRYPTO_TYPE_TRAILER:
3819         *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
3820         return 0;
3821     case KRB5_CRYPTO_TYPE_CHECKSUM:
3822         if (crypto->et->keyed_checksum)
3823             *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
3824         else
3825             *len = CHECKSUMSIZE(crypto->et->checksum);
3826         return 0;
3827     }
3828     krb5_set_error_message(context, EINVAL,
3829                            "%d not a supported type", type);
3830     return EINVAL;
3831 }
3832
3833
3834 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3835 krb5_crypto_length_iov(krb5_context context,
3836                        krb5_crypto crypto,
3837                        krb5_crypto_iov *data,
3838                        unsigned int num_data)
3839 {
3840     krb5_error_code ret;
3841     int i;
3842
3843     for (i = 0; i < num_data; i++) {
3844         ret = krb5_crypto_length(context, crypto,
3845                                  data[i].flags,
3846                                  &data[i].data.length);
3847         if (ret)
3848             return ret;
3849     }
3850     return 0;
3851 }
3852
3853
3854 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3855 krb5_encrypt_ivec(krb5_context context,
3856                   krb5_crypto crypto,
3857                   unsigned usage,
3858                   const void *data,
3859                   size_t len,
3860                   krb5_data *result,
3861                   void *ivec)
3862 {
3863     if(derived_crypto(context, crypto))
3864         return encrypt_internal_derived(context, crypto, usage,
3865                                         data, len, result, ivec);
3866     else if (special_crypto(context, crypto))
3867         return encrypt_internal_special (context, crypto, usage,
3868                                          data, len, result, ivec);
3869     else
3870         return encrypt_internal(context, crypto, data, len, result, ivec);
3871 }
3872
3873 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3874 krb5_encrypt(krb5_context context,
3875              krb5_crypto crypto,
3876              unsigned usage,
3877              const void *data,
3878              size_t len,
3879              krb5_data *result)
3880 {
3881     return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
3882 }
3883
3884 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3885 krb5_encrypt_EncryptedData(krb5_context context,
3886                            krb5_crypto crypto,
3887                            unsigned usage,
3888                            void *data,
3889                            size_t len,
3890                            int kvno,
3891                            EncryptedData *result)
3892 {
3893     result->etype = CRYPTO_ETYPE(crypto);
3894     if(kvno){
3895         ALLOC(result->kvno, 1);
3896         *result->kvno = kvno;
3897     }else
3898         result->kvno = NULL;
3899     return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
3900 }
3901
3902 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3903 krb5_decrypt_ivec(krb5_context context,
3904                   krb5_crypto crypto,
3905                   unsigned usage,
3906                   void *data,
3907                   size_t len,
3908                   krb5_data *result,
3909                   void *ivec)
3910 {
3911     if(derived_crypto(context, crypto))
3912         return decrypt_internal_derived(context, crypto, usage,
3913                                         data, len, result, ivec);
3914     else if (special_crypto (context, crypto))
3915         return decrypt_internal_special(context, crypto, usage,
3916                                         data, len, result, ivec);
3917     else
3918         return decrypt_internal(context, crypto, data, len, result, ivec);
3919 }
3920
3921 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3922 krb5_decrypt(krb5_context context,
3923              krb5_crypto crypto,
3924              unsigned usage,
3925              void *data,
3926              size_t len,
3927              krb5_data *result)
3928 {
3929     return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
3930                               NULL);
3931 }
3932
3933 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3934 krb5_decrypt_EncryptedData(krb5_context context,
3935                            krb5_crypto crypto,
3936                            unsigned usage,
3937                            const EncryptedData *e,
3938                            krb5_data *result)
3939 {
3940     return krb5_decrypt(context, crypto, usage,
3941                         e->cipher.data, e->cipher.length, result);
3942 }
3943
3944 /************************************************************
3945  *                                                          *
3946  ************************************************************/
3947
3948 #define ENTROPY_NEEDED 128
3949
3950 static int
3951 seed_something(void)
3952 {
3953     char buf[1024], seedfile[256];
3954
3955     /* If there is a seed file, load it. But such a file cannot be trusted,
3956        so use 0 for the entropy estimate */
3957     if (RAND_file_name(seedfile, sizeof(seedfile))) {
3958         int fd;
3959         fd = open(seedfile, O_RDONLY | O_BINARY | O_CLOEXEC);
3960         if (fd >= 0) {
3961             ssize_t ret;
3962             rk_cloexec(fd);
3963             ret = read(fd, buf, sizeof(buf));
3964             if (ret > 0)
3965                 RAND_add(buf, ret, 0.0);
3966             close(fd);
3967         } else
3968             seedfile[0] = '\0';
3969     } else
3970         seedfile[0] = '\0';
3971
3972     /* Calling RAND_status() will try to use /dev/urandom if it exists so
3973        we do not have to deal with it. */
3974     if (RAND_status() != 1) {
3975 #ifndef _WIN32
3976         krb5_context context;
3977         const char *p;
3978
3979         /* Try using egd */
3980         if (!krb5_init_context(&context)) {
3981             p = krb5_config_get_string(context, NULL, "libdefaults",
3982                                        "egd_socket", NULL);
3983             if (p != NULL)
3984                 RAND_egd_bytes(p, ENTROPY_NEEDED);
3985             krb5_free_context(context);
3986         }
3987 #else
3988         /* TODO: Once a Windows CryptoAPI RAND method is defined, we
3989            can use that and failover to another method. */
3990 #endif
3991     }
3992
3993     if (RAND_status() == 1)     {
3994         /* Update the seed file */
3995         if (seedfile[0])
3996             RAND_write_file(seedfile);
3997
3998         return 0;
3999     } else
4000         return -1;
4001 }
4002
4003 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
4004 krb5_generate_random_block(void *buf, size_t len)
4005 {
4006     static int rng_initialized = 0;
4007
4008     HEIMDAL_MUTEX_lock(&crypto_mutex);
4009     if (!rng_initialized) {
4010         if (seed_something())
4011             krb5_abortx(NULL, "Fatal: could not seed the "
4012                         "random number generator");
4013         
4014         rng_initialized = 1;
4015     }
4016     HEIMDAL_MUTEX_unlock(&crypto_mutex);
4017     if (RAND_bytes(buf, len) <= 0)
4018         krb5_abortx(NULL, "Failed to generate random block");
4019 }
4020
4021 static krb5_error_code
4022 derive_key(krb5_context context,
4023            struct encryption_type *et,
4024            struct key_data *key,
4025            const void *constant,
4026            size_t len)
4027 {
4028     unsigned char *k = NULL;
4029     unsigned int nblocks = 0, i;
4030     krb5_error_code ret = 0;
4031     struct key_type *kt = et->keytype;
4032
4033     ret = _key_schedule(context, key);
4034     if(ret)
4035         return ret;
4036     if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
4037         nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
4038         k = malloc(nblocks * et->blocksize);
4039         if(k == NULL) {
4040             ret = ENOMEM;
4041             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4042             goto out;
4043         }
4044         ret = _krb5_n_fold(constant, len, k, et->blocksize);
4045         if (ret) {
4046             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4047             goto out;
4048         }
4049
4050         for(i = 0; i < nblocks; i++) {
4051             if(i > 0)
4052                 memcpy(k + i * et->blocksize,
4053                        k + (i - 1) * et->blocksize,
4054                        et->blocksize);
4055             (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
4056                            1, 0, NULL);
4057         }
4058     } else {
4059         /* this case is probably broken, but won't be run anyway */
4060         void *c = malloc(len);
4061         size_t res_len = (kt->bits + 7) / 8;
4062
4063         if(len != 0 && c == NULL) {
4064             ret = ENOMEM;
4065             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4066             goto out;
4067         }
4068         memcpy(c, constant, len);
4069         (*et->encrypt)(context, key, c, len, 1, 0, NULL);
4070         k = malloc(res_len);
4071         if(res_len != 0 && k == NULL) {
4072             free(c);
4073             ret = ENOMEM;
4074             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4075             goto out;
4076         }
4077         ret = _krb5_n_fold(c, len, k, res_len);
4078         free(c);
4079         if (ret) {
4080             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4081             goto out;
4082         }
4083     }
4084
4085     /* XXX keytype dependent post-processing */
4086     switch(kt->type) {
4087     case KEYTYPE_DES3:
4088         DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
4089         break;
4090     case KEYTYPE_AES128:
4091     case KEYTYPE_AES256:
4092         memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
4093         break;
4094     default:
4095         ret = KRB5_CRYPTO_INTERNAL;
4096         krb5_set_error_message(context, ret,
4097                                N_("derive_key() called with unknown keytype (%u)", ""),
4098                                kt->type);
4099         break;
4100     }
4101  out:
4102     if (key->schedule) {
4103         free_key_schedule(context, key, et);
4104         key->schedule = NULL;
4105     }
4106     if (k) {
4107         memset(k, 0, nblocks * et->blocksize);
4108         free(k);
4109     }
4110     return ret;
4111 }
4112
4113 static struct key_data *
4114 _new_derived_key(krb5_crypto crypto, unsigned usage)
4115 {
4116     struct key_usage *d = crypto->key_usage;
4117     d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
4118     if(d == NULL)
4119         return NULL;
4120     crypto->key_usage = d;
4121     d += crypto->num_key_usage++;
4122     memset(d, 0, sizeof(*d));
4123     d->usage = usage;
4124     return &d->key;
4125 }
4126
4127 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4128 krb5_derive_key(krb5_context context,
4129                 const krb5_keyblock *key,
4130                 krb5_enctype etype,
4131                 const void *constant,
4132                 size_t constant_len,
4133                 krb5_keyblock **derived_key)
4134 {
4135     krb5_error_code ret;
4136     struct encryption_type *et;
4137     struct key_data d;
4138
4139     *derived_key = NULL;
4140
4141     et = _find_enctype (etype);
4142     if (et == NULL) {
4143         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4144                                N_("encryption type %d not supported", ""),
4145                                etype);
4146         return KRB5_PROG_ETYPE_NOSUPP;
4147     }
4148
4149     ret = krb5_copy_keyblock(context, key, &d.key);
4150     if (ret)
4151         return ret;
4152
4153     d.schedule = NULL;
4154     ret = derive_key(context, et, &d, constant, constant_len);
4155     if (ret == 0)
4156         ret = krb5_copy_keyblock(context, d.key, derived_key);
4157     free_key_data(context, &d, et);
4158     return ret;
4159 }
4160
4161 static krb5_error_code
4162 _get_derived_key(krb5_context context,
4163                  krb5_crypto crypto,
4164                  unsigned usage,
4165                  struct key_data **key)
4166 {
4167     int i;
4168     struct key_data *d;
4169     unsigned char constant[5];
4170
4171     for(i = 0; i < crypto->num_key_usage; i++)
4172         if(crypto->key_usage[i].usage == usage) {
4173             *key = &crypto->key_usage[i].key;
4174             return 0;
4175         }
4176     d = _new_derived_key(crypto, usage);
4177     if(d == NULL) {
4178         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4179         return ENOMEM;
4180     }
4181     krb5_copy_keyblock(context, crypto->key.key, &d->key);
4182     _krb5_put_int(constant, usage, 5);
4183     derive_key(context, crypto->et, d, constant, sizeof(constant));
4184     *key = d;
4185     return 0;
4186 }
4187
4188 /**
4189  * Create a crypto context used for all encryption and signature
4190  * operation. The encryption type to use is taken from the key, but
4191  * can be overridden with the enctype parameter.  This can be useful
4192  * for encryptions types which is compatiable (DES for example).
4193  *
4194  * To free the crypto context, use krb5_crypto_destroy().
4195  *
4196  * @param context Kerberos context
4197  * @param key the key block information with all key data
4198  * @param etype the encryption type
4199  * @param crypto the resulting crypto context
4200  *
4201  * @return Return an error code or 0.
4202  *
4203  * @ingroup krb5_crypto
4204  */
4205
4206 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4207 krb5_crypto_init(krb5_context context,
4208                  const krb5_keyblock *key,
4209                  krb5_enctype etype,
4210                  krb5_crypto *crypto)
4211 {
4212     krb5_error_code ret;
4213     ALLOC(*crypto, 1);
4214     if(*crypto == NULL) {
4215         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4216         return ENOMEM;
4217     }
4218     if(etype == ETYPE_NULL)
4219         etype = key->keytype;
4220     (*crypto)->et = _find_enctype(etype);
4221     if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
4222         free(*crypto);
4223         *crypto = NULL;
4224         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
4225                                 N_("encryption type %d not supported", ""),
4226                                 etype);
4227         return KRB5_PROG_ETYPE_NOSUPP;
4228     }
4229     if((*crypto)->et->keytype->size != key->keyvalue.length) {
4230         free(*crypto);
4231         *crypto = NULL;
4232         krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
4233                                 "encryption key has bad length");
4234         return KRB5_BAD_KEYSIZE;
4235     }
4236     ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
4237     if(ret) {
4238         free(*crypto);
4239         *crypto = NULL;
4240         return ret;
4241     }
4242     (*crypto)->key.schedule = NULL;
4243     (*crypto)->num_key_usage = 0;
4244     (*crypto)->key_usage = NULL;
4245     return 0;
4246 }
4247
4248 static void
4249 free_key_schedule(krb5_context context,
4250                   struct key_data *key,
4251                   struct encryption_type *et)
4252 {
4253     if (et->keytype->cleanup)
4254         (*et->keytype->cleanup)(context, key);
4255     memset(key->schedule->data, 0, key->schedule->length);
4256     krb5_free_data(context, key->schedule);
4257 }
4258
4259 static void
4260 free_key_data(krb5_context context, struct key_data *key,
4261               struct encryption_type *et)
4262 {
4263     krb5_free_keyblock(context, key->key);
4264     if(key->schedule) {
4265         free_key_schedule(context, key, et);
4266         key->schedule = NULL;
4267     }
4268 }
4269
4270 static void
4271 free_key_usage(krb5_context context, struct key_usage *ku,
4272                struct encryption_type *et)
4273 {
4274     free_key_data(context, &ku->key, et);
4275 }
4276
4277 /**
4278  * Free a crypto context created by krb5_crypto_init().
4279  *
4280  * @param context Kerberos context
4281  * @param crypto crypto context to free
4282  *
4283  * @return Return an error code or 0.
4284  *
4285  * @ingroup krb5_crypto
4286  */
4287
4288 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4289 krb5_crypto_destroy(krb5_context context,
4290                     krb5_crypto crypto)
4291 {
4292     int i;
4293
4294     for(i = 0; i < crypto->num_key_usage; i++)
4295         free_key_usage(context, &crypto->key_usage[i], crypto->et);
4296     free(crypto->key_usage);
4297     free_key_data(context, &crypto->key, crypto->et);
4298     free (crypto);
4299     return 0;
4300 }
4301
4302 /**
4303  * Return the blocksize used algorithm referenced by the crypto context
4304  * 
4305  * @param context Kerberos context
4306  * @param crypto crypto context to query
4307  * @param blocksize the resulting blocksize
4308  *
4309  * @return Return an error code or 0.
4310  *
4311  * @ingroup krb5_crypto
4312  */
4313
4314 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4315 krb5_crypto_getblocksize(krb5_context context,
4316                          krb5_crypto crypto,
4317                          size_t *blocksize)
4318 {
4319     *blocksize = crypto->et->blocksize;
4320     return 0;
4321 }
4322
4323 /**
4324  * Return the encryption type used by the crypto context
4325  * 
4326  * @param context Kerberos context
4327  * @param crypto crypto context to query
4328  * @param enctype the resulting encryption type
4329  *
4330  * @return Return an error code or 0.
4331  *
4332  * @ingroup krb5_crypto
4333  */
4334
4335 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4336 krb5_crypto_getenctype(krb5_context context,
4337                        krb5_crypto crypto,
4338                        krb5_enctype *enctype)
4339 {
4340     *enctype = crypto->et->type;
4341     return 0;
4342 }
4343
4344 /**
4345  * Return the padding size used by the crypto context
4346  * 
4347  * @param context Kerberos context
4348  * @param crypto crypto context to query
4349  * @param padsize the return padding size
4350  *
4351  * @return Return an error code or 0.
4352  *
4353  * @ingroup krb5_crypto
4354  */
4355
4356 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4357 krb5_crypto_getpadsize(krb5_context context,
4358                        krb5_crypto crypto,
4359                        size_t *padsize)
4360 {
4361     *padsize = crypto->et->padsize;
4362     return 0;
4363 }
4364
4365 /**
4366  * Return the confounder size used by the crypto context
4367  * 
4368  * @param context Kerberos context
4369  * @param crypto crypto context to query
4370  * @param confoundersize the returned confounder size
4371  *
4372  * @return Return an error code or 0.
4373  *
4374  * @ingroup krb5_crypto
4375  */
4376
4377 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4378 krb5_crypto_getconfoundersize(krb5_context context,
4379                               krb5_crypto crypto,
4380                               size_t *confoundersize)
4381 {
4382     *confoundersize = crypto->et->confoundersize;
4383     return 0;
4384 }
4385
4386
4387 /**
4388  * Disable encryption type
4389  *
4390  * @param context Kerberos 5 context
4391  * @param enctype encryption type to disable
4392  *
4393  * @return Return an error code or 0.
4394  *
4395  * @ingroup krb5_crypto
4396  */
4397
4398 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4399 krb5_enctype_disable(krb5_context context,
4400                      krb5_enctype enctype)
4401 {
4402     struct encryption_type *et = _find_enctype(enctype);
4403     if(et == NULL) {
4404         if (context)
4405             krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
4406                                     N_("encryption type %d not supported", ""),
4407                                     enctype);
4408         return KRB5_PROG_ETYPE_NOSUPP;
4409     }
4410     et->flags |= F_DISABLED;
4411     return 0;
4412 }
4413
4414 /**
4415  * Enable encryption type
4416  *
4417  * @param context Kerberos 5 context
4418  * @param enctype encryption type to enable
4419  *
4420  * @return Return an error code or 0.
4421  *
4422  * @ingroup krb5_crypto
4423  */
4424
4425 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4426 krb5_enctype_enable(krb5_context context,
4427                     krb5_enctype enctype)
4428 {
4429     struct encryption_type *et = _find_enctype(enctype);
4430     if(et == NULL) {
4431         if (context)
4432             krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
4433                                     N_("encryption type %d not supported", ""),
4434                                     enctype);
4435         return KRB5_PROG_ETYPE_NOSUPP;
4436     }
4437     et->flags &= ~F_DISABLED;
4438     return 0;
4439 }
4440
4441 /**
4442  * Enable or disable all weak encryption types
4443  *
4444  * @param context Kerberos 5 context
4445  * @param enable true to enable, false to disable
4446  *
4447  * @return Return an error code or 0.
4448  *
4449  * @ingroup krb5_crypto
4450  */
4451
4452 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4453 krb5_allow_weak_crypto(krb5_context context,
4454                        krb5_boolean enable)
4455 {
4456     int i;
4457
4458     for(i = 0; i < num_etypes; i++)
4459         if(etypes[i]->flags & F_WEAK) {
4460             if(enable)
4461                 etypes[i]->flags &= ~F_DISABLED;
4462             else
4463                 etypes[i]->flags |= F_DISABLED;
4464         }
4465     return 0;
4466 }
4467
4468
4469 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4470 krb5_string_to_key_derived(krb5_context context,
4471                            const void *str,
4472                            size_t len,
4473                            krb5_enctype etype,
4474                            krb5_keyblock *key)
4475 {
4476     struct encryption_type *et = _find_enctype(etype);
4477     krb5_error_code ret;
4478     struct key_data kd;
4479     size_t keylen;
4480     u_char *tmp;
4481
4482     if(et == NULL) {
4483         krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
4484                                 N_("encryption type %d not supported", ""),
4485                                 etype);
4486         return KRB5_PROG_ETYPE_NOSUPP;
4487     }
4488     keylen = et->keytype->bits / 8;
4489
4490     ALLOC(kd.key, 1);
4491     if(kd.key == NULL) {
4492         krb5_set_error_message (context, ENOMEM,
4493                                 N_("malloc: out of memory", ""));
4494         return ENOMEM;
4495     }
4496     ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
4497     if(ret) {
4498         free(kd.key);
4499         return ret;
4500     }
4501     kd.key->keytype = etype;
4502     tmp = malloc (keylen);
4503     if(tmp == NULL) {
4504         krb5_free_keyblock(context, kd.key);
4505         krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
4506         return ENOMEM;
4507     }
4508     ret = _krb5_n_fold(str, len, tmp, keylen);
4509     if (ret) {
4510         free(tmp);
4511         krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
4512         return ret;
4513     }
4514     kd.schedule = NULL;
4515     DES3_random_to_key(context, kd.key, tmp, keylen);
4516     memset(tmp, 0, keylen);
4517     free(tmp);
4518     ret = derive_key(context,
4519                      et,
4520                      &kd,
4521                      "kerberos", /* XXX well known constant */
4522                      strlen("kerberos"));
4523     if (ret) {
4524         free_key_data(context, &kd, et);
4525         return ret;
4526     }
4527     ret = krb5_copy_keyblock_contents(context, kd.key, key);
4528     free_key_data(context, &kd, et);
4529     return ret;
4530 }
4531
4532 static size_t
4533 wrapped_length (krb5_context context,
4534                 krb5_crypto  crypto,
4535                 size_t       data_len)
4536 {
4537     struct encryption_type *et = crypto->et;
4538     size_t padsize = et->padsize;
4539     size_t checksumsize = CHECKSUMSIZE(et->checksum);
4540     size_t res;
4541
4542     res =  et->confoundersize + checksumsize + data_len;
4543     res =  (res + padsize - 1) / padsize * padsize;
4544     return res;
4545 }
4546
4547 static size_t
4548 wrapped_length_dervied (krb5_context context,
4549                         krb5_crypto  crypto,
4550                         size_t       data_len)
4551 {
4552     struct encryption_type *et = crypto->et;
4553     size_t padsize = et->padsize;
4554     size_t res;
4555
4556     res =  et->confoundersize + data_len;
4557     res =  (res + padsize - 1) / padsize * padsize;
4558     if (et->keyed_checksum)
4559         res += et->keyed_checksum->checksumsize;
4560     else
4561         res += et->checksum->checksumsize;
4562     return res;
4563 }
4564
4565 /*
4566  * Return the size of an encrypted packet of length `data_len'
4567  */
4568
4569 size_t
4570 krb5_get_wrapped_length (krb5_context context,
4571                          krb5_crypto  crypto,
4572                          size_t       data_len)
4573 {
4574     if (derived_crypto (context, crypto))
4575         return wrapped_length_dervied (context, crypto, data_len);
4576     else
4577         return wrapped_length (context, crypto, data_len);
4578 }
4579
4580 /*
4581  * Return the size of an encrypted packet of length `data_len'
4582  */
4583
4584 static size_t
4585 crypto_overhead (krb5_context context,
4586                  krb5_crypto  crypto)
4587 {
4588     struct encryption_type *et = crypto->et;
4589     size_t res;
4590
4591     res = CHECKSUMSIZE(et->checksum);
4592     res += et->confoundersize;
4593     if (et->padsize > 1)
4594         res += et->padsize;
4595     return res;
4596 }
4597
4598 static size_t
4599 crypto_overhead_dervied (krb5_context context,
4600                          krb5_crypto  crypto)
4601 {
4602     struct encryption_type *et = crypto->et;
4603     size_t res;
4604
4605     if (et->keyed_checksum)
4606         res = CHECKSUMSIZE(et->keyed_checksum);
4607     else
4608         res = CHECKSUMSIZE(et->checksum);
4609     res += et->confoundersize;
4610     if (et->padsize > 1)
4611         res += et->padsize;
4612     return res;
4613 }
4614
4615 size_t
4616 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
4617 {
4618     if (derived_crypto (context, crypto))
4619         return crypto_overhead_dervied (context, crypto);
4620     else
4621         return crypto_overhead (context, crypto);
4622 }
4623
4624 /**
4625  * Converts the random bytestring to a protocol key according to
4626  * Kerberos crypto frame work. It may be assumed that all the bits of
4627  * the input string are equally random, even though the entropy
4628  * present in the random source may be limited.
4629  *
4630  * @param context Kerberos 5 context
4631  * @param type the enctype resulting key will be of
4632  * @param data input random data to convert to a key
4633  * @param size size of input random data, at least krb5_enctype_keysize() long
4634  * @param key key, output key, free with krb5_free_keyblock_contents()
4635  *
4636  * @return Return an error code or 0.
4637  *
4638  * @ingroup krb5_crypto
4639  */
4640
4641 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4642 krb5_random_to_key(krb5_context context,
4643                    krb5_enctype type,
4644                    const void *data,
4645                    size_t size,
4646                    krb5_keyblock *key)
4647 {
4648     krb5_error_code ret;
4649     struct encryption_type *et = _find_enctype(type);
4650     if(et == NULL) {
4651         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4652                                N_("encryption type %d not supported", ""),
4653                                type);
4654         return KRB5_PROG_ETYPE_NOSUPP;
4655     }
4656     if ((et->keytype->bits + 7) / 8 > size) {
4657         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4658                                N_("encryption key %s needs %d bytes "
4659                                   "of random to make an encryption key "
4660                                   "out of it", ""),
4661                                et->name, (int)et->keytype->size);
4662         return KRB5_PROG_ETYPE_NOSUPP;
4663     }
4664     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
4665     if(ret)
4666         return ret;
4667     key->keytype = type;
4668     if (et->keytype->random_to_key)
4669         (*et->keytype->random_to_key)(context, key, data, size);
4670     else
4671         memcpy(key->keyvalue.data, data, et->keytype->size);
4672
4673     return 0;
4674 }
4675
4676 krb5_error_code
4677 _krb5_pk_octetstring2key(krb5_context context,
4678                          krb5_enctype type,
4679                          const void *dhdata,
4680                          size_t dhsize,
4681                          const heim_octet_string *c_n,
4682                          const heim_octet_string *k_n,
4683                          krb5_keyblock *key)
4684 {
4685     struct encryption_type *et = _find_enctype(type);
4686     krb5_error_code ret;
4687     size_t keylen, offset;
4688     void *keydata;
4689     unsigned char counter;
4690     unsigned char shaoutput[SHA_DIGEST_LENGTH];
4691     EVP_MD_CTX *m;
4692
4693     if(et == NULL) {
4694         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4695                                N_("encryption type %d not supported", ""),
4696                                type);
4697         return KRB5_PROG_ETYPE_NOSUPP;
4698     }
4699     keylen = (et->keytype->bits + 7) / 8;
4700
4701     keydata = malloc(keylen);
4702     if (keydata == NULL) {
4703         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4704         return ENOMEM;
4705     }
4706
4707     m = EVP_MD_CTX_create();
4708     if (m == NULL) {
4709         free(keydata);
4710         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4711         return ENOMEM;
4712     }
4713
4714     counter = 0;
4715     offset = 0;
4716     do {
4717         
4718         EVP_DigestInit_ex(m, EVP_sha1(), NULL);
4719         EVP_DigestUpdate(m, &counter, 1);
4720         EVP_DigestUpdate(m, dhdata, dhsize);
4721
4722         if (c_n)
4723             EVP_DigestUpdate(m, c_n->data, c_n->length);
4724         if (k_n)
4725             EVP_DigestUpdate(m, k_n->data, k_n->length);
4726
4727         EVP_DigestFinal_ex(m, shaoutput, NULL);
4728
4729         memcpy((unsigned char *)keydata + offset,
4730                shaoutput,
4731                min(keylen - offset, sizeof(shaoutput)));
4732
4733         offset += sizeof(shaoutput);
4734         counter++;
4735     } while(offset < keylen);
4736     memset(shaoutput, 0, sizeof(shaoutput));
4737
4738     EVP_MD_CTX_destroy(m);
4739
4740     ret = krb5_random_to_key(context, type, keydata, keylen, key);
4741     memset(keydata, 0, sizeof(keylen));
4742     free(keydata);
4743     return ret;
4744 }
4745
4746 static krb5_error_code
4747 encode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data)
4748 {
4749     KRB5PrincipalName pn;
4750     krb5_error_code ret;
4751     size_t size;
4752
4753     pn.principalName = p->name;
4754     pn.realm = p->realm;
4755
4756     ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length,
4757                        &pn, &size, ret);
4758     if (ret) {
4759         krb5_data_zero(data);
4760         krb5_set_error_message(context, ret,
4761                                N_("Failed to encode KRB5PrincipalName", ""));
4762         return ret;
4763     }
4764     if (data->length != size)
4765         krb5_abortx(context, "asn1 compiler internal error");
4766     return 0;
4767 }
4768
4769 static krb5_error_code
4770 encode_otherinfo(krb5_context context,
4771                  const AlgorithmIdentifier *ai,
4772                  krb5_const_principal client,
4773                  krb5_const_principal server,
4774                  krb5_enctype enctype,
4775                  const krb5_data *as_req,
4776                  const krb5_data *pk_as_rep,
4777                  const Ticket *ticket,
4778                  krb5_data *other)
4779 {
4780     PkinitSP80056AOtherInfo otherinfo;
4781     PkinitSuppPubInfo pubinfo;
4782     krb5_error_code ret;
4783     krb5_data pub;
4784     size_t size;
4785
4786     krb5_data_zero(other);
4787     memset(&otherinfo, 0, sizeof(otherinfo));
4788     memset(&pubinfo, 0, sizeof(pubinfo));
4789
4790     pubinfo.enctype = enctype;
4791     pubinfo.as_REQ = *as_req;
4792     pubinfo.pk_as_rep = *pk_as_rep;
4793     pubinfo.ticket = *ticket;
4794     ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length,
4795                        &pubinfo, &size, ret);
4796     if (ret) {
4797         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4798         return ret;
4799     }
4800     if (pub.length != size)
4801         krb5_abortx(context, "asn1 compiler internal error");
4802
4803     ret = encode_uvinfo(context, client, &otherinfo.partyUInfo);
4804     if (ret) {
4805         free(pub.data);
4806         return ret;
4807     }
4808     ret = encode_uvinfo(context, server, &otherinfo.partyVInfo);
4809     if (ret) {
4810         free(otherinfo.partyUInfo.data);
4811         free(pub.data);
4812         return ret;
4813     }
4814
4815     otherinfo.algorithmID = *ai;
4816     otherinfo.suppPubInfo = &pub;
4817
4818     ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length,
4819                        &otherinfo, &size, ret);
4820     free(otherinfo.partyUInfo.data);
4821     free(otherinfo.partyVInfo.data);
4822     free(pub.data);
4823     if (ret) {
4824         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
4825         return ret;
4826     }
4827     if (other->length != size)
4828         krb5_abortx(context, "asn1 compiler internal error");
4829
4830     return 0;
4831 }
4832
4833 krb5_error_code
4834 _krb5_pk_kdf(krb5_context context,
4835              const struct AlgorithmIdentifier *ai,
4836              const void *dhdata,
4837              size_t dhsize,
4838              krb5_const_principal client,
4839              krb5_const_principal server,
4840              krb5_enctype enctype,
4841              const krb5_data *as_req,
4842              const krb5_data *pk_as_rep,
4843              const Ticket *ticket,
4844              krb5_keyblock *key)
4845 {
4846     struct encryption_type *et;
4847     krb5_error_code ret;
4848     krb5_data other;
4849     size_t keylen, offset;
4850     uint32_t counter;
4851     unsigned char *keydata;
4852     unsigned char shaoutput[SHA_DIGEST_LENGTH];
4853     EVP_MD_CTX *m;
4854
4855     if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) != 0) {
4856         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4857                                N_("KDF not supported", ""));
4858         return KRB5_PROG_ETYPE_NOSUPP;
4859     }
4860     if (ai->parameters != NULL &&
4861         (ai->parameters->length != 2 ||
4862          memcmp(ai->parameters->data, "\x05\x00", 2) != 0))
4863         {
4864             krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4865                                    N_("kdf params not NULL or the NULL-type",
4866                                       ""));
4867             return KRB5_PROG_ETYPE_NOSUPP;
4868         }
4869
4870     et = _find_enctype(enctype);
4871     if(et == NULL) {
4872         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4873                                N_("encryption type %d not supported", ""),
4874                                enctype);
4875         return KRB5_PROG_ETYPE_NOSUPP;
4876     }
4877     keylen = (et->keytype->bits + 7) / 8;
4878
4879     keydata = malloc(keylen);
4880     if (keydata == NULL) {
4881         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4882         return ENOMEM;
4883     }
4884
4885     ret = encode_otherinfo(context, ai, client, server,
4886                            enctype, as_req, pk_as_rep, ticket, &other);
4887     if (ret) {
4888         free(keydata);
4889         return ret;
4890     }
4891
4892     m = EVP_MD_CTX_create();
4893     if (m == NULL) {
4894         free(keydata);
4895         free(other.data);
4896         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
4897         return ENOMEM;
4898     }
4899
4900     offset = 0;
4901     counter = 1;
4902     do {
4903         unsigned char cdata[4];
4904         
4905         EVP_DigestInit_ex(m, EVP_sha1(), NULL);
4906         _krb5_put_int(cdata, counter, 4);
4907         EVP_DigestUpdate(m, cdata, 4);
4908         EVP_DigestUpdate(m, dhdata, dhsize);
4909         EVP_DigestUpdate(m, other.data, other.length);
4910
4911         EVP_DigestFinal_ex(m, shaoutput, NULL);
4912
4913         memcpy((unsigned char *)keydata + offset,
4914                shaoutput,
4915                min(keylen - offset, sizeof(shaoutput)));
4916
4917         offset += sizeof(shaoutput);
4918         counter++;
4919     } while(offset < keylen);
4920     memset(shaoutput, 0, sizeof(shaoutput));
4921
4922     EVP_MD_CTX_destroy(m);
4923     free(other.data);
4924
4925     ret = krb5_random_to_key(context, enctype, keydata, keylen, key);
4926     memset(keydata, 0, sizeof(keylen));
4927     free(keydata);
4928
4929     return ret;
4930 }
4931
4932
4933 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4934 krb5_crypto_prf_length(krb5_context context,
4935                        krb5_enctype type,
4936                        size_t *length)
4937 {
4938     struct encryption_type *et = _find_enctype(type);
4939
4940     if(et == NULL || et->prf_length == 0) {
4941         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4942                                N_("encryption type %d not supported", ""),
4943                                type);
4944         return KRB5_PROG_ETYPE_NOSUPP;
4945     }
4946
4947     *length = et->prf_length;
4948     return 0;
4949 }
4950
4951 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4952 krb5_crypto_prf(krb5_context context,
4953                 const krb5_crypto crypto,
4954                 const krb5_data *input,
4955                 krb5_data *output)
4956 {
4957     struct encryption_type *et = crypto->et;
4958
4959     krb5_data_zero(output);
4960
4961     if(et->prf == NULL) {
4962         krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
4963                                "kerberos prf for %s not supported",
4964                                et->name);
4965         return KRB5_PROG_ETYPE_NOSUPP;
4966     }
4967
4968     return (*et->prf)(context, crypto, input, output);
4969 }
4970
4971 static krb5_error_code
4972 krb5_crypto_prfplus(krb5_context context,
4973                     const krb5_crypto crypto,
4974                     const krb5_data *input,
4975                     size_t length,
4976                     krb5_data *output)
4977 {
4978     krb5_error_code ret;
4979     krb5_data input2;
4980     unsigned char i = 1;
4981     unsigned char *p;
4982
4983     krb5_data_zero(&input2);
4984     krb5_data_zero(output);
4985
4986     krb5_clear_error_message(context);
4987
4988     ret = krb5_data_alloc(output, length);
4989     if (ret) goto out;
4990     ret = krb5_data_alloc(&input2, input->length + 1);
4991     if (ret) goto out;
4992
4993     krb5_clear_error_message(context);
4994
4995     memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
4996
4997     p = output->data;
4998
4999     while (length) {
5000         krb5_data block;
5001
5002         ((unsigned char *)input2.data)[0] = i++;
5003
5004         ret = krb5_crypto_prf(context, crypto, &input2, &block);
5005         if (ret)
5006             goto out;
5007
5008         if (block.length < length) {
5009             memcpy(p, block.data, block.length);
5010             length -= block.length;
5011         } else {
5012             memcpy(p, block.data, length);
5013             length = 0;
5014         }
5015         p += block.length;
5016         krb5_data_free(&block);
5017     }
5018
5019  out:
5020     krb5_data_free(&input2);
5021     if (ret)
5022         krb5_data_free(output);
5023     return 0;
5024 }
5025
5026 /**
5027  * The FX-CF2 key derivation function, used in FAST and preauth framework.
5028  *
5029  * @param context Kerberos 5 context
5030  * @param crypto1 first key to combine
5031  * @param crypto2 second key to combine
5032  * @param pepper1 factor to combine with first key to garante uniqueness
5033  * @param pepper2 factor to combine with second key to garante uniqueness
5034  * @param enctype the encryption type of the resulting key
5035  * @param res allocated key, free with krb5_free_keyblock_contents()
5036  *
5037  * @return Return an error code or 0.
5038  *
5039  * @ingroup krb5_crypto
5040  */
5041
5042 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
5043 krb5_crypto_fx_cf2(krb5_context context,
5044                    const krb5_crypto crypto1,
5045                    const krb5_crypto crypto2,
5046                    krb5_data *pepper1,
5047                    krb5_data *pepper2,
5048                    krb5_enctype enctype,
5049                    krb5_keyblock *res)
5050 {
5051     krb5_error_code ret;
5052     krb5_data os1, os2;
5053     size_t i, keysize;
5054
5055     memset(res, 0, sizeof(*res));
5056
5057     ret = krb5_enctype_keysize(context, enctype, &keysize);
5058     if (ret)
5059         return ret;
5060
5061     ret = krb5_data_alloc(&res->keyvalue, keysize);
5062     if (ret)
5063         goto out;
5064     ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
5065     if (ret)
5066         goto out;
5067     ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
5068     if (ret)
5069         goto out;
5070
5071     res->keytype = enctype;
5072     {
5073         unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data;
5074         for (i = 0; i < keysize; i++)
5075             p3[i] = p1[i] ^ p2[i];
5076     }
5077  out:
5078     if (ret)
5079         krb5_data_free(&res->keyvalue);
5080     krb5_data_free(&os1);
5081     krb5_data_free(&os2);
5082
5083     return ret;
5084 }
5085
5086
5087
5088 #ifndef HEIMDAL_SMALLER
5089
5090 /**
5091  * Deprecated: keytypes doesn't exists, they are really enctypes.
5092  *
5093  * @ingroup krb5_deprecated
5094  */
5095
5096 KRB5_DEPRECATED
5097 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
5098 krb5_keytype_to_enctypes (krb5_context context,
5099                           krb5_keytype keytype,
5100                           unsigned *len,
5101                           krb5_enctype **val)
5102 {
5103     int i;
5104     unsigned n = 0;
5105     krb5_enctype *ret;
5106
5107     for (i = num_etypes - 1; i >= 0; --i) {
5108         if (etypes[i]->keytype->type == keytype
5109             && !(etypes[i]->flags & F_PSEUDO)
5110             && krb5_enctype_valid(context, etypes[i]->type) == 0)
5111             ++n;
5112     }
5113     if (n == 0) {
5114         krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
5115                                "Keytype have no mapping");
5116         return KRB5_PROG_KEYTYPE_NOSUPP;
5117     }
5118
5119     ret = malloc(n * sizeof(*ret));
5120     if (ret == NULL && n != 0) {
5121         krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
5122         return ENOMEM;
5123     }
5124     n = 0;
5125     for (i = num_etypes - 1; i >= 0; --i) {
5126         if (etypes[i]->keytype->type == keytype
5127             && !(etypes[i]->flags & F_PSEUDO)
5128             && krb5_enctype_valid(context, etypes[i]->type) == 0)
5129             ret[n++] = etypes[i]->type;
5130     }
5131     *len = n;
5132     *val = ret;
5133     return 0;
5134 }
5135
5136 /**
5137  * Deprecated: keytypes doesn't exists, they are really enctypes.
5138  *
5139  * @ingroup krb5_deprecated
5140  */
5141
5142 /* if two enctypes have compatible keys */
5143 KRB5_DEPRECATED
5144 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
5145 krb5_enctypes_compatible_keys(krb5_context context,
5146                               krb5_enctype etype1,
5147                               krb5_enctype etype2)
5148 {
5149     struct encryption_type *e1 = _find_enctype(etype1);
5150     struct encryption_type *e2 = _find_enctype(etype2);
5151     return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
5152 }
5153
5154 #endif /* HEIMDAL_SMALLER */