Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / heimdal / lib / krb5 / crypto.c
1 /*
2  * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "krb5_locl.h"
35 RCSID("$Id: crypto.c,v 1.66 2002/09/03 19:58:15 joda Exp $");
36 /* RCSID("$FreeBSD: src/crypto/heimdal/lib/krb5/crypto.c,v 1.2.2.4 2002/09/20 10:50:25 nectar Exp $"); */
37
38 #undef CRYPTO_DEBUG
39 #ifdef CRYPTO_DEBUG
40 static void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*);
41 #endif
42
43
44 struct key_data {
45     krb5_keyblock *key;
46     krb5_data *schedule;
47 };
48
49 struct key_usage {
50     unsigned usage;
51     struct key_data key;
52 };
53
54 struct krb5_crypto_data {
55     struct encryption_type *et;
56     struct key_data key;
57     int num_key_usage;
58     struct key_usage *key_usage;
59 };
60
61 #define CRYPTO_ETYPE(C) ((C)->et->type)
62
63 /* bits for `flags' below */
64 #define F_KEYED          1      /* checksum is keyed */
65 #define F_CPROOF         2      /* checksum is collision proof */
66 #define F_DERIVED        4      /* uses derived keys */
67 #define F_VARIANT        8      /* uses `variant' keys (6.4.3) */
68 #define F_PSEUDO        16      /* not a real protocol type */
69 #define F_SPECIAL       32      /* backwards */
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_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 #if 0
85     krb5_enctype best_etype;
86 #endif
87     void (*random_key)(krb5_context, krb5_keyblock*);
88     void (*schedule)(krb5_context, struct key_data *);
89     struct salt_type *string_to_key;
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     void (*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 confoundersize;
115     struct key_type *keytype;
116     struct checksum_type *checksum;
117     struct checksum_type *keyed_checksum;
118     unsigned flags;
119     krb5_error_code (*encrypt)(krb5_context context,
120                                struct key_data *key,
121                                void *data, size_t len,
122                                krb5_boolean encrypt,
123                                int usage,
124                                void *ivec);
125 };
126
127 #define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
128 #define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)
129 #define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)
130
131 static struct checksum_type *_find_checksum(krb5_cksumtype type);
132 static struct encryption_type *_find_enctype(krb5_enctype type);
133 static struct key_type *_find_keytype(krb5_keytype type);
134 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, 
135                                         unsigned, struct key_data**);
136 static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
137
138 /************************************************************
139  *                                                          *
140  ************************************************************/
141
142 static void
143 krb5_DES_random_key(krb5_context context,
144                krb5_keyblock *key)
145 {
146     des_cblock *k = key->keyvalue.data;
147     do {
148         krb5_generate_random_block(k, sizeof(des_cblock));
149         des_set_odd_parity(k);
150     } while(des_is_weak_key(k));
151 }
152
153 static void
154 krb5_DES_schedule(krb5_context context,
155              struct key_data *key)
156 {
157     des_set_key(key->key->keyvalue.data, key->schedule->data);
158 }
159
160 static void
161 DES_string_to_key_int(unsigned char *data, size_t length, des_cblock *key)
162 {
163     des_key_schedule schedule;
164     int i;
165     int reverse = 0;
166     unsigned char *p;
167
168     unsigned char swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 
169                              0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
170     memset(key, 0, 8);
171     
172     p = (unsigned char*)key;
173     for (i = 0; i < length; i++) {
174         unsigned char tmp = data[i];
175         if (!reverse)
176             *p++ ^= (tmp << 1);
177         else
178             *--p ^= (swap[tmp & 0xf] << 4) | swap[(tmp & 0xf0) >> 4];
179         if((i % 8) == 7)
180             reverse = !reverse;
181     }
182     des_set_odd_parity(key);
183     if(des_is_weak_key(key))
184         (*key)[7] ^= 0xF0;
185     des_set_key(key, schedule);
186     des_cbc_cksum((void*)data, key, length, schedule, key);
187     memset(schedule, 0, sizeof(schedule));
188     des_set_odd_parity(key);
189 }
190
191 static krb5_error_code
192 krb5_DES_string_to_key(krb5_context context,
193                   krb5_enctype enctype,
194                   krb5_data password,
195                   krb5_salt salt,
196                   krb5_keyblock *key)
197 {
198     unsigned char *s;
199     size_t len;
200     des_cblock tmp;
201
202     len = password.length + salt.saltvalue.length;
203     s = malloc(len);
204     if(len > 0 && s == NULL) {
205         krb5_set_error_string(context, "malloc: out of memory");
206         return ENOMEM;
207     }
208     memcpy(s, password.data, password.length);
209     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
210     DES_string_to_key_int(s, len, &tmp);
211     key->keytype = enctype;
212     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
213     memset(&tmp, 0, sizeof(tmp));
214     memset(s, 0, len);
215     free(s);
216     return 0;
217 }
218
219 /* This defines the Andrew string_to_key function.  It accepts a password
220  * string as input and converts its via a one-way encryption algorithm to a DES
221  * encryption key.  It is compatible with the original Andrew authentication
222  * service password database.
223  */
224
225 /*
226  * Short passwords, i.e 8 characters or less.
227  */
228 static void
229 krb5_DES_AFS3_CMU_string_to_key (krb5_data pw,
230                             krb5_data cell,
231                             des_cblock *key)
232 {
233     char  password[8+1];        /* crypt is limited to 8 chars anyway */
234     int   i;
235     
236     for(i = 0; i < 8; i++) {
237         char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^
238                  ((i < cell.length) ?
239                   tolower(((unsigned char*)cell.data)[i]) : 0);
240         password[i] = c ? c : 'X';
241     }
242     password[8] = '\0';
243
244     memcpy(key, crypt(password, "#~") + 2, sizeof(des_cblock));
245
246     /* parity is inserted into the LSB so left shift each byte up one
247        bit. This allows ascii characters with a zero MSB to retain as
248        much significance as possible. */
249     for (i = 0; i < sizeof(des_cblock); i++)
250         ((unsigned char*)key)[i] <<= 1;
251     des_set_odd_parity (key);
252 }
253
254 /*
255  * Long passwords, i.e 9 characters or more.
256  */
257 static void
258 krb5_DES_AFS3_Transarc_string_to_key (krb5_data pw,
259                                  krb5_data cell,
260                                  des_cblock *key)
261 {
262     des_key_schedule schedule;
263     des_cblock temp_key;
264     des_cblock ivec;
265     char password[512];
266     size_t passlen;
267
268     memcpy(password, pw.data, min(pw.length, sizeof(password)));
269     if(pw.length < sizeof(password)) {
270         int len = min(cell.length, sizeof(password) - pw.length);
271         int i;
272
273         memcpy(password + pw.length, cell.data, len);
274         for (i = pw.length; i < pw.length + len; ++i)
275             password[i] = tolower((unsigned char)password[i]);
276     }
277     passlen = min(sizeof(password), pw.length + cell.length);
278     memcpy(&ivec, "kerberos", 8);
279     memcpy(&temp_key, "kerberos", 8);
280     des_set_odd_parity (&temp_key);
281     des_set_key (&temp_key, schedule);
282     des_cbc_cksum (password, &ivec, passlen, schedule, &ivec);
283
284     memcpy(&temp_key, &ivec, 8);
285     des_set_odd_parity (&temp_key);
286     des_set_key (&temp_key, schedule);
287     des_cbc_cksum (password, key, passlen, schedule, &ivec);
288     memset(&schedule, 0, sizeof(schedule));
289     memset(&temp_key, 0, sizeof(temp_key));
290     memset(&ivec, 0, sizeof(ivec));
291     memset(password, 0, sizeof(password));
292
293     des_set_odd_parity (key);
294 }
295
296 static krb5_error_code
297 DES_AFS3_string_to_key(krb5_context context,
298                        krb5_enctype enctype,
299                        krb5_data password,
300                        krb5_salt salt,
301                        krb5_keyblock *key)
302 {
303     des_cblock tmp;
304     if(password.length > 8)
305         krb5_DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp);
306     else
307         krb5_DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp);
308     key->keytype = enctype;
309     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
310     memset(&key, 0, sizeof(key));
311     return 0;
312 }
313
314 static void
315 DES3_random_key(krb5_context context,
316                 krb5_keyblock *key)
317 {
318     des_cblock *k = key->keyvalue.data;
319     do {
320         krb5_generate_random_block(k, 3 * sizeof(des_cblock));
321         des_set_odd_parity(&k[0]);
322         des_set_odd_parity(&k[1]);
323         des_set_odd_parity(&k[2]);
324     } while(des_is_weak_key(&k[0]) ||
325             des_is_weak_key(&k[1]) ||
326             des_is_weak_key(&k[2]));
327 }
328
329 static void
330 DES3_schedule(krb5_context context,
331               struct key_data *key)
332 {
333     des_cblock *k = key->key->keyvalue.data;
334     des_key_schedule *s = key->schedule->data;
335     des_set_key(&k[0], s[0]);
336     des_set_key(&k[1], s[1]);
337     des_set_key(&k[2], s[2]);
338 }
339
340 /*
341  * A = A xor B. A & B are 8 bytes.
342  */
343
344 static void
345 xor (des_cblock *key, const unsigned char *b)
346 {
347     unsigned char *a = (unsigned char*)key;
348     a[0] ^= b[0];
349     a[1] ^= b[1];
350     a[2] ^= b[2];
351     a[3] ^= b[3];
352     a[4] ^= b[4];
353     a[5] ^= b[5];
354     a[6] ^= b[6];
355     a[7] ^= b[7];
356 }
357
358 static krb5_error_code
359 DES3_string_to_key(krb5_context context,
360                    krb5_enctype enctype,
361                    krb5_data password,
362                    krb5_salt salt,
363                    krb5_keyblock *key)
364 {
365     char *str;
366     size_t len;
367     unsigned char tmp[24];
368     des_cblock keys[3];
369     
370     len = password.length + salt.saltvalue.length;
371     str = malloc(len);
372     if(len != 0 && str == NULL) {
373         krb5_set_error_string(context, "malloc: out of memory");
374         return ENOMEM;
375     }
376     memcpy(str, password.data, password.length);
377     memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length);
378     {
379         des_cblock ivec;
380         des_key_schedule s[3];
381         int i;
382         
383         _krb5_n_fold(str, len, tmp, 24);
384         
385         for(i = 0; i < 3; i++){
386             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
387             des_set_odd_parity(keys + i);
388             if(des_is_weak_key(keys + i))
389                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
390             des_set_key(keys + i, s[i]);
391         }
392         memset(&ivec, 0, sizeof(ivec));
393         des_ede3_cbc_encrypt(tmp,
394                              tmp, sizeof(tmp), 
395                              s[0], s[1], s[2], &ivec, DES_ENCRYPT);
396         memset(s, 0, sizeof(s));
397         memset(&ivec, 0, sizeof(ivec));
398         for(i = 0; i < 3; i++){
399             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
400             des_set_odd_parity(keys + i);
401             if(des_is_weak_key(keys + i))
402                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
403         }
404         memset(tmp, 0, sizeof(tmp));
405     }
406     key->keytype = enctype;
407     krb5_data_copy(&key->keyvalue, keys, sizeof(keys));
408     memset(keys, 0, sizeof(keys));
409     memset(str, 0, len);
410     free(str);
411     return 0;
412 }
413
414 static krb5_error_code
415 DES3_string_to_key_derived(krb5_context context,
416                            krb5_enctype enctype,
417                            krb5_data password,
418                            krb5_salt salt,
419                            krb5_keyblock *key)
420 {
421     krb5_error_code ret;
422     size_t len = password.length + salt.saltvalue.length;
423     char *s;
424
425     s = malloc(len);
426     if(len != 0 && s == NULL) {
427         krb5_set_error_string(context, "malloc: out of memory");
428         return ENOMEM;
429     }
430     memcpy(s, password.data, password.length);
431     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
432     ret = krb5_string_to_key_derived(context,
433                                      s,
434                                      len,
435                                      enctype,
436                                      key);
437     memset(s, 0, len);
438     free(s);
439     return ret;
440 }
441
442 /*
443  * ARCFOUR
444  */
445
446 static void
447 ARCFOUR_random_key(krb5_context context, krb5_keyblock *key)
448 {
449     krb5_generate_random_block (key->keyvalue.data,
450                                 key->keyvalue.length);
451 }
452
453 static void
454 ARCFOUR_schedule(krb5_context context, struct key_data *kd)
455 {
456     RC4_set_key (kd->schedule->data,
457                  kd->key->keyvalue.length, kd->key->keyvalue.data);
458 }
459
460 static krb5_error_code
461 ARCFOUR_string_to_key(krb5_context context,
462                   krb5_enctype enctype,
463                   krb5_data password,
464                   krb5_salt salt,
465                   krb5_keyblock *key)
466 {
467     char *s, *p;
468     size_t len;
469     int i;
470     MD4_CTX m;
471
472     len = 2 * password.length;
473     s = malloc (len);
474     if (len != 0 && s == NULL) {
475         krb5_set_error_string(context, "malloc: out of memory");
476         return ENOMEM;
477     }
478     for (p = s, i = 0; i < password.length; ++i) {
479         *p++ = ((char *)password.data)[i];
480         *p++ = 0;
481     }
482     MD4_Init (&m);
483     MD4_Update (&m, s, len);
484     key->keytype = enctype;
485     krb5_data_alloc (&key->keyvalue, 16);
486     MD4_Final (key->keyvalue.data, &m);
487     memset (s, 0, len);
488     free (s);
489     return 0;
490 }
491
492 extern struct salt_type des_salt[], 
493     des3_salt[], des3_salt_derived[], arcfour_salt[];
494
495 struct key_type keytype_null = {
496     KEYTYPE_NULL,
497     "null",
498     0,
499     0,
500     0,
501     NULL,
502     NULL,
503     NULL
504 };
505
506 struct key_type keytype_des = {
507     KEYTYPE_DES,
508     "des",
509     56,
510     sizeof(des_cblock),
511     sizeof(des_key_schedule),
512     krb5_DES_random_key,
513     krb5_DES_schedule,
514     des_salt
515 };
516
517 struct key_type keytype_des3 = {
518     KEYTYPE_DES3,
519     "des3",
520     168,
521     3 * sizeof(des_cblock), 
522     3 * sizeof(des_key_schedule), 
523     DES3_random_key,
524     DES3_schedule,
525     des3_salt
526 };
527
528 struct key_type keytype_des3_derived = {
529     KEYTYPE_DES3,
530     "des3",
531     168,
532     3 * sizeof(des_cblock),
533     3 * sizeof(des_key_schedule), 
534     DES3_random_key,
535     DES3_schedule,
536     des3_salt_derived
537 };
538
539 struct key_type keytype_arcfour = {
540     KEYTYPE_ARCFOUR,
541     "arcfour",
542     128,
543     16,
544     sizeof(RC4_KEY),
545     ARCFOUR_random_key,
546     ARCFOUR_schedule,
547     arcfour_salt
548 };
549
550 struct key_type *keytypes[] = {
551     &keytype_null,
552     &keytype_des,
553     &keytype_des3_derived,
554     &keytype_des3,
555     &keytype_arcfour
556 };
557
558 static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]);
559
560 static struct key_type *
561 _find_keytype(krb5_keytype type)
562 {
563     int i;
564     for(i = 0; i < num_keytypes; i++)
565         if(keytypes[i]->type == type)
566             return keytypes[i];
567     return NULL;
568 }
569
570
571 struct salt_type des_salt[] = {
572     {
573         KRB5_PW_SALT,
574         "pw-salt",
575         krb5_DES_string_to_key
576     },
577     {
578         KRB5_AFS3_SALT,
579         "afs3-salt",
580         DES_AFS3_string_to_key
581     },
582     { 0 }
583 };
584
585 struct salt_type des3_salt[] = {
586     {
587         KRB5_PW_SALT,
588         "pw-salt",
589         DES3_string_to_key
590     },
591     { 0 }
592 };
593
594 struct salt_type des3_salt_derived[] = {
595     {
596         KRB5_PW_SALT,
597         "pw-salt",
598         DES3_string_to_key_derived
599     },
600     { 0 }
601 };
602
603 struct salt_type arcfour_salt[] = {
604     {
605         KRB5_PW_SALT,
606         "pw-salt",
607         ARCFOUR_string_to_key
608     },
609     { 0 }
610 };
611
612 krb5_error_code
613 krb5_salttype_to_string (krb5_context context,
614                          krb5_enctype etype,
615                          krb5_salttype stype,
616                          char **string)
617 {
618     struct encryption_type *e;
619     struct salt_type *st;
620
621     e = _find_enctype (etype);
622     if (e == NULL) {
623         krb5_set_error_string(context, "encryption type %d not supported",
624                               etype);
625         return KRB5_PROG_ETYPE_NOSUPP;
626     }
627     for (st = e->keytype->string_to_key; st && st->type; st++) {
628         if (st->type == stype) {
629             *string = strdup (st->name);
630             if (*string == NULL) {
631                 krb5_set_error_string(context, "malloc: out of memory");
632                 return ENOMEM;
633             }
634             return 0;
635         }
636     }
637     krb5_set_error_string(context, "salttype %d not supported", stype);
638     return HEIM_ERR_SALTTYPE_NOSUPP;
639 }
640
641 krb5_error_code
642 krb5_string_to_salttype (krb5_context context,
643                          krb5_enctype etype,
644                          const char *string,
645                          krb5_salttype *salttype)
646 {
647     struct encryption_type *e;
648     struct salt_type *st;
649
650     e = _find_enctype (etype);
651     if (e == NULL) {
652         krb5_set_error_string(context, "encryption type %d not supported",
653                               etype);
654         return KRB5_PROG_ETYPE_NOSUPP;
655     }
656     for (st = e->keytype->string_to_key; st && st->type; st++) {
657         if (strcasecmp (st->name, string) == 0) {
658             *salttype = st->type;
659             return 0;
660         }
661     }
662     krb5_set_error_string(context, "salttype %s not supported", string);
663     return HEIM_ERR_SALTTYPE_NOSUPP;
664 }
665
666 krb5_error_code
667 krb5_get_pw_salt(krb5_context context,
668                  krb5_const_principal principal,
669                  krb5_salt *salt)
670 {
671     size_t len;
672     int i;
673     krb5_error_code ret;
674     char *p;
675      
676     salt->salttype = KRB5_PW_SALT;
677     len = strlen(principal->realm);
678     for (i = 0; i < principal->name.name_string.len; ++i)
679         len += strlen(principal->name.name_string.val[i]);
680     ret = krb5_data_alloc (&salt->saltvalue, len);
681     if (ret)
682         return ret;
683     p = salt->saltvalue.data;
684     memcpy (p, principal->realm, strlen(principal->realm));
685     p += strlen(principal->realm);
686     for (i = 0; i < principal->name.name_string.len; ++i) {
687         memcpy (p,
688                 principal->name.name_string.val[i],
689                 strlen(principal->name.name_string.val[i]));
690         p += strlen(principal->name.name_string.val[i]);
691     }
692     return 0;
693 }
694
695 krb5_error_code
696 krb5_free_salt(krb5_context context, 
697                krb5_salt salt)
698 {
699     krb5_data_free(&salt.saltvalue);
700     return 0;
701 }
702
703 krb5_error_code
704 krb5_string_to_key_data (krb5_context context,
705                          krb5_enctype enctype,
706                          krb5_data password,
707                          krb5_principal principal,
708                          krb5_keyblock *key)
709 {
710     krb5_error_code ret;
711     krb5_salt salt;
712
713     ret = krb5_get_pw_salt(context, principal, &salt);
714     if(ret)
715         return ret;
716     ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
717     krb5_free_salt(context, salt);
718     return ret;
719 }
720
721 krb5_error_code
722 krb5_string_to_key (krb5_context context,
723                     krb5_enctype enctype,
724                     const char *password,
725                     krb5_principal principal,
726                     krb5_keyblock *key)
727 {
728     krb5_data pw;
729     pw.data = (void*)password;
730     pw.length = strlen(password);
731     return krb5_string_to_key_data(context, enctype, pw, principal, key);
732 }
733
734 /*
735  * Do a string -> key for encryption type `enctype' operation on
736  * `password' (with salt `salt'), returning the resulting key in `key'
737  */
738
739 krb5_error_code
740 krb5_string_to_key_data_salt (krb5_context context,
741                               krb5_enctype enctype,
742                               krb5_data password,
743                               krb5_salt salt,
744                               krb5_keyblock *key)
745 {
746     struct encryption_type *et =_find_enctype(enctype);
747     struct salt_type *st;
748     if(et == NULL) {
749         krb5_set_error_string(context, "encryption type %d not supported",
750                               enctype);
751         return KRB5_PROG_ETYPE_NOSUPP;
752     }
753     for(st = et->keytype->string_to_key; st && st->type; st++) 
754         if(st->type == salt.salttype)
755             return (*st->string_to_key)(context, enctype, password, salt, key);
756     krb5_set_error_string(context, "salt type %d not supported",
757                           salt.salttype);
758     return HEIM_ERR_SALTTYPE_NOSUPP;
759 }
760
761 /*
762  * Do a string -> key for encryption type `enctype' operation on the
763  * string `password' (with salt `salt'), returning the resulting key
764  * in `key'
765  */
766
767 krb5_error_code
768 krb5_string_to_key_salt (krb5_context context,
769                          krb5_enctype enctype,
770                          const char *password,
771                          krb5_salt salt,
772                          krb5_keyblock *key)
773 {
774     krb5_data pw;
775     pw.data = (void*)password;
776     pw.length = strlen(password);
777     return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
778 }
779
780 krb5_error_code
781 krb5_keytype_to_string(krb5_context context,
782                        krb5_keytype keytype,
783                        char **string)
784 {
785     struct key_type *kt = _find_keytype(keytype);
786     if(kt == NULL) {
787         krb5_set_error_string(context, "key type %d not supported", keytype);
788         return KRB5_PROG_KEYTYPE_NOSUPP;
789     }
790     *string = strdup(kt->name);
791     if(*string == NULL) {
792         krb5_set_error_string(context, "malloc: out of memory");
793         return ENOMEM;
794     }
795     return 0;
796 }
797
798 krb5_error_code
799 krb5_string_to_keytype(krb5_context context,
800                        const char *string,
801                        krb5_keytype *keytype)
802 {
803     int i;
804     for(i = 0; i < num_keytypes; i++)
805         if(strcasecmp(keytypes[i]->name, string) == 0){
806             *keytype = keytypes[i]->type;
807             return 0;
808         }
809     krb5_set_error_string(context, "key type %s not supported", string);
810     return KRB5_PROG_KEYTYPE_NOSUPP;
811 }
812
813 krb5_error_code
814 krb5_generate_random_keyblock(krb5_context context,
815                               krb5_enctype type,
816                               krb5_keyblock *key)
817 {
818     krb5_error_code ret;
819     struct encryption_type *et = _find_enctype(type);
820     if(et == NULL) {
821         krb5_set_error_string(context, "encryption type %d not supported",
822                               type);
823         return KRB5_PROG_ETYPE_NOSUPP;
824     }
825     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
826     if(ret) 
827         return ret;
828     key->keytype = type;
829     if(et->keytype->random_key)
830         (*et->keytype->random_key)(context, key);
831     else
832         krb5_generate_random_block(key->keyvalue.data, 
833                                    key->keyvalue.length);
834     return 0;
835 }
836
837 static krb5_error_code
838 _key_schedule(krb5_context context,
839               struct key_data *key)
840 {
841     krb5_error_code ret;
842     struct encryption_type *et = _find_enctype(key->key->keytype);
843     struct key_type *kt = et->keytype;
844
845     if(kt->schedule == NULL)
846         return 0;
847     if (key->schedule != NULL)
848         return 0;
849     ALLOC(key->schedule, 1);
850     if(key->schedule == NULL) {
851         krb5_set_error_string(context, "malloc: out of memory");
852         return ENOMEM;
853     }
854     ret = krb5_data_alloc(key->schedule, kt->schedule_size);
855     if(ret) {
856         free(key->schedule);
857         key->schedule = NULL;
858         return ret;
859     }
860     (*kt->schedule)(context, key);
861     return 0;
862 }
863
864 /************************************************************
865  *                                                          *
866  ************************************************************/
867
868 static void
869 NONE_checksum(krb5_context context,
870               struct key_data *key,
871               const void *data,
872               size_t len,
873               unsigned usage,
874               Checksum *C)
875 {
876 }
877
878 static void
879 CRC32_checksum(krb5_context context,
880                struct key_data *key,
881                const void *data,
882                size_t len,
883                unsigned usage,
884                Checksum *C)
885 {
886     u_int32_t crc;
887     unsigned char *r = C->checksum.data;
888     _krb5_crc_init_table ();
889     crc = _krb5_crc_update (data, len, 0);
890     r[0] = crc & 0xff;
891     r[1] = (crc >> 8)  & 0xff;
892     r[2] = (crc >> 16) & 0xff;
893     r[3] = (crc >> 24) & 0xff;
894 }
895
896 static void
897 RSA_MD4_checksum(krb5_context context,
898                  struct key_data *key,
899                  const void *data,
900                  size_t len,
901                  unsigned usage,
902                  Checksum *C)
903 {
904     MD4_CTX m;
905
906     MD4_Init (&m);
907     MD4_Update (&m, data, len);
908     MD4_Final (C->checksum.data, &m);
909 }
910
911 static void
912 RSA_MD4_DES_checksum(krb5_context context, 
913                      struct key_data *key,
914                      const void *data, 
915                      size_t len, 
916                      unsigned usage,
917                      Checksum *cksum)
918 {
919     MD4_CTX md4;
920     des_cblock ivec;
921     unsigned char *p = cksum->checksum.data;
922     
923     krb5_generate_random_block(p, 8);
924     MD4_Init (&md4);
925     MD4_Update (&md4, p, 8);
926     MD4_Update (&md4, data, len);
927     MD4_Final (p + 8, &md4);
928     memset (&ivec, 0, sizeof(ivec));
929     des_cbc_encrypt(p, 
930                     p, 
931                     24, 
932                     key->schedule->data, 
933                     &ivec, 
934                     DES_ENCRYPT);
935 }
936
937 static krb5_error_code
938 RSA_MD4_DES_verify(krb5_context context,
939                    struct key_data *key,
940                    const void *data,
941                    size_t len,
942                    unsigned usage,
943                    Checksum *C)
944 {
945     MD4_CTX md4;
946     unsigned char tmp[24];
947     unsigned char res[16];
948     des_cblock ivec;
949     krb5_error_code ret = 0;
950
951     memset(&ivec, 0, sizeof(ivec));
952     des_cbc_encrypt(C->checksum.data,
953                     (void*)tmp, 
954                     C->checksum.length, 
955                     key->schedule->data,
956                     &ivec,
957                     DES_DECRYPT);
958     MD4_Init (&md4);
959     MD4_Update (&md4, tmp, 8); /* confounder */
960     MD4_Update (&md4, data, len);
961     MD4_Final (res, &md4);
962     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
963         krb5_clear_error_string (context);
964         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
965     }
966     memset(tmp, 0, sizeof(tmp));
967     memset(res, 0, sizeof(res));
968     return ret;
969 }
970
971 static void
972 RSA_MD5_checksum(krb5_context context,
973                  struct key_data *key,
974                  const void *data,
975                  size_t len,
976                  unsigned usage,
977                  Checksum *C)
978 {
979     MD5_CTX m;
980
981     MD5_Init  (&m);
982     MD5_Update(&m, data, len);
983     MD5_Final (C->checksum.data, &m);
984 }
985
986 static void
987 RSA_MD5_DES_checksum(krb5_context context,
988                      struct key_data *key,
989                      const void *data,
990                      size_t len,
991                      unsigned usage,
992                      Checksum *C)
993 {
994     MD5_CTX md5;
995     des_cblock ivec;
996     unsigned char *p = C->checksum.data;
997     
998     krb5_generate_random_block(p, 8);
999     MD5_Init (&md5);
1000     MD5_Update (&md5, p, 8);
1001     MD5_Update (&md5, data, len);
1002     MD5_Final (p + 8, &md5);
1003     memset (&ivec, 0, sizeof(ivec));
1004     des_cbc_encrypt(p, 
1005                     p, 
1006                     24, 
1007                     key->schedule->data, 
1008                     &ivec, 
1009                     DES_ENCRYPT);
1010 }
1011
1012 static krb5_error_code
1013 RSA_MD5_DES_verify(krb5_context context,
1014                    struct key_data *key,
1015                    const void *data,
1016                    size_t len,
1017                    unsigned usage,
1018                    Checksum *C)
1019 {
1020     MD5_CTX md5;
1021     unsigned char tmp[24];
1022     unsigned char res[16];
1023     des_cblock ivec;
1024     des_key_schedule *sched = key->schedule->data;
1025     krb5_error_code ret = 0;
1026
1027     memset(&ivec, 0, sizeof(ivec));
1028     des_cbc_encrypt(C->checksum.data, 
1029                     (void*)tmp, 
1030                     C->checksum.length, 
1031                     sched[0],
1032                     &ivec,
1033                     DES_DECRYPT);
1034     MD5_Init (&md5);
1035     MD5_Update (&md5, tmp, 8); /* confounder */
1036     MD5_Update (&md5, data, len);
1037     MD5_Final (res, &md5);
1038     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
1039         krb5_clear_error_string (context);
1040         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1041     }
1042     memset(tmp, 0, sizeof(tmp));
1043     memset(res, 0, sizeof(res));
1044     return ret;
1045 }
1046
1047 static void
1048 RSA_MD5_DES3_checksum(krb5_context context,
1049                       struct key_data *key,
1050                       const void *data,
1051                       size_t len,
1052                       unsigned usage,
1053                       Checksum *C)
1054 {
1055     MD5_CTX md5;
1056     des_cblock ivec;
1057     unsigned char *p = C->checksum.data;
1058     des_key_schedule *sched = key->schedule->data;
1059     
1060     krb5_generate_random_block(p, 8);
1061     MD5_Init (&md5);
1062     MD5_Update (&md5, p, 8);
1063     MD5_Update (&md5, data, len);
1064     MD5_Final (p + 8, &md5);
1065     memset (&ivec, 0, sizeof(ivec));
1066     des_ede3_cbc_encrypt(p, 
1067                          p, 
1068                          24, 
1069                          sched[0], sched[1], sched[2],
1070                          &ivec, 
1071                          DES_ENCRYPT);
1072 }
1073
1074 static krb5_error_code
1075 RSA_MD5_DES3_verify(krb5_context context,
1076                     struct key_data *key,
1077                     const void *data,
1078                     size_t len,
1079                     unsigned usage,
1080                     Checksum *C)
1081 {
1082     MD5_CTX md5;
1083     unsigned char tmp[24];
1084     unsigned char res[16];
1085     des_cblock ivec;
1086     des_key_schedule *sched = key->schedule->data;
1087     krb5_error_code ret = 0;
1088
1089     memset(&ivec, 0, sizeof(ivec));
1090     des_ede3_cbc_encrypt(C->checksum.data, 
1091                          (void*)tmp, 
1092                          C->checksum.length, 
1093                          sched[0], sched[1], sched[2],
1094                          &ivec,
1095                          DES_DECRYPT);
1096     MD5_Init (&md5);
1097     MD5_Update (&md5, tmp, 8); /* confounder */
1098     MD5_Update (&md5, data, len);
1099     MD5_Final (res, &md5);
1100     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
1101         krb5_clear_error_string (context);
1102         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1103     }
1104     memset(tmp, 0, sizeof(tmp));
1105     memset(res, 0, sizeof(res));
1106     return ret;
1107 }
1108
1109 static void
1110 SHA1_checksum(krb5_context context,
1111               struct key_data *key,
1112               const void *data,
1113               size_t len,
1114               unsigned usage,
1115               Checksum *C)
1116 {
1117     SHA_CTX m;
1118
1119     SHA1_Init(&m);
1120     SHA1_Update(&m, data, len);
1121     SHA1_Final(C->checksum.data, &m);
1122 }
1123
1124 /* HMAC according to RFC2104 */
1125 static void
1126 hmac(krb5_context context,
1127      struct checksum_type *cm, 
1128      const void *data, 
1129      size_t len, 
1130      unsigned usage,
1131      struct key_data *keyblock,
1132      Checksum *result)
1133 {
1134     unsigned char *ipad, *opad;
1135     unsigned char *key;
1136     size_t key_len;
1137     int i;
1138     
1139     if(keyblock->key->keyvalue.length > cm->blocksize){
1140         (*cm->checksum)(context, 
1141                         keyblock, 
1142                         keyblock->key->keyvalue.data, 
1143                         keyblock->key->keyvalue.length, 
1144                         usage,
1145                         result);
1146         key = result->checksum.data;
1147         key_len = result->checksum.length;
1148     } else {
1149         key = keyblock->key->keyvalue.data;
1150         key_len = keyblock->key->keyvalue.length;
1151     }
1152     ipad = malloc(cm->blocksize + len);
1153     opad = malloc(cm->blocksize + cm->checksumsize);
1154     memset(ipad, 0x36, cm->blocksize);
1155     memset(opad, 0x5c, cm->blocksize);
1156     for(i = 0; i < key_len; i++){
1157         ipad[i] ^= key[i];
1158         opad[i] ^= key[i];
1159     }
1160     memcpy(ipad + cm->blocksize, data, len);
1161     (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
1162                     usage, result);
1163     memcpy(opad + cm->blocksize, result->checksum.data, 
1164            result->checksum.length);
1165     (*cm->checksum)(context, keyblock, opad, 
1166                     cm->blocksize + cm->checksumsize, usage, result);
1167     memset(ipad, 0, cm->blocksize + len);
1168     free(ipad);
1169     memset(opad, 0, cm->blocksize + cm->checksumsize);
1170     free(opad);
1171 }
1172
1173 static void
1174 HMAC_SHA1_DES3_checksum(krb5_context context,
1175                         struct key_data *key, 
1176                         const void *data, 
1177                         size_t len, 
1178                         unsigned usage,
1179                         Checksum *result)
1180 {
1181     struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1);
1182
1183     hmac(context, c, data, len, usage, key, result);
1184 }
1185
1186 /*
1187  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
1188  */
1189
1190 static void
1191 HMAC_MD5_checksum(krb5_context context,
1192                   struct key_data *key,
1193                   const void *data,
1194                   size_t len,
1195                   unsigned usage,
1196                   Checksum *result)
1197 {
1198     MD5_CTX md5;
1199     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1200     const char signature[] = "signaturekey";
1201     Checksum ksign_c;
1202     struct key_data ksign;
1203     krb5_keyblock kb;
1204     unsigned char t[4];
1205     unsigned char tmp[16];
1206     unsigned char ksign_c_data[16];
1207
1208     ksign_c.checksum.length = sizeof(ksign_c_data);
1209     ksign_c.checksum.data   = ksign_c_data;
1210     hmac(context, c, signature, sizeof(signature), 0, key, &ksign_c);
1211     ksign.key = &kb;
1212     kb.keyvalue = ksign_c.checksum;
1213     MD5_Init (&md5);
1214     t[0] = (usage >>  0) & 0xFF;
1215     t[1] = (usage >>  8) & 0xFF;
1216     t[2] = (usage >> 16) & 0xFF;
1217     t[3] = (usage >> 24) & 0xFF;
1218     MD5_Update (&md5, t, 4);
1219     MD5_Update (&md5, data, len);
1220     MD5_Final (tmp, &md5);
1221     hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
1222 }
1223
1224 /*
1225  * same as previous but being used while encrypting.
1226  */
1227
1228 static void
1229 HMAC_MD5_checksum_enc(krb5_context context,
1230                       struct key_data *key,
1231                       const void *data,
1232                       size_t len,
1233                       unsigned usage,
1234                       Checksum *result)
1235 {
1236     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1237     Checksum ksign_c;
1238     struct key_data ksign;
1239     krb5_keyblock kb;
1240     unsigned char t[4];
1241     unsigned char ksign_c_data[16];
1242
1243     t[0] = (usage >>  0) & 0xFF;
1244     t[1] = (usage >>  8) & 0xFF;
1245     t[2] = (usage >> 16) & 0xFF;
1246     t[3] = (usage >> 24) & 0xFF;
1247
1248     ksign_c.checksum.length = sizeof(ksign_c_data);
1249     ksign_c.checksum.data   = ksign_c_data;
1250     hmac(context, c, t, sizeof(t), 0, key, &ksign_c);
1251     ksign.key = &kb;
1252     kb.keyvalue = ksign_c.checksum;
1253     hmac(context, c, data, len, 0, &ksign, result);
1254 }
1255
1256 struct checksum_type checksum_none = {
1257     CKSUMTYPE_NONE, 
1258     "none", 
1259     1, 
1260     0, 
1261     0, 
1262     NONE_checksum, 
1263     NULL
1264 };
1265 struct checksum_type checksum_crc32 = {
1266     CKSUMTYPE_CRC32,
1267     "crc32",
1268     1,
1269     4,
1270     0,
1271     CRC32_checksum,
1272     NULL
1273 };
1274 struct checksum_type checksum_rsa_md4 = {
1275     CKSUMTYPE_RSA_MD4,
1276     "rsa-md4",
1277     64,
1278     16,
1279     F_CPROOF,
1280     RSA_MD4_checksum,
1281     NULL
1282 };
1283 struct checksum_type checksum_rsa_md4_des = {
1284     CKSUMTYPE_RSA_MD4_DES,
1285     "rsa-md4-des",
1286     64,
1287     24,
1288     F_KEYED | F_CPROOF | F_VARIANT,
1289     RSA_MD4_DES_checksum,
1290     RSA_MD4_DES_verify
1291 };
1292 #if 0
1293 struct checksum_type checksum_des_mac = { 
1294     CKSUMTYPE_DES_MAC,
1295     "des-mac",
1296     0,
1297     0,
1298     0,
1299     DES_MAC_checksum
1300 };
1301 struct checksum_type checksum_des_mac_k = {
1302     CKSUMTYPE_DES_MAC_K,
1303     "des-mac-k",
1304     0,
1305     0,
1306     0,
1307     DES_MAC_K_checksum
1308 };
1309 struct checksum_type checksum_rsa_md4_des_k = {
1310     CKSUMTYPE_RSA_MD4_DES_K, 
1311     "rsa-md4-des-k", 
1312     0, 
1313     0, 
1314     0, 
1315     RSA_MD4_DES_K_checksum,
1316     RSA_MD4_DES_K_verify
1317 };
1318 #endif
1319 struct checksum_type checksum_rsa_md5 = {
1320     CKSUMTYPE_RSA_MD5,
1321     "rsa-md5",
1322     64,
1323     16,
1324     F_CPROOF,
1325     RSA_MD5_checksum,
1326     NULL
1327 };
1328 struct checksum_type checksum_rsa_md5_des = {
1329     CKSUMTYPE_RSA_MD5_DES,
1330     "rsa-md5-des",
1331     64,
1332     24,
1333     F_KEYED | F_CPROOF | F_VARIANT,
1334     RSA_MD5_DES_checksum,
1335     RSA_MD5_DES_verify
1336 };
1337 struct checksum_type checksum_rsa_md5_des3 = {
1338     CKSUMTYPE_RSA_MD5_DES3,
1339     "rsa-md5-des3",
1340     64,
1341     24,
1342     F_KEYED | F_CPROOF | F_VARIANT,
1343     RSA_MD5_DES3_checksum,
1344     RSA_MD5_DES3_verify
1345 };
1346 struct checksum_type checksum_sha1 = {
1347     CKSUMTYPE_SHA1,
1348     "sha1",
1349     64,
1350     20,
1351     F_CPROOF,
1352     SHA1_checksum,
1353     NULL
1354 };
1355 struct checksum_type checksum_hmac_sha1_des3 = {
1356     CKSUMTYPE_HMAC_SHA1_DES3,
1357     "hmac-sha1-des3",
1358     64,
1359     20,
1360     F_KEYED | F_CPROOF | F_DERIVED,
1361     HMAC_SHA1_DES3_checksum,
1362     NULL
1363 };
1364
1365 struct checksum_type checksum_hmac_md5 = {
1366     CKSUMTYPE_HMAC_MD5,
1367     "hmac-md5",
1368     64,
1369     16,
1370     F_KEYED | F_CPROOF,
1371     HMAC_MD5_checksum,
1372     NULL
1373 };
1374
1375 struct checksum_type checksum_hmac_md5_enc = {
1376     CKSUMTYPE_HMAC_MD5_ENC,
1377     "hmac-md5-enc",
1378     64,
1379     16,
1380     F_KEYED | F_CPROOF | F_PSEUDO,
1381     HMAC_MD5_checksum_enc,
1382     NULL
1383 };
1384
1385 struct checksum_type *checksum_types[] = {
1386     &checksum_none,
1387     &checksum_crc32,
1388     &checksum_rsa_md4,
1389     &checksum_rsa_md4_des,
1390 #if 0
1391     &checksum_des_mac, 
1392     &checksum_des_mac_k,
1393     &checksum_rsa_md4_des_k,
1394 #endif
1395     &checksum_rsa_md5,
1396     &checksum_rsa_md5_des,
1397     &checksum_rsa_md5_des3,
1398     &checksum_sha1,
1399     &checksum_hmac_sha1_des3,
1400     &checksum_hmac_md5,
1401     &checksum_hmac_md5_enc
1402 };
1403
1404 static int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]);
1405
1406 static struct checksum_type *
1407 _find_checksum(krb5_cksumtype type)
1408 {
1409     int i;
1410     for(i = 0; i < num_checksums; i++)
1411         if(checksum_types[i]->type == type)
1412             return checksum_types[i];
1413     return NULL;
1414 }
1415
1416 static krb5_error_code
1417 get_checksum_key(krb5_context context, 
1418                  krb5_crypto crypto,
1419                  unsigned usage,  /* not krb5_key_usage */
1420                  struct checksum_type *ct, 
1421                  struct key_data **key)
1422 {
1423     krb5_error_code ret = 0;
1424
1425     if(ct->flags & F_DERIVED)
1426         ret = _get_derived_key(context, crypto, usage, key);
1427     else if(ct->flags & F_VARIANT) {
1428         int i;
1429
1430         *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
1431         if(*key == NULL) {
1432             krb5_set_error_string(context, "malloc: out of memory");
1433             return ENOMEM;
1434         }
1435         ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
1436         if(ret) 
1437             return ret;
1438         for(i = 0; i < (*key)->key->keyvalue.length; i++)
1439             ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
1440     } else {
1441         *key = &crypto->key; 
1442     }
1443     if(ret == 0)
1444         ret = _key_schedule(context, *key);
1445     return ret;
1446 }
1447
1448 static krb5_error_code
1449 do_checksum (krb5_context context,
1450              struct checksum_type *ct,
1451              krb5_crypto crypto,
1452              unsigned usage,
1453              void *data,
1454              size_t len,
1455              Checksum *result)
1456 {
1457     krb5_error_code ret;
1458     struct key_data *dkey;
1459     int keyed_checksum;
1460
1461     keyed_checksum = (ct->flags & F_KEYED) != 0;
1462     if(keyed_checksum && crypto == NULL) {
1463         krb5_clear_error_string (context);
1464         return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1465     }
1466     if(keyed_checksum) {
1467         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1468         if (ret)
1469             return ret;
1470     } else
1471         dkey = NULL;
1472     result->cksumtype = ct->type;
1473     krb5_data_alloc(&result->checksum, ct->checksumsize);
1474     (*ct->checksum)(context, dkey, data, len, usage, result);
1475     return 0;
1476 }
1477
1478 static krb5_error_code
1479 create_checksum(krb5_context context,
1480                 krb5_crypto crypto,
1481                 unsigned usage, /* not krb5_key_usage */
1482                 krb5_cksumtype type, /* 0 -> pick from crypto */
1483                 void *data,
1484                 size_t len,
1485                 Checksum *result)
1486 {
1487     struct checksum_type *ct = NULL;
1488
1489     if (type) {
1490         ct = _find_checksum(type);
1491     } else if (crypto) {
1492         ct = crypto->et->keyed_checksum;
1493         if (ct == NULL)
1494             ct = crypto->et->checksum;
1495     }
1496
1497     if(ct == NULL) {
1498         krb5_set_error_string (context, "checksum type %d not supported",
1499                                type);
1500         return KRB5_PROG_SUMTYPE_NOSUPP;
1501     }
1502     return do_checksum (context, ct, crypto, usage, data, len, result);
1503 }
1504
1505 krb5_error_code
1506 krb5_create_checksum(krb5_context context,
1507                      krb5_crypto crypto,
1508                      krb5_key_usage usage,
1509                      int type,
1510                      void *data,
1511                      size_t len,
1512                      Checksum *result)
1513 {
1514     return create_checksum(context, crypto, 
1515                            CHECKSUM_USAGE(usage), 
1516                            type, data, len, result);
1517 }
1518
1519 static krb5_error_code
1520 verify_checksum(krb5_context context,
1521                 krb5_crypto crypto,
1522                 unsigned usage, /* not krb5_key_usage */
1523                 void *data,
1524                 size_t len,
1525                 Checksum *cksum)
1526 {
1527     krb5_error_code ret;
1528     struct key_data *dkey;
1529     int keyed_checksum;
1530     Checksum c;
1531     struct checksum_type *ct;
1532
1533     ct = _find_checksum(cksum->cksumtype);
1534     if(ct == NULL) {
1535         krb5_set_error_string (context, "checksum type %d not supported",
1536                                cksum->cksumtype);
1537         return KRB5_PROG_SUMTYPE_NOSUPP;
1538     }
1539     if(ct->checksumsize != cksum->checksum.length) {
1540         krb5_clear_error_string (context);
1541         return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
1542     }
1543     keyed_checksum = (ct->flags & F_KEYED) != 0;
1544     if(keyed_checksum && crypto == NULL) {
1545         krb5_clear_error_string (context);
1546         return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1547     }
1548     if(keyed_checksum)
1549         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1550     else
1551         dkey = NULL;
1552     if(ct->verify)
1553         return (*ct->verify)(context, dkey, data, len, usage, cksum);
1554
1555     ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
1556     if (ret)
1557         return ret;
1558
1559     (*ct->checksum)(context, dkey, data, len, usage, &c);
1560
1561     if(c.checksum.length != cksum->checksum.length || 
1562        memcmp(c.checksum.data, cksum->checksum.data, c.checksum.length)) {
1563         krb5_clear_error_string (context);
1564         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1565     } else {
1566         ret = 0;
1567     }
1568     krb5_data_free (&c.checksum);
1569     return ret;
1570 }
1571
1572 krb5_error_code
1573 krb5_verify_checksum(krb5_context context,
1574                      krb5_crypto crypto,
1575                      krb5_key_usage usage, 
1576                      void *data,
1577                      size_t len,
1578                      Checksum *cksum)
1579 {
1580     return verify_checksum(context, crypto, 
1581                            CHECKSUM_USAGE(usage), data, len, cksum);
1582 }
1583
1584 krb5_error_code
1585 krb5_checksumsize(krb5_context context,
1586                   krb5_cksumtype type,
1587                   size_t *size)
1588 {
1589     struct checksum_type *ct = _find_checksum(type);
1590     if(ct == NULL) {
1591         krb5_set_error_string (context, "checksum type %d not supported",
1592                                type);
1593         return KRB5_PROG_SUMTYPE_NOSUPP;
1594     }
1595     *size = ct->checksumsize;
1596     return 0;
1597 }
1598
1599 krb5_boolean
1600 krb5_checksum_is_keyed(krb5_context context,
1601                        krb5_cksumtype type)
1602 {
1603     struct checksum_type *ct = _find_checksum(type);
1604     if(ct == NULL) {
1605         krb5_set_error_string (context, "checksum type %d not supported",
1606                                type);
1607         return KRB5_PROG_SUMTYPE_NOSUPP;
1608     }
1609     return ct->flags & F_KEYED;
1610 }
1611
1612 krb5_boolean
1613 krb5_checksum_is_collision_proof(krb5_context context,
1614                                  krb5_cksumtype type)
1615 {
1616     struct checksum_type *ct = _find_checksum(type);
1617     if(ct == NULL) {
1618         krb5_set_error_string (context, "checksum type %d not supported",
1619                                type);
1620         return KRB5_PROG_SUMTYPE_NOSUPP;
1621     }
1622     return ct->flags & F_CPROOF;
1623 }
1624
1625 /************************************************************
1626  *                                                          *
1627  ************************************************************/
1628
1629 static krb5_error_code
1630 NULL_encrypt(krb5_context context,
1631              struct key_data *key, 
1632              void *data, 
1633              size_t len, 
1634              krb5_boolean encrypt,
1635              int usage,
1636              void *ivec)
1637 {
1638     return 0;
1639 }
1640
1641 static krb5_error_code
1642 DES_CBC_encrypt_null_ivec(krb5_context context,
1643                           struct key_data *key, 
1644                           void *data, 
1645                           size_t len, 
1646                           krb5_boolean encrypt,
1647                           int usage,
1648                           void *ignore_ivec)
1649 {
1650     des_cblock ivec;
1651     des_key_schedule *s = key->schedule->data;
1652     memset(&ivec, 0, sizeof(ivec));
1653     des_cbc_encrypt(data, data, len, *s, &ivec, encrypt);
1654     return 0;
1655 }
1656
1657 static krb5_error_code
1658 DES_CBC_encrypt_key_ivec(krb5_context context,
1659                          struct key_data *key, 
1660                          void *data, 
1661                          size_t len, 
1662                          krb5_boolean encrypt,
1663                          int usage,
1664                          void *ignore_ivec)
1665 {
1666     des_cblock ivec;
1667     des_key_schedule *s = key->schedule->data;
1668     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
1669     des_cbc_encrypt(data, data, len, *s, &ivec, encrypt);
1670     return 0;
1671 }
1672
1673 static krb5_error_code
1674 DES3_CBC_encrypt(krb5_context context,
1675                  struct key_data *key, 
1676                  void *data, 
1677                  size_t len, 
1678                  krb5_boolean encrypt,
1679                  int usage,
1680                  void *ivec)
1681 {
1682     des_cblock local_ivec;
1683     des_key_schedule *s = key->schedule->data;
1684     if(ivec == NULL) {
1685         ivec = &local_ivec;
1686         memset(local_ivec, 0, sizeof(local_ivec));
1687     }
1688     des_ede3_cbc_encrypt(data, data, len, s[0], s[1], s[2], ivec, encrypt);
1689     return 0;
1690 }
1691
1692 static krb5_error_code
1693 DES_CFB64_encrypt_null_ivec(krb5_context context,
1694                             struct key_data *key, 
1695                             void *data, 
1696                             size_t len, 
1697                             krb5_boolean encrypt,
1698                             int usage,
1699                             void *ignore_ivec)
1700 {
1701     des_cblock ivec;
1702     int num = 0;
1703     des_key_schedule *s = key->schedule->data;
1704     memset(&ivec, 0, sizeof(ivec));
1705
1706     des_cfb64_encrypt(data, data, len, *s, &ivec, &num, encrypt);
1707     return 0;
1708 }
1709
1710 static krb5_error_code
1711 DES_PCBC_encrypt_key_ivec(krb5_context context,
1712                           struct key_data *key, 
1713                           void *data, 
1714                           size_t len, 
1715                           krb5_boolean encrypt,
1716                           int usage,
1717                           void *ignore_ivec)
1718 {
1719     des_cblock ivec;
1720     des_key_schedule *s = key->schedule->data;
1721     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
1722
1723     des_pcbc_encrypt(data, data, len, *s, &ivec, encrypt);
1724     return 0;
1725 }
1726
1727 /*
1728  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
1729  *
1730  * warning: not for small children
1731  */
1732
1733 static krb5_error_code
1734 ARCFOUR_subencrypt(krb5_context context,
1735                    struct key_data *key,
1736                    void *data,
1737                    size_t len,
1738                    int usage,
1739                    void *ivec)
1740 {
1741     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1742     Checksum k1_c, k2_c, k3_c, cksum;
1743     struct key_data ke;
1744     krb5_keyblock kb;
1745     unsigned char t[4];
1746     RC4_KEY rc4_key;
1747     unsigned char *cdata = data;
1748     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
1749
1750     t[0] = (usage >>  0) & 0xFF;
1751     t[1] = (usage >>  8) & 0xFF;
1752     t[2] = (usage >> 16) & 0xFF;
1753     t[3] = (usage >> 24) & 0xFF;
1754
1755     k1_c.checksum.length = sizeof(k1_c_data);
1756     k1_c.checksum.data   = k1_c_data;
1757
1758     hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
1759
1760     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
1761
1762     k2_c.checksum.length = sizeof(k2_c_data);
1763     k2_c.checksum.data   = k2_c_data;
1764
1765     ke.key = &kb;
1766     kb.keyvalue = k2_c.checksum;
1767
1768     cksum.checksum.length = 16;
1769     cksum.checksum.data   = data;
1770
1771     hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
1772
1773     ke.key = &kb;
1774     kb.keyvalue = k1_c.checksum;
1775
1776     k3_c.checksum.length = sizeof(k3_c_data);
1777     k3_c.checksum.data   = k3_c_data;
1778
1779     hmac(NULL, c, data, 16, 0, &ke, &k3_c);
1780
1781     RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
1782     RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
1783     memset (k1_c_data, 0, sizeof(k1_c_data));
1784     memset (k2_c_data, 0, sizeof(k2_c_data));
1785     memset (k3_c_data, 0, sizeof(k3_c_data));
1786     return 0;
1787 }
1788
1789 static krb5_error_code
1790 ARCFOUR_subdecrypt(krb5_context context,
1791                    struct key_data *key,
1792                    void *data,
1793                    size_t len,
1794                    int usage,
1795                    void *ivec)
1796 {
1797     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1798     Checksum k1_c, k2_c, k3_c, cksum;
1799     struct key_data ke;
1800     krb5_keyblock kb;
1801     unsigned char t[4];
1802     RC4_KEY rc4_key;
1803     unsigned char *cdata = data;
1804     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
1805     unsigned char cksum_data[16];
1806
1807     t[0] = (usage >>  0) & 0xFF;
1808     t[1] = (usage >>  8) & 0xFF;
1809     t[2] = (usage >> 16) & 0xFF;
1810     t[3] = (usage >> 24) & 0xFF;
1811
1812     k1_c.checksum.length = sizeof(k1_c_data);
1813     k1_c.checksum.data   = k1_c_data;
1814
1815     hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
1816
1817     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
1818
1819     k2_c.checksum.length = sizeof(k2_c_data);
1820     k2_c.checksum.data   = k2_c_data;
1821
1822     ke.key = &kb;
1823     kb.keyvalue = k1_c.checksum;
1824
1825     k3_c.checksum.length = sizeof(k3_c_data);
1826     k3_c.checksum.data   = k3_c_data;
1827
1828     hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
1829
1830     RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
1831     RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
1832
1833     ke.key = &kb;
1834     kb.keyvalue = k2_c.checksum;
1835
1836     cksum.checksum.length = 16;
1837     cksum.checksum.data   = cksum_data;
1838
1839     hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
1840
1841     memset (k1_c_data, 0, sizeof(k1_c_data));
1842     memset (k2_c_data, 0, sizeof(k2_c_data));
1843     memset (k3_c_data, 0, sizeof(k3_c_data));
1844
1845     if (memcmp (cksum.checksum.data, data, 16) != 0) {
1846         krb5_clear_error_string (context);
1847         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
1848     } else {
1849         return 0;
1850     }
1851 }
1852
1853 /*
1854  * convert the usage numbers used in
1855  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
1856  * draft-brezak-win2k-krb-rc4-hmac-03.txt
1857  */
1858
1859 static krb5_error_code
1860 usage2arcfour (krb5_context context, int *usage)
1861 {
1862     switch (*usage) {
1863     case KRB5_KU_PA_ENC_TIMESTAMP :
1864         *usage = 1;
1865         return 0;
1866     case KRB5_KU_TICKET :
1867         *usage = 8;
1868     case KRB5_KU_AS_REP_ENC_PART :
1869         *usage = 8;
1870         return 0;
1871     case KRB5_KU_TGS_REQ_AUTH_DAT_SESSION :
1872     case KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY :
1873     case KRB5_KU_TGS_REQ_AUTH_CKSUM :
1874     case KRB5_KU_TGS_REQ_AUTH :
1875         *usage = 7;
1876         return 0;
1877     case KRB5_KU_TGS_REP_ENC_PART_SESSION :
1878     case KRB5_KU_TGS_REP_ENC_PART_SUB_KEY :
1879         *usage = 8;
1880         return 0;
1881     case KRB5_KU_AP_REQ_AUTH_CKSUM :
1882     case KRB5_KU_AP_REQ_AUTH :
1883     case KRB5_KU_AP_REQ_ENC_PART :
1884         *usage = 11;
1885         return 0;
1886     case KRB5_KU_KRB_PRIV :
1887         *usage = 0;
1888         return 0;
1889     case KRB5_KU_KRB_CRED :
1890     case KRB5_KU_KRB_SAFE_CKSUM :
1891     case KRB5_KU_OTHER_ENCRYPTED :
1892     case KRB5_KU_OTHER_CKSUM :
1893     case KRB5_KU_KRB_ERROR :
1894     case KRB5_KU_AD_KDC_ISSUED :
1895     case KRB5_KU_MANDATORY_TICKET_EXTENSION :
1896     case KRB5_KU_AUTH_DATA_TICKET_EXTENSION :
1897     case KRB5_KU_USAGE_SEAL :
1898     case KRB5_KU_USAGE_SIGN :
1899     case KRB5_KU_USAGE_SEQ :
1900     default :
1901         krb5_set_error_string(context, "unknown arcfour usage type %d", *usage);
1902         return KRB5_PROG_ETYPE_NOSUPP;
1903     }
1904 }
1905
1906 static krb5_error_code
1907 ARCFOUR_encrypt(krb5_context context,
1908                 struct key_data *key,
1909                 void *data,
1910                 size_t len,
1911                 krb5_boolean encrypt,
1912                 int usage,
1913                 void *ivec)
1914 {
1915     krb5_error_code ret;
1916     if((ret = usage2arcfour (context, &usage)) != 0)
1917         return ret;
1918
1919     if (encrypt)
1920         return ARCFOUR_subencrypt (context, key, data, len, usage, ivec);
1921     else
1922         return ARCFOUR_subdecrypt (context, key, data, len, usage, ivec);
1923 }
1924
1925
1926 /*
1927  * these should currently be in reverse preference order.
1928  * (only relevant for !F_PSEUDO) */
1929
1930 static struct encryption_type enctype_null = {
1931     ETYPE_NULL,
1932     "null",
1933     1,
1934     0,
1935     &keytype_null,
1936     &checksum_none,
1937     NULL,
1938     0,
1939     NULL_encrypt,
1940 };
1941 static struct encryption_type enctype_des_cbc_crc = {
1942     ETYPE_DES_CBC_CRC,
1943     "des-cbc-crc",
1944     8,
1945     8,
1946     &keytype_des,
1947     &checksum_crc32,
1948     NULL,
1949     0,
1950     DES_CBC_encrypt_key_ivec,
1951 };
1952 static struct encryption_type enctype_des_cbc_md4 = {
1953     ETYPE_DES_CBC_MD4,
1954     "des-cbc-md4",
1955     8,
1956     8,
1957     &keytype_des,
1958     &checksum_rsa_md4,
1959     &checksum_rsa_md4_des,
1960     0,
1961     DES_CBC_encrypt_null_ivec,
1962 };
1963 static struct encryption_type enctype_des_cbc_md5 = {
1964     ETYPE_DES_CBC_MD5,
1965     "des-cbc-md5",
1966     8,
1967     8,
1968     &keytype_des,
1969     &checksum_rsa_md5,
1970     &checksum_rsa_md5_des,
1971     0,
1972     DES_CBC_encrypt_null_ivec,
1973 };
1974 static struct encryption_type enctype_arcfour_hmac_md5 = {
1975     ETYPE_ARCFOUR_HMAC_MD5,
1976     "arcfour-hmac-md5",
1977     1,
1978     8,
1979     &keytype_arcfour,
1980     &checksum_hmac_md5,
1981     &checksum_hmac_md5_enc,
1982     F_SPECIAL,
1983     ARCFOUR_encrypt
1984 };
1985 static struct encryption_type enctype_des3_cbc_md5 = { 
1986     ETYPE_DES3_CBC_MD5,
1987     "des3-cbc-md5",
1988     8,
1989     8,
1990     &keytype_des3,
1991     &checksum_rsa_md5,
1992     &checksum_rsa_md5_des3,
1993     0,
1994     DES3_CBC_encrypt,
1995 };
1996 static struct encryption_type enctype_des3_cbc_sha1 = {
1997     ETYPE_DES3_CBC_SHA1,
1998     "des3-cbc-sha1",
1999     8,
2000     8,
2001     &keytype_des3_derived,
2002     &checksum_sha1,
2003     &checksum_hmac_sha1_des3,
2004     F_DERIVED,
2005     DES3_CBC_encrypt,
2006 };
2007 static struct encryption_type enctype_old_des3_cbc_sha1 = {
2008     ETYPE_OLD_DES3_CBC_SHA1,
2009     "old-des3-cbc-sha1",
2010     8,
2011     8,
2012     &keytype_des3,
2013     &checksum_sha1,
2014     &checksum_hmac_sha1_des3,
2015     0,
2016     DES3_CBC_encrypt,
2017 };
2018 static struct encryption_type enctype_des_cbc_none = {
2019     ETYPE_DES_CBC_NONE,
2020     "des-cbc-none",
2021     8,
2022     0,
2023     &keytype_des,
2024     &checksum_none,
2025     NULL,
2026     F_PSEUDO,
2027     DES_CBC_encrypt_null_ivec,
2028 };
2029 static struct encryption_type enctype_des_cfb64_none = {
2030     ETYPE_DES_CFB64_NONE,
2031     "des-cfb64-none",
2032     1,
2033     0,
2034     &keytype_des,
2035     &checksum_none,
2036     NULL,
2037     F_PSEUDO,
2038     DES_CFB64_encrypt_null_ivec,
2039 };
2040 static struct encryption_type enctype_des_pcbc_none = {
2041     ETYPE_DES_PCBC_NONE,
2042     "des-pcbc-none",
2043     8,
2044     0,
2045     &keytype_des,
2046     &checksum_none,
2047     NULL,
2048     F_PSEUDO,
2049     DES_PCBC_encrypt_key_ivec,
2050 };
2051 static struct encryption_type enctype_des3_cbc_none = {
2052     ETYPE_DES3_CBC_NONE,
2053     "des3-cbc-none",
2054     8,
2055     0,
2056     &keytype_des3_derived,
2057     &checksum_none,
2058     NULL,
2059     F_PSEUDO,
2060     DES3_CBC_encrypt,
2061 };
2062
2063 static struct encryption_type *etypes[] = {
2064     &enctype_null,
2065     &enctype_des_cbc_crc,
2066     &enctype_des_cbc_md4,
2067     &enctype_des_cbc_md5,
2068     &enctype_arcfour_hmac_md5,
2069     &enctype_des3_cbc_md5, 
2070     &enctype_des3_cbc_sha1,
2071     &enctype_old_des3_cbc_sha1,
2072     &enctype_des_cbc_none,
2073     &enctype_des_cfb64_none,
2074     &enctype_des_pcbc_none,
2075     &enctype_des3_cbc_none
2076 };
2077
2078 static unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]);
2079
2080
2081 static struct encryption_type *
2082 _find_enctype(krb5_enctype type)
2083 {
2084     int i;
2085     for(i = 0; i < num_etypes; i++)
2086         if(etypes[i]->type == type)
2087             return etypes[i];
2088     return NULL;
2089 }
2090
2091
2092 krb5_error_code
2093 krb5_enctype_to_string(krb5_context context,
2094                        krb5_enctype etype,
2095                        char **string)
2096 {
2097     struct encryption_type *e;
2098     e = _find_enctype(etype);
2099     if(e == NULL) {
2100         krb5_set_error_string (context, "encryption type %d not supported",
2101                                etype);
2102         return KRB5_PROG_ETYPE_NOSUPP;
2103     }
2104     *string = strdup(e->name);
2105     if(*string == NULL) {
2106         krb5_set_error_string(context, "malloc: out of memory");
2107         return ENOMEM;
2108     }
2109     return 0;
2110 }
2111
2112 krb5_error_code
2113 krb5_string_to_enctype(krb5_context context,
2114                        const char *string,
2115                        krb5_enctype *etype)
2116 {
2117     int i;
2118     for(i = 0; i < num_etypes; i++)
2119         if(strcasecmp(etypes[i]->name, string) == 0){
2120             *etype = etypes[i]->type;
2121             return 0;
2122         }
2123     krb5_set_error_string (context, "encryption type %s not supported",
2124                            string);
2125     return KRB5_PROG_ETYPE_NOSUPP;
2126 }
2127
2128 krb5_error_code
2129 krb5_enctype_to_keytype(krb5_context context,
2130                         krb5_enctype etype,
2131                         krb5_keytype *keytype)
2132 {
2133     struct encryption_type *e = _find_enctype(etype);
2134     if(e == NULL) {
2135         krb5_set_error_string (context, "encryption type %d not supported",
2136                                etype);
2137         return KRB5_PROG_ETYPE_NOSUPP;
2138     }
2139     *keytype = e->keytype->type; /* XXX */
2140     return 0;
2141 }
2142
2143 #if 0
2144 krb5_error_code
2145 krb5_keytype_to_enctype(krb5_context context,
2146                         krb5_keytype keytype,
2147                         krb5_enctype *etype)
2148 {
2149     struct key_type *kt = _find_keytype(keytype);
2150     krb5_warnx(context, "krb5_keytype_to_enctype(%u)", keytype);
2151     if(kt == NULL)
2152         return KRB5_PROG_KEYTYPE_NOSUPP;
2153     *etype = kt->best_etype;
2154     return 0;
2155 }
2156 #endif
2157     
2158 krb5_error_code
2159 krb5_keytype_to_enctypes (krb5_context context,
2160                           krb5_keytype keytype,
2161                           unsigned *len,
2162                           krb5_enctype **val)
2163 {
2164     int i;
2165     unsigned n = 0;
2166     krb5_enctype *ret;
2167
2168     for (i = num_etypes - 1; i >= 0; --i) {
2169         if (etypes[i]->keytype->type == keytype
2170             && !(etypes[i]->flags & F_PSEUDO))
2171             ++n;
2172     }
2173     ret = malloc(n * sizeof(*ret));
2174     if (ret == NULL && n != 0) {
2175         krb5_set_error_string(context, "malloc: out of memory");
2176         return ENOMEM;
2177     }
2178     n = 0;
2179     for (i = num_etypes - 1; i >= 0; --i) {
2180         if (etypes[i]->keytype->type == keytype
2181             && !(etypes[i]->flags & F_PSEUDO))
2182             ret[n++] = etypes[i]->type;
2183     }
2184     *len = n;
2185     *val = ret;
2186     return 0;
2187 }
2188
2189 /*
2190  * First take the configured list of etypes for `keytype' if available,
2191  * else, do `krb5_keytype_to_enctypes'.
2192  */
2193
2194 krb5_error_code
2195 krb5_keytype_to_enctypes_default (krb5_context context,
2196                                   krb5_keytype keytype,
2197                                   unsigned *len,
2198                                   krb5_enctype **val)
2199 {
2200     int i, n;
2201     krb5_enctype *ret;
2202
2203     if (keytype != KEYTYPE_DES || context->etypes_des == NULL)
2204         return krb5_keytype_to_enctypes (context, keytype, len, val);
2205
2206     for (n = 0; context->etypes_des[n]; ++n)
2207         ;
2208     ret = malloc (n * sizeof(*ret));
2209     if (ret == NULL && n != 0) {
2210         krb5_set_error_string(context, "malloc: out of memory");
2211         return ENOMEM;
2212     }
2213     for (i = 0; i < n; ++i)
2214         ret[i] = context->etypes_des[i];
2215     *len = n;
2216     *val = ret;
2217     return 0;
2218 }
2219
2220 krb5_error_code
2221 krb5_enctype_valid(krb5_context context, 
2222                  krb5_enctype etype)
2223 {
2224     return _find_enctype(etype) != NULL;
2225 }
2226
2227 /* if two enctypes have compatible keys */
2228 krb5_boolean
2229 krb5_enctypes_compatible_keys(krb5_context context,
2230                               krb5_enctype etype1,
2231                               krb5_enctype etype2)
2232 {
2233     struct encryption_type *e1 = _find_enctype(etype1);
2234     struct encryption_type *e2 = _find_enctype(etype2);
2235     return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2236 }
2237
2238 static krb5_boolean
2239 derived_crypto(krb5_context context,
2240                krb5_crypto crypto)
2241 {
2242     return (crypto->et->flags & F_DERIVED) != 0;
2243 }
2244
2245 static krb5_boolean
2246 special_crypto(krb5_context context,
2247                krb5_crypto crypto)
2248 {
2249     return (crypto->et->flags & F_SPECIAL) != 0;
2250 }
2251
2252 #define CHECKSUMSIZE(C) ((C)->checksumsize)
2253 #define CHECKSUMTYPE(C) ((C)->type)
2254
2255 static krb5_error_code
2256 encrypt_internal_derived(krb5_context context,
2257                          krb5_crypto crypto,
2258                          unsigned usage,
2259                          void *data,
2260                          size_t len,
2261                          krb5_data *result,
2262                          void *ivec)
2263 {
2264     size_t sz, block_sz, checksum_sz, total_sz;
2265     Checksum cksum;
2266     unsigned char *p, *q;
2267     krb5_error_code ret;
2268     struct key_data *dkey;
2269     const struct encryption_type *et = crypto->et;
2270     
2271     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
2272
2273     sz = et->confoundersize + len;
2274     block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */
2275     total_sz = block_sz + checksum_sz;
2276     p = calloc(1, total_sz);
2277     if(p == NULL) {
2278         krb5_set_error_string(context, "malloc: out of memory");
2279         return ENOMEM;
2280     }
2281     
2282     q = p;
2283     krb5_generate_random_block(q, et->confoundersize); /* XXX */
2284     q += et->confoundersize;
2285     memcpy(q, data, len);
2286     
2287     ret = create_checksum(context, 
2288                           crypto, 
2289                           INTEGRITY_USAGE(usage),
2290                           et->keyed_checksum->type,
2291                           p, 
2292                           block_sz,
2293                           &cksum);
2294     if(ret == 0 && cksum.checksum.length != checksum_sz) {
2295         free_Checksum (&cksum);
2296         krb5_clear_error_string (context);
2297         ret = KRB5_CRYPTO_INTERNAL;
2298     }
2299     if(ret)
2300         goto fail;
2301     memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
2302     free_Checksum (&cksum);
2303     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
2304     if(ret)
2305         goto fail;
2306     ret = _key_schedule(context, dkey);
2307     if(ret)
2308         goto fail;
2309 #ifdef CRYPTO_DEBUG
2310     krb5_crypto_debug(context, 1, block_sz, dkey->key);
2311 #endif
2312     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
2313     if (ret)
2314         goto fail;
2315     result->data = p;
2316     result->length = total_sz;
2317     return 0;
2318  fail:
2319     memset(p, 0, total_sz);
2320     free(p);
2321     return ret;
2322 }
2323
2324
2325 static krb5_error_code
2326 encrypt_internal(krb5_context context,
2327                  krb5_crypto crypto,
2328                  void *data,
2329                  size_t len,
2330                  krb5_data *result,
2331                  void *ivec)
2332 {
2333     size_t sz, block_sz, checksum_sz;
2334     Checksum cksum;
2335     unsigned char *p, *q;
2336     krb5_error_code ret;
2337     const struct encryption_type *et = crypto->et;
2338     
2339     checksum_sz = CHECKSUMSIZE(et->checksum);
2340     
2341     sz = et->confoundersize + checksum_sz + len;
2342     block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */
2343     p = calloc(1, block_sz);
2344     if(p == NULL) {
2345         krb5_set_error_string(context, "malloc: out of memory");
2346         return ENOMEM;
2347     }
2348     
2349     q = p;
2350     krb5_generate_random_block(q, et->confoundersize); /* XXX */
2351     q += et->confoundersize;
2352     memset(q, 0, checksum_sz);
2353     q += checksum_sz;
2354     memcpy(q, data, len);
2355
2356     ret = create_checksum(context, 
2357                           crypto,
2358                           0,
2359                           et->checksum->type,
2360                           p, 
2361                           block_sz,
2362                           &cksum);
2363     if(ret == 0 && cksum.checksum.length != checksum_sz) {
2364         krb5_clear_error_string (context);
2365         free_Checksum(&cksum);
2366         ret = KRB5_CRYPTO_INTERNAL;
2367     }
2368     if(ret)
2369         goto fail;
2370     memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
2371     free_Checksum(&cksum);
2372     ret = _key_schedule(context, &crypto->key);
2373     if(ret)
2374         goto fail;
2375 #ifdef CRYPTO_DEBUG
2376     krb5_crypto_debug(context, 1, block_sz, crypto->key.key);
2377 #endif
2378     ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
2379     if (ret) {
2380         memset(p, 0, block_sz);
2381         free(p);
2382         return ret;
2383     }
2384     result->data = p;
2385     result->length = block_sz;
2386     return 0;
2387  fail:
2388     memset(p, 0, block_sz);
2389     free(p);
2390     return ret;
2391 }
2392
2393 static krb5_error_code
2394 encrypt_internal_special(krb5_context context,
2395                          krb5_crypto crypto,
2396                          int usage,
2397                          void *data,
2398                          size_t len,
2399                          krb5_data *result,
2400                          void *ivec)
2401 {
2402     struct encryption_type *et = crypto->et;
2403     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
2404     size_t sz = len + cksum_sz + et->confoundersize;
2405     char *tmp, *p;
2406     krb5_error_code ret;
2407
2408     tmp = malloc (sz);
2409     if (tmp == NULL) {
2410         krb5_set_error_string(context, "malloc: out of memory");
2411         return ENOMEM;
2412     }
2413     p = tmp;
2414     memset (p, 0, cksum_sz);
2415     p += cksum_sz;
2416     krb5_generate_random_block(p, et->confoundersize);
2417     p += et->confoundersize;
2418     memcpy (p, data, len);
2419     ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
2420     if (ret) {
2421         memset(tmp, 0, sz);
2422         free(tmp);
2423         return ret;
2424     }
2425     result->data   = tmp;
2426     result->length = sz;
2427     return 0;
2428 }
2429
2430 static krb5_error_code
2431 decrypt_internal_derived(krb5_context context,
2432                          krb5_crypto crypto,
2433                          unsigned usage,
2434                          void *data,
2435                          size_t len,
2436                          krb5_data *result,
2437                          void *ivec)
2438 {
2439     size_t checksum_sz;
2440     Checksum cksum;
2441     unsigned char *p;
2442     krb5_error_code ret;
2443     struct key_data *dkey;
2444     struct encryption_type *et = crypto->et;
2445     unsigned long l;
2446     
2447     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
2448     if (len < checksum_sz) {
2449         krb5_clear_error_string (context);
2450         return EINVAL;          /* XXX - better error code? */
2451     }
2452
2453     p = malloc(len);
2454     if(len != 0 && p == NULL) {
2455         krb5_set_error_string(context, "malloc: out of memory");
2456         return ENOMEM;
2457     }
2458     memcpy(p, data, len);
2459
2460     len -= checksum_sz;
2461
2462     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
2463     if(ret) {
2464         free(p);
2465         return ret;
2466     }
2467     ret = _key_schedule(context, dkey);
2468     if(ret) {
2469         free(p);
2470         return ret;
2471     }
2472 #ifdef CRYPTO_DEBUG
2473     krb5_crypto_debug(context, 0, len, dkey->key);
2474 #endif
2475     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
2476     if (ret) {
2477         free(p);
2478         return ret;
2479     }
2480
2481     cksum.checksum.data   = p + len;
2482     cksum.checksum.length = checksum_sz;
2483     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
2484
2485     ret = verify_checksum(context,
2486                           crypto,
2487                           INTEGRITY_USAGE(usage),
2488                           p,
2489                           len,
2490                           &cksum);
2491     if(ret) {
2492         free(p);
2493         return ret;
2494     }
2495     l = len - et->confoundersize;
2496     memmove(p, p + et->confoundersize, l);
2497     result->data = realloc(p, l);
2498     if(result->data == NULL) {
2499         free(p);
2500         krb5_set_error_string(context, "malloc: out of memory");
2501         return ENOMEM;
2502     }
2503     result->length = l;
2504     return 0;
2505 }
2506
2507 static krb5_error_code
2508 decrypt_internal(krb5_context context,
2509                  krb5_crypto crypto,
2510                  void *data,
2511                  size_t len,
2512                  krb5_data *result,
2513                  void *ivec)
2514 {
2515     krb5_error_code ret;
2516     unsigned char *p;
2517     Checksum cksum;
2518     size_t checksum_sz, l;
2519     struct encryption_type *et = crypto->et;
2520     
2521     checksum_sz = CHECKSUMSIZE(et->checksum);
2522     p = malloc(len);
2523     if(len != 0 && p == NULL) {
2524         krb5_set_error_string(context, "malloc: out of memory");
2525         return ENOMEM;
2526     }
2527     memcpy(p, data, len);
2528     
2529     ret = _key_schedule(context, &crypto->key);
2530     if(ret) {
2531         free(p);
2532         return ret;
2533     }
2534 #ifdef CRYPTO_DEBUG
2535     krb5_crypto_debug(context, 0, len, crypto->key.key);
2536 #endif
2537     ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
2538     if (ret) {
2539         free(p);
2540         return ret;
2541     }
2542     ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
2543     if(ret) {
2544         free(p);
2545         return ret;
2546     }
2547     memset(p + et->confoundersize, 0, checksum_sz);
2548     cksum.cksumtype = CHECKSUMTYPE(et->checksum);
2549     ret = verify_checksum(context, NULL, 0, p, len, &cksum);
2550     free_Checksum(&cksum);
2551     if(ret) {
2552         free(p);
2553         return ret;
2554     }
2555     l = len - et->confoundersize - checksum_sz;
2556     memmove(p, p + et->confoundersize + checksum_sz, l);
2557     result->data = realloc(p, l);
2558     if(result->data == NULL) {
2559         free(p);
2560         krb5_set_error_string(context, "malloc: out of memory");
2561         return ENOMEM;
2562     }
2563     result->length = l;
2564     return 0;
2565 }
2566
2567 static krb5_error_code
2568 decrypt_internal_special(krb5_context context,
2569                          krb5_crypto crypto,
2570                          int usage,
2571                          void *data,
2572                          size_t len,
2573                          krb5_data *result,
2574                          void *ivec)
2575 {
2576     struct encryption_type *et = crypto->et;
2577     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
2578     size_t sz = len - cksum_sz - et->confoundersize;
2579     char *cdata = (char *)data;
2580     char *tmp;
2581     krb5_error_code ret;
2582
2583     tmp = malloc (sz);
2584     if (tmp == NULL) {
2585         krb5_set_error_string(context, "malloc: out of memory");
2586         return ENOMEM;
2587     }
2588     
2589     ret = (*et->encrypt)(context, &crypto->key, data, len, FALSE, usage, ivec);
2590     if (ret) {
2591         free(tmp);
2592         return ret;
2593     }
2594
2595     memcpy (tmp, cdata + cksum_sz + et->confoundersize, sz);
2596
2597     result->data   = tmp;
2598     result->length = sz;
2599     return 0;
2600 }
2601
2602
2603 krb5_error_code
2604 krb5_encrypt_ivec(krb5_context context,
2605                   krb5_crypto crypto,
2606                   unsigned usage,
2607                   void *data,
2608                   size_t len,
2609                   krb5_data *result,
2610                   void *ivec)
2611 {
2612     if(derived_crypto(context, crypto))
2613         return encrypt_internal_derived(context, crypto, usage, 
2614                                         data, len, result, ivec);
2615     else if (special_crypto(context, crypto))
2616         return encrypt_internal_special (context, crypto, usage,
2617                                          data, len, result, ivec);
2618     else
2619         return encrypt_internal(context, crypto, data, len, result, ivec);
2620 }
2621
2622 krb5_error_code
2623 krb5_encrypt(krb5_context context,
2624              krb5_crypto crypto,
2625              unsigned usage,
2626              void *data,
2627              size_t len,
2628              krb5_data *result)
2629 {
2630     return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
2631 }
2632
2633 krb5_error_code
2634 krb5_encrypt_EncryptedData(krb5_context context,
2635                            krb5_crypto crypto,
2636                            unsigned usage,
2637                            void *data,
2638                            size_t len,
2639                            int kvno,
2640                            EncryptedData *result)
2641 {
2642     result->etype = CRYPTO_ETYPE(crypto);
2643     if(kvno){
2644         ALLOC(result->kvno, 1);
2645         *result->kvno = kvno;
2646     }else
2647         result->kvno = NULL;
2648     return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
2649 }
2650
2651 krb5_error_code
2652 krb5_decrypt_ivec(krb5_context context,
2653                   krb5_crypto crypto,
2654                   unsigned usage,
2655                   void *data,
2656                   size_t len,
2657                   krb5_data *result,
2658                   void *ivec)
2659 {
2660     if(derived_crypto(context, crypto))
2661         return decrypt_internal_derived(context, crypto, usage, 
2662                                         data, len, result, ivec);
2663     else if (special_crypto (context, crypto))
2664         return decrypt_internal_special(context, crypto, usage,
2665                                         data, len, result, ivec);
2666     else
2667         return decrypt_internal(context, crypto, data, len, result, ivec);
2668 }
2669
2670 krb5_error_code
2671 krb5_decrypt(krb5_context context,
2672              krb5_crypto crypto,
2673              unsigned usage,
2674              void *data,
2675              size_t len,
2676              krb5_data *result)
2677 {
2678     return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
2679                               NULL);
2680 }
2681
2682 krb5_error_code
2683 krb5_decrypt_EncryptedData(krb5_context context,
2684                            krb5_crypto crypto,
2685                            unsigned usage,
2686                            const EncryptedData *e,
2687                            krb5_data *result)
2688 {
2689     return krb5_decrypt(context, crypto, usage, 
2690                         e->cipher.data, e->cipher.length, result);
2691 }
2692
2693 /************************************************************
2694  *                                                          *
2695  ************************************************************/
2696
2697 #ifdef HAVE_OPENSSL
2698 #include <openssl/rand.h>
2699
2700 /* From openssl/crypto/rand/rand_lcl.h */
2701 #define ENTROPY_NEEDED 20
2702 static int
2703 seed_something(void)
2704 {
2705     int fd = -1;
2706     char buf[1024], seedfile[256];
2707
2708     /* If there is a seed file, load it. But such a file cannot be trusted,
2709        so use 0 for the entropy estimate */
2710     if (RAND_file_name(seedfile, sizeof(seedfile))) {
2711         fd = open(seedfile, O_RDONLY);
2712         if (fd >= 0) {
2713             read(fd, buf, sizeof(buf));
2714             /* Use the full buffer anyway */
2715             RAND_add(buf, sizeof(buf), 0.0);
2716         } else
2717             seedfile[0] = '\0';
2718     } else
2719         seedfile[0] = '\0';
2720
2721     /* Calling RAND_status() will try to use /dev/urandom if it exists so
2722        we do not have to deal with it. */
2723     if (RAND_status() != 1) {
2724         krb5_context context;
2725         const char *p;
2726
2727         /* Try using egd */
2728         if (!krb5_init_context(&context)) {
2729             p = krb5_config_get_string(context, NULL, "libdefaults",
2730                 "egd_socket", NULL);
2731             if (p != NULL)
2732                 RAND_egd_bytes(p, ENTROPY_NEEDED);
2733             krb5_free_context(context);
2734         }
2735     }
2736     
2737     if (RAND_status() == 1)     {
2738         /* Update the seed file */
2739         if (seedfile[0])
2740             RAND_write_file(seedfile);
2741
2742         return 0;
2743     } else
2744         return -1;
2745 }
2746
2747 void
2748 krb5_generate_random_block(void *buf, size_t len)
2749 {
2750     static int rng_initialized = 0;
2751     
2752     if (!rng_initialized) {
2753         if (seed_something())
2754             krb5_abortx(NULL, "Fatal: could not seed the random number generator");
2755         
2756         rng_initialized = 1;
2757     }
2758     RAND_bytes(buf, len);
2759 }
2760
2761 #else
2762
2763 void
2764 krb5_generate_random_block(void *buf, size_t len)
2765 {
2766     des_cblock key, out;
2767     static des_cblock counter;
2768     static des_key_schedule schedule;
2769     int i;
2770     static int initialized = 0;
2771
2772     if(!initialized) {
2773         des_new_random_key(&key);
2774         des_set_key(&key, schedule);
2775         memset(&key, 0, sizeof(key));
2776         des_new_random_key(&counter);
2777     }
2778     while(len > 0) {
2779         des_ecb_encrypt(&counter, &out, schedule, DES_ENCRYPT);
2780         for(i = 7; i >=0; i--)
2781             if(counter[i]++)
2782                 break;
2783         memcpy(buf, out, min(len, sizeof(out)));
2784         len -= min(len, sizeof(out));
2785         buf = (char*)buf + sizeof(out);
2786     }
2787 }
2788 #endif
2789
2790 static void
2791 DES3_postproc(krb5_context context,
2792               unsigned char *k, size_t len, struct key_data *key)
2793 {
2794     unsigned char x[24];
2795     int i, j;
2796
2797     memset(x, 0, sizeof(x));
2798     for (i = 0; i < 3; ++i) {
2799         unsigned char foo;
2800
2801         for (j = 0; j < 7; ++j) {
2802             unsigned char b = k[7 * i + j];
2803
2804             x[8 * i + j] = b;
2805         }
2806         foo = 0;
2807         for (j = 6; j >= 0; --j) {
2808             foo |= k[7 * i + j] & 1;
2809             foo <<= 1;
2810         }
2811         x[8 * i + 7] = foo;
2812     }
2813     k = key->key->keyvalue.data;
2814     memcpy(k, x, 24);
2815     memset(x, 0, sizeof(x));
2816     if (key->schedule) {
2817         krb5_free_data(context, key->schedule);
2818         key->schedule = NULL;
2819     }
2820     des_set_odd_parity((des_cblock*)k);
2821     des_set_odd_parity((des_cblock*)(k + 8));
2822     des_set_odd_parity((des_cblock*)(k + 16));
2823 }
2824
2825 static krb5_error_code
2826 derive_key(krb5_context context,
2827            struct encryption_type *et,
2828            struct key_data *key,
2829            const void *constant,
2830            size_t len)
2831 {
2832     unsigned char *k;
2833     unsigned int nblocks = 0, i;
2834     krb5_error_code ret = 0;
2835     
2836     struct key_type *kt = et->keytype;
2837     ret = _key_schedule(context, key);
2838     if(ret)
2839         return ret;
2840     if(et->blocksize * 8 < kt->bits || 
2841        len != et->blocksize) {
2842         nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
2843         k = malloc(nblocks * et->blocksize);
2844         if(k == NULL) {
2845             krb5_set_error_string(context, "malloc: out of memory");
2846             return ENOMEM;
2847         }
2848         _krb5_n_fold(constant, len, k, et->blocksize);
2849         for(i = 0; i < nblocks; i++) {
2850             if(i > 0)
2851                 memcpy(k + i * et->blocksize, 
2852                        k + (i - 1) * et->blocksize,
2853                        et->blocksize);
2854             (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
2855                            1, 0, NULL);
2856         }
2857     } else {
2858         /* this case is probably broken, but won't be run anyway */
2859         void *c = malloc(len);
2860         size_t res_len = (kt->bits + 7) / 8;
2861
2862         if(len != 0 && c == NULL) {
2863             krb5_set_error_string(context, "malloc: out of memory");
2864             return ENOMEM;
2865         }
2866         memcpy(c, constant, len);
2867         (*et->encrypt)(context, key, c, len, 1, 0, NULL);
2868         k = malloc(res_len);
2869         if(res_len != 0 && k == NULL) {
2870             free(c);
2871             krb5_set_error_string(context, "malloc: out of memory");
2872             return ENOMEM;
2873         }
2874         _krb5_n_fold(c, len, k, res_len);
2875         free(c);
2876     }
2877     
2878     /* XXX keytype dependent post-processing */
2879     switch(kt->type) {
2880     case KEYTYPE_DES3:
2881         DES3_postproc(context, k, nblocks * et->blocksize, key);
2882         break;
2883     default:
2884         krb5_set_error_string(context,
2885                               "derive_key() called with unknown keytype (%u)", 
2886                               kt->type);
2887         ret = KRB5_CRYPTO_INTERNAL;
2888         break;
2889     }
2890     memset(k, 0, nblocks * et->blocksize);
2891     free(k);
2892     return ret;
2893 }
2894
2895 static struct key_data *
2896 _new_derived_key(krb5_crypto crypto, unsigned usage)
2897 {
2898     struct key_usage *d = crypto->key_usage;
2899     d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
2900     if(d == NULL)
2901         return NULL;
2902     crypto->key_usage = d;
2903     d += crypto->num_key_usage++;
2904     memset(d, 0, sizeof(*d));
2905     d->usage = usage;
2906     return &d->key;
2907 }
2908
2909 krb5_error_code
2910 krb5_derive_key(krb5_context context,
2911                 const krb5_keyblock *key,
2912                 krb5_enctype etype,
2913                 const void *constant,
2914                 size_t constant_len,
2915                 krb5_keyblock **derived_key)
2916 {
2917     krb5_error_code ret;
2918     struct encryption_type *et;
2919     struct key_data d;
2920
2921     et = _find_enctype (etype);
2922     if (et == NULL) {
2923         krb5_set_error_string(context, "encryption type %d not supported",
2924                               etype);
2925         return KRB5_PROG_ETYPE_NOSUPP;
2926     }
2927
2928     ret = krb5_copy_keyblock(context, key, derived_key);
2929     if (ret)
2930         return ret;
2931
2932     d.key = *derived_key;
2933     d.schedule = NULL;
2934     ret = derive_key(context, et, &d, constant, constant_len);
2935     if (ret)
2936         return ret;
2937     ret = krb5_copy_keyblock(context, d.key, derived_key);
2938     return ret;
2939 }
2940
2941 static krb5_error_code
2942 _get_derived_key(krb5_context context, 
2943                  krb5_crypto crypto, 
2944                  unsigned usage, 
2945                  struct key_data **key)
2946 {
2947     int i;
2948     struct key_data *d;
2949     unsigned char constant[5];
2950
2951     for(i = 0; i < crypto->num_key_usage; i++)
2952         if(crypto->key_usage[i].usage == usage) {
2953             *key = &crypto->key_usage[i].key;
2954             return 0;
2955         }
2956     d = _new_derived_key(crypto, usage);
2957     if(d == NULL) {
2958         krb5_set_error_string(context, "malloc: out of memory");
2959         return ENOMEM;
2960     }
2961     krb5_copy_keyblock(context, crypto->key.key, &d->key);
2962     _krb5_put_int(constant, usage, 5);
2963     derive_key(context, crypto->et, d, constant, sizeof(constant));
2964     *key = d;
2965     return 0;
2966 }
2967
2968
2969 krb5_error_code
2970 krb5_crypto_init(krb5_context context,
2971                  const krb5_keyblock *key,
2972                  krb5_enctype etype,
2973                  krb5_crypto *crypto)
2974 {
2975     krb5_error_code ret;
2976     ALLOC(*crypto, 1);
2977     if(*crypto == NULL) {
2978         krb5_set_error_string(context, "malloc: out of memory");
2979         return ENOMEM;
2980     }
2981     if(etype == ETYPE_NULL)
2982         etype = key->keytype;
2983     (*crypto)->et = _find_enctype(etype);
2984     if((*crypto)->et == NULL) {
2985         free(*crypto);
2986         krb5_set_error_string (context, "encryption type %d not supported",
2987                                etype);
2988         return KRB5_PROG_ETYPE_NOSUPP;
2989     }
2990     if((*crypto)->et->keytype->size != key->keyvalue.length) {
2991         free(*crypto);
2992         krb5_set_error_string (context, "encryption key has bad length");
2993         return KRB5_BAD_KEYSIZE;
2994     }
2995     ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2996     if(ret) {
2997         free(*crypto);
2998         return ret;
2999     }
3000     (*crypto)->key.schedule = NULL;
3001     (*crypto)->num_key_usage = 0;
3002     (*crypto)->key_usage = NULL;
3003     return 0;
3004 }
3005
3006 static void
3007 free_key_data(krb5_context context, struct key_data *key)
3008 {
3009     krb5_free_keyblock(context, key->key);
3010     if(key->schedule) {
3011         memset(key->schedule->data, 0, key->schedule->length);
3012         krb5_free_data(context, key->schedule);
3013     }
3014 }
3015
3016 static void
3017 free_key_usage(krb5_context context, struct key_usage *ku)
3018 {
3019     free_key_data(context, &ku->key);
3020 }
3021
3022 krb5_error_code
3023 krb5_crypto_destroy(krb5_context context,
3024                     krb5_crypto crypto)
3025 {
3026     int i;
3027     
3028     for(i = 0; i < crypto->num_key_usage; i++)
3029         free_key_usage(context, &crypto->key_usage[i]);
3030     free(crypto->key_usage);
3031     free_key_data(context, &crypto->key);
3032     free (crypto);
3033     return 0;
3034 }
3035
3036 krb5_error_code
3037 krb5_crypto_getblocksize(krb5_context context,
3038                          krb5_crypto crypto,
3039                          size_t *blocksize)
3040 {
3041     *blocksize = crypto->et->blocksize;
3042     return 0;
3043 }
3044
3045 krb5_error_code
3046 krb5_string_to_key_derived(krb5_context context,
3047                            const void *str,
3048                            size_t len,
3049                            krb5_enctype etype,
3050                            krb5_keyblock *key)
3051 {
3052     struct encryption_type *et = _find_enctype(etype);
3053     krb5_error_code ret;
3054     struct key_data kd;
3055     size_t keylen = et->keytype->bits / 8;
3056     u_char *tmp;
3057
3058     if(et == NULL) {
3059         krb5_set_error_string (context, "encryption type %d not supported",
3060                                etype);
3061         return KRB5_PROG_ETYPE_NOSUPP;
3062     }
3063     ALLOC(kd.key, 1);
3064     if(kd.key == NULL) {
3065         krb5_set_error_string (context, "malloc: out of memory");
3066         return ENOMEM;
3067     }
3068     ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
3069     if(ret) {
3070         free(kd.key);
3071         return ret;
3072     }
3073     kd.key->keytype = etype;
3074     tmp = malloc (keylen);
3075     if(tmp == NULL) {
3076         krb5_free_keyblock(context, kd.key);
3077         krb5_set_error_string (context, "malloc: out of memory");
3078         return ENOMEM;
3079     }
3080     _krb5_n_fold(str, len, tmp, keylen);
3081     kd.schedule = NULL;
3082     DES3_postproc (context, tmp, keylen, &kd); /* XXX */
3083     memset(tmp, 0, keylen);
3084     free(tmp);
3085     ret = derive_key(context, 
3086                      et,
3087                      &kd,
3088                      "kerberos", /* XXX well known constant */
3089                      strlen("kerberos"));
3090     ret = krb5_copy_keyblock_contents(context, kd.key, key);
3091     free_key_data(context, &kd);
3092     return ret;
3093 }
3094
3095 static size_t
3096 wrapped_length (krb5_context context,
3097                 krb5_crypto  crypto,
3098                 size_t       data_len)
3099 {
3100     struct encryption_type *et = crypto->et;
3101     size_t blocksize = et->blocksize;
3102     size_t res;
3103
3104     res =  et->confoundersize + et->checksum->checksumsize + data_len;
3105     res =  (res + blocksize - 1) / blocksize * blocksize;
3106     return res;
3107 }
3108
3109 static size_t
3110 wrapped_length_dervied (krb5_context context,
3111                         krb5_crypto  crypto,
3112                         size_t       data_len)
3113 {
3114     struct encryption_type *et = crypto->et;
3115     size_t blocksize = et->blocksize;
3116     size_t res;
3117
3118     res =  et->confoundersize + data_len;
3119     res =  (res + blocksize - 1) / blocksize * blocksize;
3120     res += et->checksum->checksumsize;
3121     return res;
3122 }
3123
3124 /*
3125  * Return the size of an encrypted packet of length `data_len'
3126  */
3127
3128 size_t
3129 krb5_get_wrapped_length (krb5_context context,
3130                          krb5_crypto  crypto,
3131                          size_t       data_len)
3132 {
3133     if (derived_crypto (context, crypto))
3134         return wrapped_length_dervied (context, crypto, data_len);
3135     else
3136         return wrapped_length (context, crypto, data_len);
3137 }
3138
3139 #ifdef CRYPTO_DEBUG
3140
3141 static krb5_error_code
3142 krb5_get_keyid(krb5_context context,
3143                krb5_keyblock *key,
3144                u_int32_t *keyid)
3145 {
3146     MD5_CTX md5;
3147     unsigned char tmp[16];
3148
3149     MD5_Init (&md5);
3150     MD5_Update (&md5, key->keyvalue.data, key->keyvalue.length);
3151     MD5_Final (tmp, &md5);
3152     *keyid = (tmp[12] << 24) | (tmp[13] << 16) | (tmp[14] << 8) | tmp[15];
3153     return 0;
3154 }
3155
3156 static void
3157 krb5_crypto_debug(krb5_context context,
3158                   int encrypt,
3159                   size_t len,
3160                   krb5_keyblock *key)
3161 {
3162     u_int32_t keyid;
3163     char *kt;
3164     krb5_get_keyid(context, key, &keyid);
3165     krb5_enctype_to_string(context, key->keytype, &kt);
3166     krb5_warnx(context, "%s %lu bytes with key-id %#x (%s)", 
3167                encrypt ? "encrypting" : "decrypting",
3168                (unsigned long)len,
3169                keyid,
3170                kt);
3171     free(kt);
3172 }
3173
3174 #endif /* CRYPTO_DEBUG */
3175
3176 #if 0
3177 int
3178 main()
3179 {
3180 #if 0
3181     int i;
3182     krb5_context context;
3183     krb5_crypto crypto;
3184     struct key_data *d;
3185     krb5_keyblock key;
3186     char constant[4];
3187     unsigned usage = ENCRYPTION_USAGE(3);
3188     krb5_error_code ret;
3189
3190     ret = krb5_init_context(&context);
3191     if (ret)
3192         errx (1, "krb5_init_context failed: %d", ret);
3193
3194     key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
3195     key.keyvalue.data = "\xb3\x85\x58\x94\xd9\xdc\x7c\xc8"
3196         "\x25\xe9\x85\xab\x3e\xb5\xfb\x0e"
3197         "\xc8\xdf\xab\x26\x86\x64\x15\x25";
3198     key.keyvalue.length = 24;
3199
3200     krb5_crypto_init(context, &key, 0, &crypto);
3201
3202     d = _new_derived_key(crypto, usage);
3203     if(d == NULL)
3204         return ENOMEM;
3205     krb5_copy_keyblock(context, crypto->key.key, &d->key);
3206     _krb5_put_int(constant, usage, 4);
3207     derive_key(context, crypto->et, d, constant, sizeof(constant));
3208     return 0;
3209 #else
3210     int i;
3211     krb5_context context;
3212     krb5_crypto crypto;
3213     struct key_data *d;
3214     krb5_keyblock key;
3215     krb5_error_code ret;
3216     Checksum res;
3217
3218     char *data = "what do ya want for nothing?";
3219
3220     ret = krb5_init_context(&context);
3221     if (ret)
3222         errx (1, "krb5_init_context failed: %d", ret);
3223
3224     key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
3225     key.keyvalue.data = "Jefe";
3226     /* "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
3227        "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; */
3228     key.keyvalue.length = 4;
3229
3230     d = calloc(1, sizeof(*d));
3231
3232     d->key = &key;
3233     res.checksum.length = 20;
3234     res.checksum.data = malloc(res.checksum.length);
3235     HMAC_SHA1_DES3_checksum(context, d, data, 28, &res);
3236
3237     return 0;
3238 #endif
3239 }
3240 #endif