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