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