]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/krb5/crypto.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / krb5 / crypto.c
1 /*
2  * Copyright (c) 1997 - 2005 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 22200 2007-12-07 13:48:01Z lha $");
36 /* RCSID("$FreeBSD$"); */
37
38 #undef CRYPTO_DEBUG
39 #ifdef CRYPTO_DEBUG
40 static void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*);
41 #endif
42
43
44 struct key_data {
45     krb5_keyblock *key;
46     krb5_data *schedule;
47 };
48
49 struct key_usage {
50     unsigned usage;
51     struct key_data key;
52 };
53
54 struct krb5_crypto_data {
55     struct encryption_type *et;
56     struct key_data key;
57     int num_key_usage;
58     struct key_usage *key_usage;
59 };
60
61 #define CRYPTO_ETYPE(C) ((C)->et->type)
62
63 /* bits for `flags' below */
64 #define F_KEYED          1      /* checksum is keyed */
65 #define F_CPROOF         2      /* checksum is collision proof */
66 #define F_DERIVED        4      /* uses derived keys */
67 #define F_VARIANT        8      /* uses `variant' keys (6.4.3) */
68 #define F_PSEUDO        16      /* not a real protocol type */
69 #define F_SPECIAL       32      /* backwards */
70 #define F_DISABLED      64      /* enctype/checksum disabled */
71
72 struct salt_type {
73     krb5_salttype type;
74     const char *name;
75     krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data, 
76                                      krb5_salt, krb5_data, krb5_keyblock*);
77 };
78
79 struct key_type {
80     krb5_keytype type; /* XXX */
81     const char *name;
82     size_t bits;
83     size_t size;
84     size_t schedule_size;
85 #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     void (*random_to_key)(krb5_context, krb5_keyblock*, const void*, size_t);
92 };
93
94 struct checksum_type {
95     krb5_cksumtype type;
96     const char *name;
97     size_t blocksize;
98     size_t checksumsize;
99     unsigned flags;
100     void (*checksum)(krb5_context context,
101                      struct key_data *key,
102                      const void *buf, size_t len,
103                      unsigned usage,
104                      Checksum *csum);
105     krb5_error_code (*verify)(krb5_context context,
106                               struct key_data *key,
107                               const void *buf, size_t len,
108                               unsigned usage,
109                               Checksum *csum);
110 };
111
112 struct encryption_type {
113     krb5_enctype type;
114     const char *name;
115     heim_oid *oid;
116     size_t blocksize;
117     size_t padsize;
118     size_t confoundersize;
119     struct key_type *keytype;
120     struct checksum_type *checksum;
121     struct checksum_type *keyed_checksum;
122     unsigned flags;
123     krb5_error_code (*encrypt)(krb5_context context,
124                                struct key_data *key,
125                                void *data, size_t len,
126                                krb5_boolean encryptp,
127                                int usage,
128                                void *ivec);
129     size_t prf_length;
130     krb5_error_code (*prf)(krb5_context,
131                            krb5_crypto, const krb5_data *, krb5_data *);
132 };
133
134 #define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
135 #define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)
136 #define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)
137
138 static struct checksum_type *_find_checksum(krb5_cksumtype type);
139 static struct encryption_type *_find_enctype(krb5_enctype type);
140 static struct key_type *_find_keytype(krb5_keytype type);
141 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, 
142                                         unsigned, struct key_data**);
143 static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
144 static krb5_error_code derive_key(krb5_context context,
145                                   struct encryption_type *et,
146                                   struct key_data *key,
147                                   const void *constant,
148                                   size_t len);
149 static krb5_error_code hmac(krb5_context context,
150                             struct checksum_type *cm, 
151                             const void *data, 
152                             size_t len, 
153                             unsigned usage,
154                             struct key_data *keyblock,
155                             Checksum *result);
156 static void free_key_data(krb5_context context, struct key_data *key);
157 static krb5_error_code usage2arcfour (krb5_context, unsigned *);
158 static void xor (DES_cblock *, const unsigned char *);
159
160 /************************************************************
161  *                                                          *
162  ************************************************************/
163
164 static HEIMDAL_MUTEX crypto_mutex = HEIMDAL_MUTEX_INITIALIZER;
165
166
167 static void
168 krb5_DES_random_key(krb5_context context,
169                krb5_keyblock *key)
170 {
171     DES_cblock *k = key->keyvalue.data;
172     do {
173         krb5_generate_random_block(k, sizeof(DES_cblock));
174         DES_set_odd_parity(k);
175     } while(DES_is_weak_key(k));
176 }
177
178 static void
179 krb5_DES_schedule(krb5_context context,
180                   struct key_data *key)
181 {
182     DES_set_key(key->key->keyvalue.data, key->schedule->data);
183 }
184
185 #ifdef ENABLE_AFS_STRING_TO_KEY
186
187 /* This defines the Andrew string_to_key function.  It accepts a password
188  * string as input and converts it via a one-way encryption algorithm to a DES
189  * encryption key.  It is compatible with the original Andrew authentication
190  * service password database.
191  */
192
193 /*
194  * Short passwords, i.e 8 characters or less.
195  */
196 static void
197 krb5_DES_AFS3_CMU_string_to_key (krb5_data pw,
198                             krb5_data cell,
199                             DES_cblock *key)
200 {
201     char  password[8+1];        /* crypt is limited to 8 chars anyway */
202     int   i;
203     
204     for(i = 0; i < 8; i++) {
205         char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^
206                  ((i < cell.length) ?
207                   tolower(((unsigned char*)cell.data)[i]) : 0);
208         password[i] = c ? c : 'X';
209     }
210     password[8] = '\0';
211
212     memcpy(key, crypt(password, "p1") + 2, sizeof(DES_cblock));
213
214     /* parity is inserted into the LSB so left shift each byte up one
215        bit. This allows ascii characters with a zero MSB to retain as
216        much significance as possible. */
217     for (i = 0; i < sizeof(DES_cblock); i++)
218         ((unsigned char*)key)[i] <<= 1;
219     DES_set_odd_parity (key);
220 }
221
222 /*
223  * Long passwords, i.e 9 characters or more.
224  */
225 static void
226 krb5_DES_AFS3_Transarc_string_to_key (krb5_data pw,
227                                  krb5_data cell,
228                                  DES_cblock *key)
229 {
230     DES_key_schedule schedule;
231     DES_cblock temp_key;
232     DES_cblock ivec;
233     char password[512];
234     size_t passlen;
235
236     memcpy(password, pw.data, min(pw.length, sizeof(password)));
237     if(pw.length < sizeof(password)) {
238         int len = min(cell.length, sizeof(password) - pw.length);
239         int i;
240
241         memcpy(password + pw.length, cell.data, len);
242         for (i = pw.length; i < pw.length + len; ++i)
243             password[i] = tolower((unsigned char)password[i]);
244     }
245     passlen = min(sizeof(password), pw.length + cell.length);
246     memcpy(&ivec, "kerberos", 8);
247     memcpy(&temp_key, "kerberos", 8);
248     DES_set_odd_parity (&temp_key);
249     DES_set_key (&temp_key, &schedule);
250     DES_cbc_cksum ((void*)password, &ivec, passlen, &schedule, &ivec);
251
252     memcpy(&temp_key, &ivec, 8);
253     DES_set_odd_parity (&temp_key);
254     DES_set_key (&temp_key, &schedule);
255     DES_cbc_cksum ((void*)password, key, passlen, &schedule, &ivec);
256     memset(&schedule, 0, sizeof(schedule));
257     memset(&temp_key, 0, sizeof(temp_key));
258     memset(&ivec, 0, sizeof(ivec));
259     memset(password, 0, sizeof(password));
260
261     DES_set_odd_parity (key);
262 }
263
264 static krb5_error_code
265 DES_AFS3_string_to_key(krb5_context context,
266                        krb5_enctype enctype,
267                        krb5_data password,
268                        krb5_salt salt,
269                        krb5_data opaque,
270                        krb5_keyblock *key)
271 {
272     DES_cblock tmp;
273     if(password.length > 8)
274         krb5_DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp);
275     else
276         krb5_DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp);
277     key->keytype = enctype;
278     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
279     memset(&key, 0, sizeof(key));
280     return 0;
281 }
282 #endif /* ENABLE_AFS_STRING_TO_KEY */
283
284 static void
285 DES_string_to_key_int(unsigned char *data, size_t length, DES_cblock *key)
286 {
287     DES_key_schedule schedule;
288     int i;
289     int reverse = 0;
290     unsigned char *p;
291
292     unsigned char swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 
293                              0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
294     memset(key, 0, 8);
295     
296     p = (unsigned char*)key;
297     for (i = 0; i < length; i++) {
298         unsigned char tmp = data[i];
299         if (!reverse)
300             *p++ ^= (tmp << 1);
301         else
302             *--p ^= (swap[tmp & 0xf] << 4) | swap[(tmp & 0xf0) >> 4];
303         if((i % 8) == 7)
304             reverse = !reverse;
305     }
306     DES_set_odd_parity(key);
307     if(DES_is_weak_key(key))
308         (*key)[7] ^= 0xF0;
309     DES_set_key(key, &schedule);
310     DES_cbc_cksum((void*)data, key, length, &schedule, key);
311     memset(&schedule, 0, sizeof(schedule));
312     DES_set_odd_parity(key);
313     if(DES_is_weak_key(key))
314         (*key)[7] ^= 0xF0;
315 }
316
317 static krb5_error_code
318 krb5_DES_string_to_key(krb5_context context,
319                   krb5_enctype enctype,
320                   krb5_data password,
321                   krb5_salt salt,
322                   krb5_data opaque,
323                   krb5_keyblock *key)
324 {
325     unsigned char *s;
326     size_t len;
327     DES_cblock tmp;
328
329 #ifdef ENABLE_AFS_STRING_TO_KEY
330     if (opaque.length == 1) {
331         unsigned long v;
332         _krb5_get_int(opaque.data, &v, 1);
333         if (v == 1)
334             return DES_AFS3_string_to_key(context, enctype, password,
335                                           salt, opaque, key);
336     }
337 #endif
338
339     len = password.length + salt.saltvalue.length;
340     s = malloc(len);
341     if(len > 0 && s == NULL) {
342         krb5_set_error_string(context, "malloc: out of memory");
343         return ENOMEM;
344     }
345     memcpy(s, password.data, password.length);
346     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
347     DES_string_to_key_int(s, len, &tmp);
348     key->keytype = enctype;
349     krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
350     memset(&tmp, 0, sizeof(tmp));
351     memset(s, 0, len);
352     free(s);
353     return 0;
354 }
355
356 static void
357 krb5_DES_random_to_key(krb5_context context,
358                        krb5_keyblock *key,
359                        const void *data,
360                        size_t size)
361 {
362     DES_cblock *k = key->keyvalue.data;
363     memcpy(k, data, key->keyvalue.length);
364     DES_set_odd_parity(k);
365     if(DES_is_weak_key(k))
366         xor(k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
367 }
368
369 /*
370  *
371  */
372
373 static void
374 DES3_random_key(krb5_context context,
375                 krb5_keyblock *key)
376 {
377     DES_cblock *k = key->keyvalue.data;
378     do {
379         krb5_generate_random_block(k, 3 * sizeof(DES_cblock));
380         DES_set_odd_parity(&k[0]);
381         DES_set_odd_parity(&k[1]);
382         DES_set_odd_parity(&k[2]);
383     } while(DES_is_weak_key(&k[0]) ||
384             DES_is_weak_key(&k[1]) ||
385             DES_is_weak_key(&k[2]));
386 }
387
388 static void
389 DES3_schedule(krb5_context context,
390               struct key_data *key)
391 {
392     DES_cblock *k = key->key->keyvalue.data;
393     DES_key_schedule *s = key->schedule->data;
394     DES_set_key(&k[0], &s[0]);
395     DES_set_key(&k[1], &s[1]);
396     DES_set_key(&k[2], &s[2]);
397 }
398
399 /*
400  * A = A xor B. A & B are 8 bytes.
401  */
402
403 static void
404 xor (DES_cblock *key, const unsigned char *b)
405 {
406     unsigned char *a = (unsigned char*)key;
407     a[0] ^= b[0];
408     a[1] ^= b[1];
409     a[2] ^= b[2];
410     a[3] ^= b[3];
411     a[4] ^= b[4];
412     a[5] ^= b[5];
413     a[6] ^= b[6];
414     a[7] ^= b[7];
415 }
416
417 static krb5_error_code
418 DES3_string_to_key(krb5_context context,
419                    krb5_enctype enctype,
420                    krb5_data password,
421                    krb5_salt salt,
422                    krb5_data opaque,
423                    krb5_keyblock *key)
424 {
425     char *str;
426     size_t len;
427     unsigned char tmp[24];
428     DES_cblock keys[3];
429     krb5_error_code ret;
430     
431     len = password.length + salt.saltvalue.length;
432     str = malloc(len);
433     if(len != 0 && str == NULL) {
434         krb5_set_error_string(context, "malloc: out of memory");
435         return ENOMEM;
436     }
437     memcpy(str, password.data, password.length);
438     memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length);
439     {
440         DES_cblock ivec;
441         DES_key_schedule s[3];
442         int i;
443         
444         ret = _krb5_n_fold(str, len, tmp, 24);
445         if (ret) {
446             memset(str, 0, len);
447             free(str);
448             krb5_set_error_string(context, "out of memory");
449             return ret;
450         }
451         
452         for(i = 0; i < 3; i++){
453             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
454             DES_set_odd_parity(keys + i);
455             if(DES_is_weak_key(keys + i))
456                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
457             DES_set_key(keys + i, &s[i]);
458         }
459         memset(&ivec, 0, sizeof(ivec));
460         DES_ede3_cbc_encrypt(tmp,
461                              tmp, sizeof(tmp), 
462                              &s[0], &s[1], &s[2], &ivec, DES_ENCRYPT);
463         memset(s, 0, sizeof(s));
464         memset(&ivec, 0, sizeof(ivec));
465         for(i = 0; i < 3; i++){
466             memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
467             DES_set_odd_parity(keys + i);
468             if(DES_is_weak_key(keys + i))
469                 xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
470         }
471         memset(tmp, 0, sizeof(tmp));
472     }
473     key->keytype = enctype;
474     krb5_data_copy(&key->keyvalue, keys, sizeof(keys));
475     memset(keys, 0, sizeof(keys));
476     memset(str, 0, len);
477     free(str);
478     return 0;
479 }
480
481 static krb5_error_code
482 DES3_string_to_key_derived(krb5_context context,
483                            krb5_enctype enctype,
484                            krb5_data password,
485                            krb5_salt salt,
486                            krb5_data opaque,
487                            krb5_keyblock *key)
488 {
489     krb5_error_code ret;
490     size_t len = password.length + salt.saltvalue.length;
491     char *s;
492
493     s = malloc(len);
494     if(len != 0 && s == NULL) {
495         krb5_set_error_string(context, "malloc: out of memory");
496         return ENOMEM;
497     }
498     memcpy(s, password.data, password.length);
499     memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
500     ret = krb5_string_to_key_derived(context,
501                                      s,
502                                      len,
503                                      enctype,
504                                      key);
505     memset(s, 0, len);
506     free(s);
507     return ret;
508 }
509
510 static void
511 DES3_random_to_key(krb5_context context,
512                    krb5_keyblock *key,
513                    const void *data,
514                    size_t size)
515 {
516     unsigned char *x = key->keyvalue.data;
517     const u_char *q = data;
518     DES_cblock *k;
519     int i, j;
520
521     memset(x, 0, sizeof(x));
522     for (i = 0; i < 3; ++i) {
523         unsigned char foo;
524         for (j = 0; j < 7; ++j) {
525             unsigned char b = q[7 * i + j];
526
527             x[8 * i + j] = b;
528         }
529         foo = 0;
530         for (j = 6; j >= 0; --j) {
531             foo |= q[7 * i + j] & 1;
532             foo <<= 1;
533         }
534         x[8 * i + 7] = foo;
535     }
536     k = key->keyvalue.data;
537     for (i = 0; i < 3; i++) {
538         DES_set_odd_parity(&k[i]);
539         if(DES_is_weak_key(&k[i]))
540             xor(&k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0");
541     }    
542 }
543
544 /*
545  * ARCFOUR
546  */
547
548 static void
549 ARCFOUR_schedule(krb5_context context, 
550                  struct key_data *kd)
551 {
552     RC4_set_key (kd->schedule->data,
553                  kd->key->keyvalue.length, kd->key->keyvalue.data);
554 }
555
556 static krb5_error_code
557 ARCFOUR_string_to_key(krb5_context context,
558                   krb5_enctype enctype,
559                   krb5_data password,
560                   krb5_salt salt,
561                   krb5_data opaque,
562                   krb5_keyblock *key)
563 {
564     char *s, *p;
565     size_t len;
566     int i;
567     MD4_CTX m;
568     krb5_error_code ret;
569
570     len = 2 * password.length;
571     s = malloc (len);
572     if (len != 0 && s == NULL) {
573         krb5_set_error_string(context, "malloc: out of memory");
574         ret = ENOMEM;
575         goto out;
576     }
577     for (p = s, i = 0; i < password.length; ++i) {
578         *p++ = ((char *)password.data)[i];
579         *p++ = 0;
580     }
581     MD4_Init (&m);
582     MD4_Update (&m, s, len);
583     key->keytype = enctype;
584     ret = krb5_data_alloc (&key->keyvalue, 16);
585     if (ret) {
586         krb5_set_error_string(context, "malloc: out of memory");
587         goto out;
588     }
589     MD4_Final (key->keyvalue.data, &m);
590     memset (s, 0, len);
591     ret = 0;
592 out:
593     free (s);
594     return ret;
595 }
596
597 /*
598  * AES
599  */
600
601 int _krb5_AES_string_to_default_iterator = 4096;
602
603 static krb5_error_code
604 AES_string_to_key(krb5_context context,
605                   krb5_enctype enctype,
606                   krb5_data password,
607                   krb5_salt salt,
608                   krb5_data opaque,
609                   krb5_keyblock *key)
610 {
611     krb5_error_code ret;
612     uint32_t iter;
613     struct encryption_type *et;
614     struct key_data kd;
615
616     if (opaque.length == 0)
617         iter = _krb5_AES_string_to_default_iterator;
618     else if (opaque.length == 4) {
619         unsigned long v;
620         _krb5_get_int(opaque.data, &v, 4);
621         iter = ((uint32_t)v);
622     } else
623         return KRB5_PROG_KEYTYPE_NOSUPP; /* XXX */
624         
625     et = _find_enctype(enctype);
626     if (et == NULL)
627         return KRB5_PROG_KEYTYPE_NOSUPP;
628
629     kd.schedule = NULL;
630     ALLOC(kd.key, 1);
631     if(kd.key == NULL) {
632         krb5_set_error_string (context, "malloc: out of memory");
633         return ENOMEM;
634     }
635     kd.key->keytype = enctype;
636     ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
637     if (ret) {
638         krb5_set_error_string(context, "Failed to allocate pkcs5 key");
639         return ret;
640     }
641
642     ret = PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length,
643                                  salt.saltvalue.data, salt.saltvalue.length,
644                                  iter, 
645                                  et->keytype->size, kd.key->keyvalue.data);
646     if (ret != 1) {
647         free_key_data(context, &kd);
648         krb5_set_error_string(context, "Error calculating s2k");
649         return KRB5_PROG_KEYTYPE_NOSUPP;
650     }
651
652     ret = derive_key(context, et, &kd, "kerberos", strlen("kerberos"));
653     if (ret == 0)
654         ret = krb5_copy_keyblock_contents(context, kd.key, key);
655     free_key_data(context, &kd);
656
657     return ret;
658 }
659
660 struct krb5_aes_schedule {
661     AES_KEY ekey;
662     AES_KEY dkey;
663 };
664
665 static void
666 AES_schedule(krb5_context context,
667              struct key_data *kd)
668 {
669     struct krb5_aes_schedule *key = kd->schedule->data;
670     int bits = kd->key->keyvalue.length * 8;
671
672     memset(key, 0, sizeof(*key));
673     AES_set_encrypt_key(kd->key->keyvalue.data, bits, &key->ekey);
674     AES_set_decrypt_key(kd->key->keyvalue.data, bits, &key->dkey);
675 }
676
677 /*
678  *
679  */
680
681 static struct salt_type des_salt[] = {
682     {
683         KRB5_PW_SALT,
684         "pw-salt",
685         krb5_DES_string_to_key
686     },
687 #ifdef ENABLE_AFS_STRING_TO_KEY
688     {
689         KRB5_AFS3_SALT,
690         "afs3-salt",
691         DES_AFS3_string_to_key
692     },
693 #endif
694     { 0 }
695 };
696
697 static struct salt_type des3_salt[] = {
698     {
699         KRB5_PW_SALT,
700         "pw-salt",
701         DES3_string_to_key
702     },
703     { 0 }
704 };
705
706 static struct salt_type des3_salt_derived[] = {
707     {
708         KRB5_PW_SALT,
709         "pw-salt",
710         DES3_string_to_key_derived
711     },
712     { 0 }
713 };
714
715 static struct salt_type AES_salt[] = {
716     {
717         KRB5_PW_SALT,
718         "pw-salt",
719         AES_string_to_key
720     },
721     { 0 }
722 };
723
724 static struct salt_type arcfour_salt[] = {
725     {
726         KRB5_PW_SALT,
727         "pw-salt",
728         ARCFOUR_string_to_key
729     },
730     { 0 }
731 };
732
733 /*
734  *
735  */
736
737 static struct key_type keytype_null = {
738     KEYTYPE_NULL,
739     "null",
740     0,
741     0,
742     0,
743     NULL,
744     NULL,
745     NULL
746 };
747
748 static struct key_type keytype_des = {
749     KEYTYPE_DES,
750     "des",
751     56,
752     sizeof(DES_cblock),
753     sizeof(DES_key_schedule),
754     krb5_DES_random_key,
755     krb5_DES_schedule,
756     des_salt,
757     krb5_DES_random_to_key
758 };
759
760 static struct key_type keytype_des3 = {
761     KEYTYPE_DES3,
762     "des3",
763     168,
764     3 * sizeof(DES_cblock), 
765     3 * sizeof(DES_key_schedule), 
766     DES3_random_key,
767     DES3_schedule,
768     des3_salt,
769     DES3_random_to_key
770 };
771
772 static struct key_type keytype_des3_derived = {
773     KEYTYPE_DES3,
774     "des3",
775     168,
776     3 * sizeof(DES_cblock),
777     3 * sizeof(DES_key_schedule), 
778     DES3_random_key,
779     DES3_schedule,
780     des3_salt_derived,
781     DES3_random_to_key
782 };
783
784 static struct key_type keytype_aes128 = {
785     KEYTYPE_AES128,
786     "aes-128",
787     128,
788     16,
789     sizeof(struct krb5_aes_schedule),
790     NULL,
791     AES_schedule,
792     AES_salt
793 };
794
795 static struct key_type keytype_aes256 = {
796     KEYTYPE_AES256,
797     "aes-256",
798     256,
799     32,
800     sizeof(struct krb5_aes_schedule),
801     NULL,
802     AES_schedule,
803     AES_salt
804 };
805
806 static struct key_type keytype_arcfour = {
807     KEYTYPE_ARCFOUR,
808     "arcfour",
809     128,
810     16,
811     sizeof(RC4_KEY),
812     NULL,
813     ARCFOUR_schedule,
814     arcfour_salt
815 };
816
817 static struct key_type *keytypes[] = {
818     &keytype_null,
819     &keytype_des,
820     &keytype_des3_derived,
821     &keytype_des3,
822     &keytype_aes128,
823     &keytype_aes256,
824     &keytype_arcfour
825 };
826
827 static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]);
828
829 static struct key_type *
830 _find_keytype(krb5_keytype type)
831 {
832     int i;
833     for(i = 0; i < num_keytypes; i++)
834         if(keytypes[i]->type == type)
835             return keytypes[i];
836     return NULL;
837 }
838
839
840 krb5_error_code KRB5_LIB_FUNCTION
841 krb5_salttype_to_string (krb5_context context,
842                          krb5_enctype etype,
843                          krb5_salttype stype,
844                          char **string)
845 {
846     struct encryption_type *e;
847     struct salt_type *st;
848
849     e = _find_enctype (etype);
850     if (e == NULL) {
851         krb5_set_error_string(context, "encryption type %d not supported",
852                               etype);
853         return KRB5_PROG_ETYPE_NOSUPP;
854     }
855     for (st = e->keytype->string_to_key; st && st->type; st++) {
856         if (st->type == stype) {
857             *string = strdup (st->name);
858             if (*string == NULL) {
859                 krb5_set_error_string(context, "malloc: out of memory");
860                 return ENOMEM;
861             }
862             return 0;
863         }
864     }
865     krb5_set_error_string(context, "salttype %d not supported", stype);
866     return HEIM_ERR_SALTTYPE_NOSUPP;
867 }
868
869 krb5_error_code KRB5_LIB_FUNCTION
870 krb5_string_to_salttype (krb5_context context,
871                          krb5_enctype etype,
872                          const char *string,
873                          krb5_salttype *salttype)
874 {
875     struct encryption_type *e;
876     struct salt_type *st;
877
878     e = _find_enctype (etype);
879     if (e == NULL) {
880         krb5_set_error_string(context, "encryption type %d not supported",
881                               etype);
882         return KRB5_PROG_ETYPE_NOSUPP;
883     }
884     for (st = e->keytype->string_to_key; st && st->type; st++) {
885         if (strcasecmp (st->name, string) == 0) {
886             *salttype = st->type;
887             return 0;
888         }
889     }
890     krb5_set_error_string(context, "salttype %s not supported", string);
891     return HEIM_ERR_SALTTYPE_NOSUPP;
892 }
893
894 krb5_error_code KRB5_LIB_FUNCTION
895 krb5_get_pw_salt(krb5_context context,
896                  krb5_const_principal principal,
897                  krb5_salt *salt)
898 {
899     size_t len;
900     int i;
901     krb5_error_code ret;
902     char *p;
903      
904     salt->salttype = KRB5_PW_SALT;
905     len = strlen(principal->realm);
906     for (i = 0; i < principal->name.name_string.len; ++i)
907         len += strlen(principal->name.name_string.val[i]);
908     ret = krb5_data_alloc (&salt->saltvalue, len);
909     if (ret)
910         return ret;
911     p = salt->saltvalue.data;
912     memcpy (p, principal->realm, strlen(principal->realm));
913     p += strlen(principal->realm);
914     for (i = 0; i < principal->name.name_string.len; ++i) {
915         memcpy (p,
916                 principal->name.name_string.val[i],
917                 strlen(principal->name.name_string.val[i]));
918         p += strlen(principal->name.name_string.val[i]);
919     }
920     return 0;
921 }
922
923 krb5_error_code KRB5_LIB_FUNCTION
924 krb5_free_salt(krb5_context context, 
925                krb5_salt salt)
926 {
927     krb5_data_free(&salt.saltvalue);
928     return 0;
929 }
930
931 krb5_error_code KRB5_LIB_FUNCTION
932 krb5_string_to_key_data (krb5_context context,
933                          krb5_enctype enctype,
934                          krb5_data password,
935                          krb5_principal principal,
936                          krb5_keyblock *key)
937 {
938     krb5_error_code ret;
939     krb5_salt salt;
940
941     ret = krb5_get_pw_salt(context, principal, &salt);
942     if(ret)
943         return ret;
944     ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
945     krb5_free_salt(context, salt);
946     return ret;
947 }
948
949 krb5_error_code KRB5_LIB_FUNCTION
950 krb5_string_to_key (krb5_context context,
951                     krb5_enctype enctype,
952                     const char *password,
953                     krb5_principal principal,
954                     krb5_keyblock *key)
955 {
956     krb5_data pw;
957     pw.data = rk_UNCONST(password);
958     pw.length = strlen(password);
959     return krb5_string_to_key_data(context, enctype, pw, principal, key);
960 }
961
962 krb5_error_code KRB5_LIB_FUNCTION
963 krb5_string_to_key_data_salt (krb5_context context,
964                               krb5_enctype enctype,
965                               krb5_data password,
966                               krb5_salt salt,
967                               krb5_keyblock *key)
968 {
969     krb5_data opaque;
970     krb5_data_zero(&opaque);
971     return krb5_string_to_key_data_salt_opaque(context, enctype, password, 
972                                                salt, opaque, key);
973 }
974
975 /*
976  * Do a string -> key for encryption type `enctype' operation on
977  * `password' (with salt `salt' and the enctype specific data string
978  * `opaque'), returning the resulting key in `key'
979  */
980
981 krb5_error_code KRB5_LIB_FUNCTION
982 krb5_string_to_key_data_salt_opaque (krb5_context context,
983                                      krb5_enctype enctype,
984                                      krb5_data password,
985                                      krb5_salt salt,
986                                      krb5_data opaque,
987                                      krb5_keyblock *key)
988 {
989     struct encryption_type *et =_find_enctype(enctype);
990     struct salt_type *st;
991     if(et == NULL) {
992         krb5_set_error_string(context, "encryption type %d not supported",
993                               enctype);
994         return KRB5_PROG_ETYPE_NOSUPP;
995     }
996     for(st = et->keytype->string_to_key; st && st->type; st++) 
997         if(st->type == salt.salttype)
998             return (*st->string_to_key)(context, enctype, password, 
999                                         salt, opaque, key);
1000     krb5_set_error_string(context, "salt type %d not supported",
1001                           salt.salttype);
1002     return HEIM_ERR_SALTTYPE_NOSUPP;
1003 }
1004
1005 /*
1006  * Do a string -> key for encryption type `enctype' operation on the
1007  * string `password' (with salt `salt'), returning the resulting key
1008  * in `key'
1009  */
1010
1011 krb5_error_code KRB5_LIB_FUNCTION
1012 krb5_string_to_key_salt (krb5_context context,
1013                          krb5_enctype enctype,
1014                          const char *password,
1015                          krb5_salt salt,
1016                          krb5_keyblock *key)
1017 {
1018     krb5_data pw;
1019     pw.data = rk_UNCONST(password);
1020     pw.length = strlen(password);
1021     return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
1022 }
1023
1024 krb5_error_code KRB5_LIB_FUNCTION
1025 krb5_string_to_key_salt_opaque (krb5_context context,
1026                                 krb5_enctype enctype,
1027                                 const char *password,
1028                                 krb5_salt salt,
1029                                 krb5_data opaque,
1030                                 krb5_keyblock *key)
1031 {
1032     krb5_data pw;
1033     pw.data = rk_UNCONST(password);
1034     pw.length = strlen(password);
1035     return krb5_string_to_key_data_salt_opaque(context, enctype, 
1036                                                pw, salt, opaque, key);
1037 }
1038
1039 krb5_error_code KRB5_LIB_FUNCTION
1040 krb5_keytype_to_string(krb5_context context,
1041                        krb5_keytype keytype,
1042                        char **string)
1043 {
1044     struct key_type *kt = _find_keytype(keytype);
1045     if(kt == NULL) {
1046         krb5_set_error_string(context, "key type %d not supported", keytype);
1047         return KRB5_PROG_KEYTYPE_NOSUPP;
1048     }
1049     *string = strdup(kt->name);
1050     if(*string == NULL) {
1051         krb5_set_error_string(context, "malloc: out of memory");
1052         return ENOMEM;
1053     }
1054     return 0;
1055 }
1056
1057 krb5_error_code KRB5_LIB_FUNCTION
1058 krb5_string_to_keytype(krb5_context context,
1059                        const char *string,
1060                        krb5_keytype *keytype)
1061 {
1062     int i;
1063     for(i = 0; i < num_keytypes; i++)
1064         if(strcasecmp(keytypes[i]->name, string) == 0){
1065             *keytype = keytypes[i]->type;
1066             return 0;
1067         }
1068     krb5_set_error_string(context, "key type %s not supported", string);
1069     return KRB5_PROG_KEYTYPE_NOSUPP;
1070 }
1071
1072 krb5_error_code KRB5_LIB_FUNCTION
1073 krb5_enctype_keysize(krb5_context context,
1074                      krb5_enctype type,
1075                      size_t *keysize)
1076 {
1077     struct encryption_type *et = _find_enctype(type);
1078     if(et == NULL) {
1079         krb5_set_error_string(context, "encryption type %d not supported",
1080                               type);
1081         return KRB5_PROG_ETYPE_NOSUPP;
1082     }
1083     *keysize = et->keytype->size;
1084     return 0;
1085 }
1086
1087 krb5_error_code KRB5_LIB_FUNCTION
1088 krb5_enctype_keybits(krb5_context context,
1089                      krb5_enctype type,
1090                      size_t *keybits)
1091 {
1092     struct encryption_type *et = _find_enctype(type);
1093     if(et == NULL) {
1094         krb5_set_error_string(context, "encryption type %d not supported",
1095                               type);
1096         return KRB5_PROG_ETYPE_NOSUPP;
1097     }
1098     *keybits = et->keytype->bits;
1099     return 0;
1100 }
1101
1102 krb5_error_code KRB5_LIB_FUNCTION
1103 krb5_generate_random_keyblock(krb5_context context,
1104                               krb5_enctype type,
1105                               krb5_keyblock *key)
1106 {
1107     krb5_error_code ret;
1108     struct encryption_type *et = _find_enctype(type);
1109     if(et == NULL) {
1110         krb5_set_error_string(context, "encryption type %d not supported",
1111                               type);
1112         return KRB5_PROG_ETYPE_NOSUPP;
1113     }
1114     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
1115     if(ret) 
1116         return ret;
1117     key->keytype = type;
1118     if(et->keytype->random_key)
1119         (*et->keytype->random_key)(context, key);
1120     else
1121         krb5_generate_random_block(key->keyvalue.data, 
1122                                    key->keyvalue.length);
1123     return 0;
1124 }
1125
1126 static krb5_error_code
1127 _key_schedule(krb5_context context,
1128               struct key_data *key)
1129 {
1130     krb5_error_code ret;
1131     struct encryption_type *et = _find_enctype(key->key->keytype);
1132     struct key_type *kt = et->keytype;
1133
1134     if(kt->schedule == NULL)
1135         return 0;
1136     if (key->schedule != NULL)
1137         return 0;
1138     ALLOC(key->schedule, 1);
1139     if(key->schedule == NULL) {
1140         krb5_set_error_string(context, "malloc: out of memory");
1141         return ENOMEM;
1142     }
1143     ret = krb5_data_alloc(key->schedule, kt->schedule_size);
1144     if(ret) {
1145         free(key->schedule);
1146         key->schedule = NULL;
1147         return ret;
1148     }
1149     (*kt->schedule)(context, key);
1150     return 0;
1151 }
1152
1153 /************************************************************
1154  *                                                          *
1155  ************************************************************/
1156
1157 static void
1158 NONE_checksum(krb5_context context,
1159               struct key_data *key,
1160               const void *data,
1161               size_t len,
1162               unsigned usage,
1163               Checksum *C)
1164 {
1165 }
1166
1167 static void
1168 CRC32_checksum(krb5_context context,
1169                struct key_data *key,
1170                const void *data,
1171                size_t len,
1172                unsigned usage,
1173                Checksum *C)
1174 {
1175     uint32_t crc;
1176     unsigned char *r = C->checksum.data;
1177     _krb5_crc_init_table ();
1178     crc = _krb5_crc_update (data, len, 0);
1179     r[0] = crc & 0xff;
1180     r[1] = (crc >> 8)  & 0xff;
1181     r[2] = (crc >> 16) & 0xff;
1182     r[3] = (crc >> 24) & 0xff;
1183 }
1184
1185 static void
1186 RSA_MD4_checksum(krb5_context context,
1187                  struct key_data *key,
1188                  const void *data,
1189                  size_t len,
1190                  unsigned usage,
1191                  Checksum *C)
1192 {
1193     MD4_CTX m;
1194
1195     MD4_Init (&m);
1196     MD4_Update (&m, data, len);
1197     MD4_Final (C->checksum.data, &m);
1198 }
1199
1200 static void
1201 RSA_MD4_DES_checksum(krb5_context context, 
1202                      struct key_data *key,
1203                      const void *data, 
1204                      size_t len, 
1205                      unsigned usage,
1206                      Checksum *cksum)
1207 {
1208     MD4_CTX md4;
1209     DES_cblock ivec;
1210     unsigned char *p = cksum->checksum.data;
1211     
1212     krb5_generate_random_block(p, 8);
1213     MD4_Init (&md4);
1214     MD4_Update (&md4, p, 8);
1215     MD4_Update (&md4, data, len);
1216     MD4_Final (p + 8, &md4);
1217     memset (&ivec, 0, sizeof(ivec));
1218     DES_cbc_encrypt(p, 
1219                     p, 
1220                     24, 
1221                     key->schedule->data, 
1222                     &ivec, 
1223                     DES_ENCRYPT);
1224 }
1225
1226 static krb5_error_code
1227 RSA_MD4_DES_verify(krb5_context context,
1228                    struct key_data *key,
1229                    const void *data,
1230                    size_t len,
1231                    unsigned usage,
1232                    Checksum *C)
1233 {
1234     MD4_CTX md4;
1235     unsigned char tmp[24];
1236     unsigned char res[16];
1237     DES_cblock ivec;
1238     krb5_error_code ret = 0;
1239
1240     memset(&ivec, 0, sizeof(ivec));
1241     DES_cbc_encrypt(C->checksum.data,
1242                     (void*)tmp, 
1243                     C->checksum.length, 
1244                     key->schedule->data,
1245                     &ivec,
1246                     DES_DECRYPT);
1247     MD4_Init (&md4);
1248     MD4_Update (&md4, tmp, 8); /* confounder */
1249     MD4_Update (&md4, data, len);
1250     MD4_Final (res, &md4);
1251     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
1252         krb5_clear_error_string (context);
1253         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1254     }
1255     memset(tmp, 0, sizeof(tmp));
1256     memset(res, 0, sizeof(res));
1257     return ret;
1258 }
1259
1260 static void
1261 RSA_MD5_checksum(krb5_context context,
1262                  struct key_data *key,
1263                  const void *data,
1264                  size_t len,
1265                  unsigned usage,
1266                  Checksum *C)
1267 {
1268     MD5_CTX m;
1269
1270     MD5_Init  (&m);
1271     MD5_Update(&m, data, len);
1272     MD5_Final (C->checksum.data, &m);
1273 }
1274
1275 static void
1276 RSA_MD5_DES_checksum(krb5_context context,
1277                      struct key_data *key,
1278                      const void *data,
1279                      size_t len,
1280                      unsigned usage,
1281                      Checksum *C)
1282 {
1283     MD5_CTX md5;
1284     DES_cblock ivec;
1285     unsigned char *p = C->checksum.data;
1286     
1287     krb5_generate_random_block(p, 8);
1288     MD5_Init (&md5);
1289     MD5_Update (&md5, p, 8);
1290     MD5_Update (&md5, data, len);
1291     MD5_Final (p + 8, &md5);
1292     memset (&ivec, 0, sizeof(ivec));
1293     DES_cbc_encrypt(p, 
1294                     p, 
1295                     24, 
1296                     key->schedule->data, 
1297                     &ivec, 
1298                     DES_ENCRYPT);
1299 }
1300
1301 static krb5_error_code
1302 RSA_MD5_DES_verify(krb5_context context,
1303                    struct key_data *key,
1304                    const void *data,
1305                    size_t len,
1306                    unsigned usage,
1307                    Checksum *C)
1308 {
1309     MD5_CTX md5;
1310     unsigned char tmp[24];
1311     unsigned char res[16];
1312     DES_cblock ivec;
1313     DES_key_schedule *sched = key->schedule->data;
1314     krb5_error_code ret = 0;
1315
1316     memset(&ivec, 0, sizeof(ivec));
1317     DES_cbc_encrypt(C->checksum.data, 
1318                     (void*)tmp, 
1319                     C->checksum.length, 
1320                     &sched[0],
1321                     &ivec,
1322                     DES_DECRYPT);
1323     MD5_Init (&md5);
1324     MD5_Update (&md5, tmp, 8); /* confounder */
1325     MD5_Update (&md5, data, len);
1326     MD5_Final (res, &md5);
1327     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
1328         krb5_clear_error_string (context);
1329         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1330     }
1331     memset(tmp, 0, sizeof(tmp));
1332     memset(res, 0, sizeof(res));
1333     return ret;
1334 }
1335
1336 static void
1337 RSA_MD5_DES3_checksum(krb5_context context,
1338                       struct key_data *key,
1339                       const void *data,
1340                       size_t len,
1341                       unsigned usage,
1342                       Checksum *C)
1343 {
1344     MD5_CTX md5;
1345     DES_cblock ivec;
1346     unsigned char *p = C->checksum.data;
1347     DES_key_schedule *sched = key->schedule->data;
1348     
1349     krb5_generate_random_block(p, 8);
1350     MD5_Init (&md5);
1351     MD5_Update (&md5, p, 8);
1352     MD5_Update (&md5, data, len);
1353     MD5_Final (p + 8, &md5);
1354     memset (&ivec, 0, sizeof(ivec));
1355     DES_ede3_cbc_encrypt(p, 
1356                          p, 
1357                          24, 
1358                          &sched[0], &sched[1], &sched[2],
1359                          &ivec, 
1360                          DES_ENCRYPT);
1361 }
1362
1363 static krb5_error_code
1364 RSA_MD5_DES3_verify(krb5_context context,
1365                     struct key_data *key,
1366                     const void *data,
1367                     size_t len,
1368                     unsigned usage,
1369                     Checksum *C)
1370 {
1371     MD5_CTX md5;
1372     unsigned char tmp[24];
1373     unsigned char res[16];
1374     DES_cblock ivec;
1375     DES_key_schedule *sched = key->schedule->data;
1376     krb5_error_code ret = 0;
1377
1378     memset(&ivec, 0, sizeof(ivec));
1379     DES_ede3_cbc_encrypt(C->checksum.data, 
1380                          (void*)tmp, 
1381                          C->checksum.length, 
1382                          &sched[0], &sched[1], &sched[2],
1383                          &ivec,
1384                          DES_DECRYPT);
1385     MD5_Init (&md5);
1386     MD5_Update (&md5, tmp, 8); /* confounder */
1387     MD5_Update (&md5, data, len);
1388     MD5_Final (res, &md5);
1389     if(memcmp(res, tmp + 8, sizeof(res)) != 0) {
1390         krb5_clear_error_string (context);
1391         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1392     }
1393     memset(tmp, 0, sizeof(tmp));
1394     memset(res, 0, sizeof(res));
1395     return ret;
1396 }
1397
1398 static void
1399 SHA1_checksum(krb5_context context,
1400               struct key_data *key,
1401               const void *data,
1402               size_t len,
1403               unsigned usage,
1404               Checksum *C)
1405 {
1406     SHA_CTX m;
1407
1408     SHA1_Init(&m);
1409     SHA1_Update(&m, data, len);
1410     SHA1_Final(C->checksum.data, &m);
1411 }
1412
1413 /* HMAC according to RFC2104 */
1414 static krb5_error_code
1415 hmac(krb5_context context,
1416      struct checksum_type *cm, 
1417      const void *data, 
1418      size_t len, 
1419      unsigned usage,
1420      struct key_data *keyblock,
1421      Checksum *result)
1422 {
1423     unsigned char *ipad, *opad;
1424     unsigned char *key;
1425     size_t key_len;
1426     int i;
1427     
1428     ipad = malloc(cm->blocksize + len);
1429     if (ipad == NULL)
1430         return ENOMEM;
1431     opad = malloc(cm->blocksize + cm->checksumsize);
1432     if (opad == NULL) {
1433         free(ipad);
1434         return ENOMEM;
1435     }
1436     memset(ipad, 0x36, cm->blocksize);
1437     memset(opad, 0x5c, cm->blocksize);
1438
1439     if(keyblock->key->keyvalue.length > cm->blocksize){
1440         (*cm->checksum)(context, 
1441                         keyblock, 
1442                         keyblock->key->keyvalue.data, 
1443                         keyblock->key->keyvalue.length, 
1444                         usage,
1445                         result);
1446         key = result->checksum.data;
1447         key_len = result->checksum.length;
1448     } else {
1449         key = keyblock->key->keyvalue.data;
1450         key_len = keyblock->key->keyvalue.length;
1451     }
1452     for(i = 0; i < key_len; i++){
1453         ipad[i] ^= key[i];
1454         opad[i] ^= key[i];
1455     }
1456     memcpy(ipad + cm->blocksize, data, len);
1457     (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
1458                     usage, result);
1459     memcpy(opad + cm->blocksize, result->checksum.data, 
1460            result->checksum.length);
1461     (*cm->checksum)(context, keyblock, opad, 
1462                     cm->blocksize + cm->checksumsize, usage, result);
1463     memset(ipad, 0, cm->blocksize + len);
1464     free(ipad);
1465     memset(opad, 0, cm->blocksize + cm->checksumsize);
1466     free(opad);
1467
1468     return 0;
1469 }
1470
1471 krb5_error_code KRB5_LIB_FUNCTION
1472 krb5_hmac(krb5_context context,
1473           krb5_cksumtype cktype,
1474           const void *data,
1475           size_t len,
1476           unsigned usage, 
1477           krb5_keyblock *key,
1478           Checksum *result)
1479 {
1480     struct checksum_type *c = _find_checksum(cktype);
1481     struct key_data kd;
1482     krb5_error_code ret;
1483
1484     if (c == NULL) {
1485         krb5_set_error_string (context, "checksum type %d not supported",
1486                                cktype);
1487         return KRB5_PROG_SUMTYPE_NOSUPP;
1488     }
1489
1490     kd.key = key;
1491     kd.schedule = NULL;
1492
1493     ret = hmac(context, c, data, len, usage, &kd, result);
1494
1495     if (kd.schedule)
1496         krb5_free_data(context, kd.schedule);
1497
1498     return ret;
1499  }
1500
1501 static void
1502 SP_HMAC_SHA1_checksum(krb5_context context,
1503                       struct key_data *key, 
1504                       const void *data, 
1505                       size_t len, 
1506                       unsigned usage,
1507                       Checksum *result)
1508 {
1509     struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1);
1510     Checksum res;
1511     char sha1_data[20];
1512     krb5_error_code ret;
1513
1514     res.checksum.data = sha1_data;
1515     res.checksum.length = sizeof(sha1_data);
1516
1517     ret = hmac(context, c, data, len, usage, key, &res);
1518     if (ret)
1519         krb5_abortx(context, "hmac failed");
1520     memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
1521 }
1522
1523 /*
1524  * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
1525  */
1526
1527 static void
1528 HMAC_MD5_checksum(krb5_context context,
1529                   struct key_data *key,
1530                   const void *data,
1531                   size_t len,
1532                   unsigned usage,
1533                   Checksum *result)
1534 {
1535     MD5_CTX md5;
1536     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1537     const char signature[] = "signaturekey";
1538     Checksum ksign_c;
1539     struct key_data ksign;
1540     krb5_keyblock kb;
1541     unsigned char t[4];
1542     unsigned char tmp[16];
1543     unsigned char ksign_c_data[16];
1544     krb5_error_code ret;
1545
1546     ksign_c.checksum.length = sizeof(ksign_c_data);
1547     ksign_c.checksum.data   = ksign_c_data;
1548     ret = hmac(context, c, signature, sizeof(signature), 0, key, &ksign_c);
1549     if (ret)
1550         krb5_abortx(context, "hmac failed");
1551     ksign.key = &kb;
1552     kb.keyvalue = ksign_c.checksum;
1553     MD5_Init (&md5);
1554     t[0] = (usage >>  0) & 0xFF;
1555     t[1] = (usage >>  8) & 0xFF;
1556     t[2] = (usage >> 16) & 0xFF;
1557     t[3] = (usage >> 24) & 0xFF;
1558     MD5_Update (&md5, t, 4);
1559     MD5_Update (&md5, data, len);
1560     MD5_Final (tmp, &md5);
1561     ret = hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
1562     if (ret)
1563         krb5_abortx(context, "hmac failed");
1564 }
1565
1566 /*
1567  * same as previous but being used while encrypting.
1568  */
1569
1570 static void
1571 HMAC_MD5_checksum_enc(krb5_context context,
1572                       struct key_data *key,
1573                       const void *data,
1574                       size_t len,
1575                       unsigned usage,
1576                       Checksum *result)
1577 {
1578     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
1579     Checksum ksign_c;
1580     struct key_data ksign;
1581     krb5_keyblock kb;
1582     unsigned char t[4];
1583     unsigned char ksign_c_data[16];
1584     krb5_error_code ret;
1585
1586     t[0] = (usage >>  0) & 0xFF;
1587     t[1] = (usage >>  8) & 0xFF;
1588     t[2] = (usage >> 16) & 0xFF;
1589     t[3] = (usage >> 24) & 0xFF;
1590
1591     ksign_c.checksum.length = sizeof(ksign_c_data);
1592     ksign_c.checksum.data   = ksign_c_data;
1593     ret = hmac(context, c, t, sizeof(t), 0, key, &ksign_c);
1594     if (ret)
1595         krb5_abortx(context, "hmac failed");
1596     ksign.key = &kb;
1597     kb.keyvalue = ksign_c.checksum;
1598     ret = hmac(context, c, data, len, 0, &ksign, result);
1599     if (ret)
1600         krb5_abortx(context, "hmac failed");
1601 }
1602
1603 static struct checksum_type checksum_none = {
1604     CKSUMTYPE_NONE, 
1605     "none", 
1606     1, 
1607     0, 
1608     0,
1609     NONE_checksum, 
1610     NULL
1611 };
1612 static struct checksum_type checksum_crc32 = {
1613     CKSUMTYPE_CRC32,
1614     "crc32",
1615     1,
1616     4,
1617     0,
1618     CRC32_checksum,
1619     NULL
1620 };
1621 static struct checksum_type checksum_rsa_md4 = {
1622     CKSUMTYPE_RSA_MD4,
1623     "rsa-md4",
1624     64,
1625     16,
1626     F_CPROOF,
1627     RSA_MD4_checksum,
1628     NULL
1629 };
1630 static struct checksum_type checksum_rsa_md4_des = {
1631     CKSUMTYPE_RSA_MD4_DES,
1632     "rsa-md4-des",
1633     64,
1634     24,
1635     F_KEYED | F_CPROOF | F_VARIANT,
1636     RSA_MD4_DES_checksum,
1637     RSA_MD4_DES_verify
1638 };
1639 #if 0
1640 static struct checksum_type checksum_des_mac = { 
1641     CKSUMTYPE_DES_MAC,
1642     "des-mac",
1643     0,
1644     0,
1645     0,
1646     DES_MAC_checksum
1647 };
1648 static struct checksum_type checksum_des_mac_k = {
1649     CKSUMTYPE_DES_MAC_K,
1650     "des-mac-k",
1651     0,
1652     0,
1653     0,
1654     DES_MAC_K_checksum
1655 };
1656 static struct checksum_type checksum_rsa_md4_des_k = {
1657     CKSUMTYPE_RSA_MD4_DES_K, 
1658     "rsa-md4-des-k", 
1659     0, 
1660     0, 
1661     0, 
1662     RSA_MD4_DES_K_checksum,
1663     RSA_MD4_DES_K_verify
1664 };
1665 #endif
1666 static struct checksum_type checksum_rsa_md5 = {
1667     CKSUMTYPE_RSA_MD5,
1668     "rsa-md5",
1669     64,
1670     16,
1671     F_CPROOF,
1672     RSA_MD5_checksum,
1673     NULL
1674 };
1675 static struct checksum_type checksum_rsa_md5_des = {
1676     CKSUMTYPE_RSA_MD5_DES,
1677     "rsa-md5-des",
1678     64,
1679     24,
1680     F_KEYED | F_CPROOF | F_VARIANT,
1681     RSA_MD5_DES_checksum,
1682     RSA_MD5_DES_verify
1683 };
1684 static struct checksum_type checksum_rsa_md5_des3 = {
1685     CKSUMTYPE_RSA_MD5_DES3,
1686     "rsa-md5-des3",
1687     64,
1688     24,
1689     F_KEYED | F_CPROOF | F_VARIANT,
1690     RSA_MD5_DES3_checksum,
1691     RSA_MD5_DES3_verify
1692 };
1693 static struct checksum_type checksum_sha1 = {
1694     CKSUMTYPE_SHA1,
1695     "sha1",
1696     64,
1697     20,
1698     F_CPROOF,
1699     SHA1_checksum,
1700     NULL
1701 };
1702 static struct checksum_type checksum_hmac_sha1_des3 = {
1703     CKSUMTYPE_HMAC_SHA1_DES3,
1704     "hmac-sha1-des3",
1705     64,
1706     20,
1707     F_KEYED | F_CPROOF | F_DERIVED,
1708     SP_HMAC_SHA1_checksum,
1709     NULL
1710 };
1711
1712 static struct checksum_type checksum_hmac_sha1_aes128 = {
1713     CKSUMTYPE_HMAC_SHA1_96_AES_128,
1714     "hmac-sha1-96-aes128",
1715     64,
1716     12,
1717     F_KEYED | F_CPROOF | F_DERIVED,
1718     SP_HMAC_SHA1_checksum,
1719     NULL
1720 };
1721
1722 static struct checksum_type checksum_hmac_sha1_aes256 = {
1723     CKSUMTYPE_HMAC_SHA1_96_AES_256,
1724     "hmac-sha1-96-aes256",
1725     64,
1726     12,
1727     F_KEYED | F_CPROOF | F_DERIVED,
1728     SP_HMAC_SHA1_checksum,
1729     NULL
1730 };
1731
1732 static struct checksum_type checksum_hmac_md5 = {
1733     CKSUMTYPE_HMAC_MD5,
1734     "hmac-md5",
1735     64,
1736     16,
1737     F_KEYED | F_CPROOF,
1738     HMAC_MD5_checksum,
1739     NULL
1740 };
1741
1742 static struct checksum_type checksum_hmac_md5_enc = {
1743     CKSUMTYPE_HMAC_MD5_ENC,
1744     "hmac-md5-enc",
1745     64,
1746     16,
1747     F_KEYED | F_CPROOF | F_PSEUDO,
1748     HMAC_MD5_checksum_enc,
1749     NULL
1750 };
1751
1752 static struct checksum_type *checksum_types[] = {
1753     &checksum_none,
1754     &checksum_crc32,
1755     &checksum_rsa_md4,
1756     &checksum_rsa_md4_des,
1757 #if 0
1758     &checksum_des_mac, 
1759     &checksum_des_mac_k,
1760     &checksum_rsa_md4_des_k,
1761 #endif
1762     &checksum_rsa_md5,
1763     &checksum_rsa_md5_des,
1764     &checksum_rsa_md5_des3,
1765     &checksum_sha1,
1766     &checksum_hmac_sha1_des3,
1767     &checksum_hmac_sha1_aes128,
1768     &checksum_hmac_sha1_aes256,
1769     &checksum_hmac_md5,
1770     &checksum_hmac_md5_enc
1771 };
1772
1773 static int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]);
1774
1775 static struct checksum_type *
1776 _find_checksum(krb5_cksumtype type)
1777 {
1778     int i;
1779     for(i = 0; i < num_checksums; i++)
1780         if(checksum_types[i]->type == type)
1781             return checksum_types[i];
1782     return NULL;
1783 }
1784
1785 static krb5_error_code
1786 get_checksum_key(krb5_context context, 
1787                  krb5_crypto crypto,
1788                  unsigned usage,  /* not krb5_key_usage */
1789                  struct checksum_type *ct, 
1790                  struct key_data **key)
1791 {
1792     krb5_error_code ret = 0;
1793
1794     if(ct->flags & F_DERIVED)
1795         ret = _get_derived_key(context, crypto, usage, key);
1796     else if(ct->flags & F_VARIANT) {
1797         int i;
1798
1799         *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
1800         if(*key == NULL) {
1801             krb5_set_error_string(context, "malloc: out of memory");
1802             return ENOMEM;
1803         }
1804         ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
1805         if(ret) 
1806             return ret;
1807         for(i = 0; i < (*key)->key->keyvalue.length; i++)
1808             ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
1809     } else {
1810         *key = &crypto->key; 
1811     }
1812     if(ret == 0)
1813         ret = _key_schedule(context, *key);
1814     return ret;
1815 }
1816
1817 static krb5_error_code
1818 create_checksum (krb5_context context,
1819                  struct checksum_type *ct,
1820                  krb5_crypto crypto,
1821                  unsigned usage,
1822                  void *data,
1823                  size_t len,
1824                  Checksum *result)
1825 {
1826     krb5_error_code ret;
1827     struct key_data *dkey;
1828     int keyed_checksum;
1829     
1830     if (ct->flags & F_DISABLED) {
1831         krb5_clear_error_string (context);
1832         return KRB5_PROG_SUMTYPE_NOSUPP;
1833     }
1834     keyed_checksum = (ct->flags & F_KEYED) != 0;
1835     if(keyed_checksum && crypto == NULL) {
1836         krb5_set_error_string (context, "Checksum type %s is keyed "
1837                                "but no crypto context (key) was passed in",
1838                                ct->name);
1839         return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1840     }
1841     if(keyed_checksum) {
1842         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1843         if (ret)
1844             return ret;
1845     } else
1846         dkey = NULL;
1847     result->cksumtype = ct->type;
1848     ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
1849     if (ret)
1850         return (ret);
1851     (*ct->checksum)(context, dkey, data, len, usage, result);
1852     return 0;
1853 }
1854
1855 static int
1856 arcfour_checksum_p(struct checksum_type *ct, krb5_crypto crypto)
1857 {
1858     return (ct->type == CKSUMTYPE_HMAC_MD5) &&
1859         (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
1860 }
1861
1862 krb5_error_code KRB5_LIB_FUNCTION
1863 krb5_create_checksum(krb5_context context,
1864                      krb5_crypto crypto,
1865                      krb5_key_usage usage,
1866                      int type,
1867                      void *data,
1868                      size_t len,
1869                      Checksum *result)
1870 {
1871     struct checksum_type *ct = NULL;
1872     unsigned keyusage;
1873
1874     /* type 0 -> pick from crypto */
1875     if (type) {
1876         ct = _find_checksum(type);
1877     } else if (crypto) {
1878         ct = crypto->et->keyed_checksum;
1879         if (ct == NULL)
1880             ct = crypto->et->checksum;
1881     }
1882
1883     if(ct == NULL) {
1884         krb5_set_error_string (context, "checksum type %d not supported",
1885                                type);
1886         return KRB5_PROG_SUMTYPE_NOSUPP;
1887     }
1888
1889     if (arcfour_checksum_p(ct, crypto)) {
1890         keyusage = usage;
1891         usage2arcfour(context, &keyusage);
1892     } else
1893         keyusage = CHECKSUM_USAGE(usage);
1894
1895     return create_checksum(context, ct, crypto, keyusage,
1896                            data, len, result);
1897 }
1898
1899 static krb5_error_code
1900 verify_checksum(krb5_context context,
1901                 krb5_crypto crypto,
1902                 unsigned usage, /* not krb5_key_usage */
1903                 void *data,
1904                 size_t len,
1905                 Checksum *cksum)
1906 {
1907     krb5_error_code ret;
1908     struct key_data *dkey;
1909     int keyed_checksum;
1910     Checksum c;
1911     struct checksum_type *ct;
1912
1913     ct = _find_checksum(cksum->cksumtype);
1914     if (ct == NULL || (ct->flags & F_DISABLED)) {
1915         krb5_set_error_string (context, "checksum type %d not supported",
1916                                cksum->cksumtype);
1917         return KRB5_PROG_SUMTYPE_NOSUPP;
1918     }
1919     if(ct->checksumsize != cksum->checksum.length) {
1920         krb5_clear_error_string (context);
1921         return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
1922     }
1923     keyed_checksum = (ct->flags & F_KEYED) != 0;
1924     if(keyed_checksum && crypto == NULL) {
1925         krb5_set_error_string (context, "Checksum type %s is keyed "
1926                                "but no crypto context (key) was passed in",
1927                                ct->name);
1928         return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
1929     }
1930     if(keyed_checksum)
1931         ret = get_checksum_key(context, crypto, usage, ct, &dkey);
1932     else
1933         dkey = NULL;
1934     if(ct->verify)
1935         return (*ct->verify)(context, dkey, data, len, usage, cksum);
1936
1937     ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
1938     if (ret)
1939         return ret;
1940
1941     (*ct->checksum)(context, dkey, data, len, usage, &c);
1942
1943     if(c.checksum.length != cksum->checksum.length || 
1944        memcmp(c.checksum.data, cksum->checksum.data, c.checksum.length)) {
1945         krb5_clear_error_string (context);
1946         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1947     } else {
1948         ret = 0;
1949     }
1950     krb5_data_free (&c.checksum);
1951     return ret;
1952 }
1953
1954 krb5_error_code KRB5_LIB_FUNCTION
1955 krb5_verify_checksum(krb5_context context,
1956                      krb5_crypto crypto,
1957                      krb5_key_usage usage, 
1958                      void *data,
1959                      size_t len,
1960                      Checksum *cksum)
1961 {
1962     struct checksum_type *ct;
1963     unsigned keyusage;
1964
1965     ct = _find_checksum(cksum->cksumtype);
1966     if(ct == NULL) {
1967         krb5_set_error_string (context, "checksum type %d not supported",
1968                                cksum->cksumtype);
1969         return KRB5_PROG_SUMTYPE_NOSUPP;
1970     }
1971
1972     if (arcfour_checksum_p(ct, crypto)) {
1973         keyusage = usage;
1974         usage2arcfour(context, &keyusage);
1975     } else
1976         keyusage = CHECKSUM_USAGE(usage);
1977
1978     return verify_checksum(context, crypto, keyusage,
1979                            data, len, cksum);
1980 }
1981
1982 krb5_error_code KRB5_LIB_FUNCTION
1983 krb5_crypto_get_checksum_type(krb5_context context,
1984                               krb5_crypto crypto,
1985                               krb5_cksumtype *type)
1986 {
1987     struct checksum_type *ct = NULL;
1988     
1989     if (crypto != NULL) {
1990         ct = crypto->et->keyed_checksum;
1991         if (ct == NULL)
1992             ct = crypto->et->checksum;
1993     }
1994     
1995     if (ct == NULL) {
1996         krb5_set_error_string (context, "checksum type not found");
1997         return KRB5_PROG_SUMTYPE_NOSUPP;
1998     }    
1999
2000     *type = ct->type;
2001     
2002     return 0;      
2003 }
2004
2005
2006 krb5_error_code KRB5_LIB_FUNCTION
2007 krb5_checksumsize(krb5_context context,
2008                   krb5_cksumtype type,
2009                   size_t *size)
2010 {
2011     struct checksum_type *ct = _find_checksum(type);
2012     if(ct == NULL) {
2013         krb5_set_error_string (context, "checksum type %d not supported",
2014                                type);
2015         return KRB5_PROG_SUMTYPE_NOSUPP;
2016     }
2017     *size = ct->checksumsize;
2018     return 0;
2019 }
2020
2021 krb5_boolean KRB5_LIB_FUNCTION
2022 krb5_checksum_is_keyed(krb5_context context,
2023                        krb5_cksumtype type)
2024 {
2025     struct checksum_type *ct = _find_checksum(type);
2026     if(ct == NULL) {
2027         if (context)
2028             krb5_set_error_string (context, "checksum type %d not supported",
2029                                    type);
2030         return KRB5_PROG_SUMTYPE_NOSUPP;
2031     }
2032     return ct->flags & F_KEYED;
2033 }
2034
2035 krb5_boolean KRB5_LIB_FUNCTION
2036 krb5_checksum_is_collision_proof(krb5_context context,
2037                                  krb5_cksumtype type)
2038 {
2039     struct checksum_type *ct = _find_checksum(type);
2040     if(ct == NULL) {
2041         if (context)
2042             krb5_set_error_string (context, "checksum type %d not supported",
2043                                    type);
2044         return KRB5_PROG_SUMTYPE_NOSUPP;
2045     }
2046     return ct->flags & F_CPROOF;
2047 }
2048
2049 krb5_error_code KRB5_LIB_FUNCTION
2050 krb5_checksum_disable(krb5_context context,
2051                       krb5_cksumtype type)
2052 {
2053     struct checksum_type *ct = _find_checksum(type);
2054     if(ct == NULL) {
2055         if (context)
2056             krb5_set_error_string (context, "checksum type %d not supported",
2057                                    type);
2058         return KRB5_PROG_SUMTYPE_NOSUPP;
2059     }
2060     ct->flags |= F_DISABLED;
2061     return 0;
2062 }
2063
2064 /************************************************************
2065  *                                                          *
2066  ************************************************************/
2067
2068 static krb5_error_code
2069 NULL_encrypt(krb5_context context,
2070              struct key_data *key, 
2071              void *data, 
2072              size_t len, 
2073              krb5_boolean encryptp,
2074              int usage,
2075              void *ivec)
2076 {
2077     return 0;
2078 }
2079
2080 static krb5_error_code
2081 DES_CBC_encrypt_null_ivec(krb5_context context,
2082                           struct key_data *key, 
2083                           void *data, 
2084                           size_t len, 
2085                           krb5_boolean encryptp,
2086                           int usage,
2087                           void *ignore_ivec)
2088 {
2089     DES_cblock ivec;
2090     DES_key_schedule *s = key->schedule->data;
2091     memset(&ivec, 0, sizeof(ivec));
2092     DES_cbc_encrypt(data, data, len, s, &ivec, encryptp);
2093     return 0;
2094 }
2095
2096 static krb5_error_code
2097 DES_CBC_encrypt_key_ivec(krb5_context context,
2098                          struct key_data *key, 
2099                          void *data, 
2100                          size_t len, 
2101                          krb5_boolean encryptp,
2102                          int usage,
2103                          void *ignore_ivec)
2104 {
2105     DES_cblock ivec;
2106     DES_key_schedule *s = key->schedule->data;
2107     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
2108     DES_cbc_encrypt(data, data, len, s, &ivec, encryptp);
2109     return 0;
2110 }
2111
2112 static krb5_error_code
2113 DES3_CBC_encrypt(krb5_context context,
2114                  struct key_data *key, 
2115                  void *data, 
2116                  size_t len, 
2117                  krb5_boolean encryptp,
2118                  int usage,
2119                  void *ivec)
2120 {
2121     DES_cblock local_ivec;
2122     DES_key_schedule *s = key->schedule->data;
2123     if(ivec == NULL) {
2124         ivec = &local_ivec;
2125         memset(local_ivec, 0, sizeof(local_ivec));
2126     }
2127     DES_ede3_cbc_encrypt(data, data, len, &s[0], &s[1], &s[2], ivec, encryptp);
2128     return 0;
2129 }
2130
2131 static krb5_error_code
2132 DES_CFB64_encrypt_null_ivec(krb5_context context,
2133                             struct key_data *key, 
2134                             void *data, 
2135                             size_t len, 
2136                             krb5_boolean encryptp,
2137                             int usage,
2138                             void *ignore_ivec)
2139 {
2140     DES_cblock ivec;
2141     int num = 0;
2142     DES_key_schedule *s = key->schedule->data;
2143     memset(&ivec, 0, sizeof(ivec));
2144
2145     DES_cfb64_encrypt(data, data, len, s, &ivec, &num, encryptp);
2146     return 0;
2147 }
2148
2149 static krb5_error_code
2150 DES_PCBC_encrypt_key_ivec(krb5_context context,
2151                           struct key_data *key, 
2152                           void *data, 
2153                           size_t len, 
2154                           krb5_boolean encryptp,
2155                           int usage,
2156                           void *ignore_ivec)
2157 {
2158     DES_cblock ivec;
2159     DES_key_schedule *s = key->schedule->data;
2160     memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
2161
2162     DES_pcbc_encrypt(data, data, len, s, &ivec, encryptp);
2163     return 0;
2164 }
2165
2166 /*
2167  * AES draft-raeburn-krb-rijndael-krb-02
2168  */
2169
2170 void KRB5_LIB_FUNCTION
2171 _krb5_aes_cts_encrypt(const unsigned char *in, unsigned char *out,
2172                       size_t len, const AES_KEY *key,
2173                       unsigned char *ivec, const int encryptp)
2174 {
2175     unsigned char tmp[AES_BLOCK_SIZE];
2176     int i;
2177
2178     /*
2179      * In the framework of kerberos, the length can never be shorter
2180      * then at least one blocksize.
2181      */
2182
2183     if (encryptp) {
2184
2185         while(len > AES_BLOCK_SIZE) {
2186             for (i = 0; i < AES_BLOCK_SIZE; i++)
2187                 tmp[i] = in[i] ^ ivec[i];
2188             AES_encrypt(tmp, out, key);
2189             memcpy(ivec, out, AES_BLOCK_SIZE);
2190             len -= AES_BLOCK_SIZE;
2191             in += AES_BLOCK_SIZE;
2192             out += AES_BLOCK_SIZE;
2193         }
2194
2195         for (i = 0; i < len; i++)
2196             tmp[i] = in[i] ^ ivec[i];
2197         for (; i < AES_BLOCK_SIZE; i++)
2198             tmp[i] = 0 ^ ivec[i];
2199
2200         AES_encrypt(tmp, out - AES_BLOCK_SIZE, key);
2201
2202         memcpy(out, ivec, len);
2203         memcpy(ivec, out - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
2204
2205     } else {
2206         unsigned char tmp2[AES_BLOCK_SIZE];
2207         unsigned char tmp3[AES_BLOCK_SIZE];
2208
2209         while(len > AES_BLOCK_SIZE * 2) {
2210             memcpy(tmp, in, AES_BLOCK_SIZE);
2211             AES_decrypt(in, out, key);
2212             for (i = 0; i < AES_BLOCK_SIZE; i++)
2213                 out[i] ^= ivec[i];
2214             memcpy(ivec, tmp, AES_BLOCK_SIZE);
2215             len -= AES_BLOCK_SIZE;
2216             in += AES_BLOCK_SIZE;
2217             out += AES_BLOCK_SIZE;
2218         }
2219
2220         len -= AES_BLOCK_SIZE;
2221
2222         memcpy(tmp, in, AES_BLOCK_SIZE); /* save last iv */
2223         AES_decrypt(in, tmp2, key);
2224
2225         memcpy(tmp3, in + AES_BLOCK_SIZE, len);
2226         memcpy(tmp3 + len, tmp2 + len, AES_BLOCK_SIZE - len); /* xor 0 */
2227
2228         for (i = 0; i < len; i++)
2229             out[i + AES_BLOCK_SIZE] = tmp2[i] ^ tmp3[i];
2230
2231         AES_decrypt(tmp3, out, key);
2232         for (i = 0; i < AES_BLOCK_SIZE; i++)
2233             out[i] ^= ivec[i];
2234         memcpy(ivec, tmp, AES_BLOCK_SIZE);
2235     }
2236 }
2237
2238 static krb5_error_code
2239 AES_CTS_encrypt(krb5_context context,
2240                 struct key_data *key,
2241                 void *data,
2242                 size_t len,
2243                 krb5_boolean encryptp,
2244                 int usage,
2245                 void *ivec)
2246 {
2247     struct krb5_aes_schedule *aeskey = key->schedule->data;
2248     char local_ivec[AES_BLOCK_SIZE];
2249     AES_KEY *k;
2250
2251     if (encryptp)
2252         k = &aeskey->ekey;
2253     else
2254         k = &aeskey->dkey;
2255     
2256     if (len < AES_BLOCK_SIZE)
2257         krb5_abortx(context, "invalid use of AES_CTS_encrypt");
2258     if (len == AES_BLOCK_SIZE) {
2259         if (encryptp)
2260             AES_encrypt(data, data, k);
2261         else
2262             AES_decrypt(data, data, k);
2263     } else {
2264         if(ivec == NULL) {
2265             memset(local_ivec, 0, sizeof(local_ivec));
2266             ivec = local_ivec;
2267         }
2268         _krb5_aes_cts_encrypt(data, data, len, k, ivec, encryptp);
2269     }
2270
2271     return 0;
2272 }
2273
2274 /*
2275  * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
2276  *
2277  * warning: not for small children
2278  */
2279
2280 static krb5_error_code
2281 ARCFOUR_subencrypt(krb5_context context,
2282                    struct key_data *key,
2283                    void *data,
2284                    size_t len,
2285                    unsigned usage,
2286                    void *ivec)
2287 {
2288     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
2289     Checksum k1_c, k2_c, k3_c, cksum;
2290     struct key_data ke;
2291     krb5_keyblock kb;
2292     unsigned char t[4];
2293     RC4_KEY rc4_key;
2294     unsigned char *cdata = data;
2295     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
2296     krb5_error_code ret;
2297
2298     t[0] = (usage >>  0) & 0xFF;
2299     t[1] = (usage >>  8) & 0xFF;
2300     t[2] = (usage >> 16) & 0xFF;
2301     t[3] = (usage >> 24) & 0xFF;
2302
2303     k1_c.checksum.length = sizeof(k1_c_data);
2304     k1_c.checksum.data   = k1_c_data;
2305
2306     ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
2307     if (ret)
2308         krb5_abortx(context, "hmac failed");
2309
2310     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
2311
2312     k2_c.checksum.length = sizeof(k2_c_data);
2313     k2_c.checksum.data   = k2_c_data;
2314
2315     ke.key = &kb;
2316     kb.keyvalue = k2_c.checksum;
2317
2318     cksum.checksum.length = 16;
2319     cksum.checksum.data   = data;
2320
2321     ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
2322     if (ret)
2323         krb5_abortx(context, "hmac failed");
2324
2325     ke.key = &kb;
2326     kb.keyvalue = k1_c.checksum;
2327
2328     k3_c.checksum.length = sizeof(k3_c_data);
2329     k3_c.checksum.data   = k3_c_data;
2330
2331     ret = hmac(NULL, c, data, 16, 0, &ke, &k3_c);
2332     if (ret)
2333         krb5_abortx(context, "hmac failed");
2334
2335     RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
2336     RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
2337     memset (k1_c_data, 0, sizeof(k1_c_data));
2338     memset (k2_c_data, 0, sizeof(k2_c_data));
2339     memset (k3_c_data, 0, sizeof(k3_c_data));
2340     return 0;
2341 }
2342
2343 static krb5_error_code
2344 ARCFOUR_subdecrypt(krb5_context context,
2345                    struct key_data *key,
2346                    void *data,
2347                    size_t len,
2348                    unsigned usage,
2349                    void *ivec)
2350 {
2351     struct checksum_type *c = _find_checksum (CKSUMTYPE_RSA_MD5);
2352     Checksum k1_c, k2_c, k3_c, cksum;
2353     struct key_data ke;
2354     krb5_keyblock kb;
2355     unsigned char t[4];
2356     RC4_KEY rc4_key;
2357     unsigned char *cdata = data;
2358     unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
2359     unsigned char cksum_data[16];
2360     krb5_error_code ret;
2361
2362     t[0] = (usage >>  0) & 0xFF;
2363     t[1] = (usage >>  8) & 0xFF;
2364     t[2] = (usage >> 16) & 0xFF;
2365     t[3] = (usage >> 24) & 0xFF;
2366
2367     k1_c.checksum.length = sizeof(k1_c_data);
2368     k1_c.checksum.data   = k1_c_data;
2369
2370     ret = hmac(NULL, c, t, sizeof(t), 0, key, &k1_c);
2371     if (ret)
2372         krb5_abortx(context, "hmac failed");
2373
2374     memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
2375
2376     k2_c.checksum.length = sizeof(k2_c_data);
2377     k2_c.checksum.data   = k2_c_data;
2378
2379     ke.key = &kb;
2380     kb.keyvalue = k1_c.checksum;
2381
2382     k3_c.checksum.length = sizeof(k3_c_data);
2383     k3_c.checksum.data   = k3_c_data;
2384
2385     ret = hmac(NULL, c, cdata, 16, 0, &ke, &k3_c);
2386     if (ret)
2387         krb5_abortx(context, "hmac failed");
2388
2389     RC4_set_key (&rc4_key, k3_c.checksum.length, k3_c.checksum.data);
2390     RC4 (&rc4_key, len - 16, cdata + 16, cdata + 16);
2391
2392     ke.key = &kb;
2393     kb.keyvalue = k2_c.checksum;
2394
2395     cksum.checksum.length = 16;
2396     cksum.checksum.data   = cksum_data;
2397
2398     ret = hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum);
2399     if (ret)
2400         krb5_abortx(context, "hmac failed");
2401
2402     memset (k1_c_data, 0, sizeof(k1_c_data));
2403     memset (k2_c_data, 0, sizeof(k2_c_data));
2404     memset (k3_c_data, 0, sizeof(k3_c_data));
2405
2406     if (memcmp (cksum.checksum.data, data, 16) != 0) {
2407         krb5_clear_error_string (context);
2408         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
2409     } else {
2410         return 0;
2411     }
2412 }
2413
2414 /*
2415  * convert the usage numbers used in
2416  * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
2417  * draft-brezak-win2k-krb-rc4-hmac-04.txt
2418  */
2419
2420 static krb5_error_code
2421 usage2arcfour (krb5_context context, unsigned *usage)
2422 {
2423     switch (*usage) {
2424     case KRB5_KU_AS_REP_ENC_PART : /* 3 */
2425     case KRB5_KU_TGS_REP_ENC_PART_SUB_KEY : /* 9 */
2426         *usage = 8;
2427         return 0;
2428     case KRB5_KU_USAGE_SEAL :  /* 22 */
2429         *usage = 13;
2430         return 0;
2431     case KRB5_KU_USAGE_SIGN : /* 23 */
2432         *usage = 15;
2433         return 0;
2434     case KRB5_KU_USAGE_SEQ: /* 24 */
2435         *usage = 0;
2436         return 0;
2437     default :
2438         return 0;
2439     }
2440 }
2441
2442 static krb5_error_code
2443 ARCFOUR_encrypt(krb5_context context,
2444                 struct key_data *key,
2445                 void *data,
2446                 size_t len,
2447                 krb5_boolean encryptp,
2448                 int usage,
2449                 void *ivec)
2450 {
2451     krb5_error_code ret;
2452     unsigned keyusage = usage;
2453
2454     if((ret = usage2arcfour (context, &keyusage)) != 0)
2455         return ret;
2456
2457     if (encryptp)
2458         return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
2459     else
2460         return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
2461 }
2462
2463
2464 /*
2465  *
2466  */
2467
2468 static krb5_error_code
2469 AES_PRF(krb5_context context,
2470         krb5_crypto crypto,
2471         const krb5_data *in,
2472         krb5_data *out)
2473 {
2474     struct checksum_type *ct = crypto->et->checksum;
2475     krb5_error_code ret;
2476     Checksum result;
2477     krb5_keyblock *derived;
2478
2479     result.cksumtype = ct->type;
2480     ret = krb5_data_alloc(&result.checksum, ct->checksumsize);
2481     if (ret) {
2482         krb5_set_error_string(context, "out memory");
2483         return ret;
2484     }
2485
2486     (*ct->checksum)(context, NULL, in->data, in->length, 0, &result);
2487
2488     if (result.checksum.length < crypto->et->blocksize)
2489         krb5_abortx(context, "internal prf error");
2490
2491     derived = NULL;
2492     ret = krb5_derive_key(context, crypto->key.key, 
2493                           crypto->et->type, "prf", 3, &derived);
2494     if (ret)
2495         krb5_abortx(context, "krb5_derive_key");
2496
2497     ret = krb5_data_alloc(out, crypto->et->blocksize);
2498     if (ret)
2499         krb5_abortx(context, "malloc failed");
2500     
2501     { 
2502         AES_KEY key;
2503
2504         AES_set_encrypt_key(derived->keyvalue.data, 
2505                             crypto->et->keytype->bits, &key);
2506         AES_encrypt(result.checksum.data, out->data, &key);
2507         memset(&key, 0, sizeof(key));
2508     }
2509
2510     krb5_data_free(&result.checksum);
2511     krb5_free_keyblock(context, derived);
2512
2513     return ret;
2514 }
2515
2516 /*
2517  * these should currently be in reverse preference order.
2518  * (only relevant for !F_PSEUDO) */
2519
2520 static struct encryption_type enctype_null = {
2521     ETYPE_NULL,
2522     "null",
2523     NULL,
2524     1,
2525     1,
2526     0,
2527     &keytype_null,
2528     &checksum_none,
2529     NULL,
2530     F_DISABLED,
2531     NULL_encrypt,
2532     0,
2533     NULL
2534 };
2535 static struct encryption_type enctype_des_cbc_crc = {
2536     ETYPE_DES_CBC_CRC,
2537     "des-cbc-crc",
2538     NULL,
2539     8,
2540     8,
2541     8,
2542     &keytype_des,
2543     &checksum_crc32,
2544     NULL,
2545     0,
2546     DES_CBC_encrypt_key_ivec,
2547     0,
2548     NULL
2549 };
2550 static struct encryption_type enctype_des_cbc_md4 = {
2551     ETYPE_DES_CBC_MD4,
2552     "des-cbc-md4",
2553     NULL,
2554     8,
2555     8,
2556     8,
2557     &keytype_des,
2558     &checksum_rsa_md4,
2559     &checksum_rsa_md4_des,
2560     0,
2561     DES_CBC_encrypt_null_ivec,
2562     0,
2563     NULL
2564 };
2565 static struct encryption_type enctype_des_cbc_md5 = {
2566     ETYPE_DES_CBC_MD5,
2567     "des-cbc-md5",
2568     NULL,
2569     8,
2570     8,
2571     8,
2572     &keytype_des,
2573     &checksum_rsa_md5,
2574     &checksum_rsa_md5_des,
2575     0,
2576     DES_CBC_encrypt_null_ivec,
2577     0,
2578     NULL
2579 };
2580 static struct encryption_type enctype_arcfour_hmac_md5 = {
2581     ETYPE_ARCFOUR_HMAC_MD5,
2582     "arcfour-hmac-md5",
2583     NULL,
2584     1,
2585     1,
2586     8,
2587     &keytype_arcfour,
2588     &checksum_hmac_md5,
2589     NULL,
2590     F_SPECIAL,
2591     ARCFOUR_encrypt,
2592     0,
2593     NULL
2594 };
2595 static struct encryption_type enctype_des3_cbc_md5 = { 
2596     ETYPE_DES3_CBC_MD5,
2597     "des3-cbc-md5",
2598     NULL,
2599     8,
2600     8,
2601     8,
2602     &keytype_des3,
2603     &checksum_rsa_md5,
2604     &checksum_rsa_md5_des3,
2605     0,
2606     DES3_CBC_encrypt,
2607     0,
2608     NULL
2609 };
2610 static struct encryption_type enctype_des3_cbc_sha1 = {
2611     ETYPE_DES3_CBC_SHA1,
2612     "des3-cbc-sha1",
2613     NULL,
2614     8,
2615     8,
2616     8,
2617     &keytype_des3_derived,
2618     &checksum_sha1,
2619     &checksum_hmac_sha1_des3,
2620     F_DERIVED,
2621     DES3_CBC_encrypt,
2622     0,
2623     NULL
2624 };
2625 static struct encryption_type enctype_old_des3_cbc_sha1 = {
2626     ETYPE_OLD_DES3_CBC_SHA1,
2627     "old-des3-cbc-sha1",
2628     NULL,
2629     8,
2630     8,
2631     8,
2632     &keytype_des3,
2633     &checksum_sha1,
2634     &checksum_hmac_sha1_des3,
2635     0,
2636     DES3_CBC_encrypt,
2637     0,
2638     NULL
2639 };
2640 static struct encryption_type enctype_aes128_cts_hmac_sha1 = {
2641     ETYPE_AES128_CTS_HMAC_SHA1_96,
2642     "aes128-cts-hmac-sha1-96",
2643     NULL,
2644     16,
2645     1,
2646     16,
2647     &keytype_aes128,
2648     &checksum_sha1,
2649     &checksum_hmac_sha1_aes128,
2650     F_DERIVED,
2651     AES_CTS_encrypt,
2652     16,
2653     AES_PRF
2654 };
2655 static struct encryption_type enctype_aes256_cts_hmac_sha1 = {
2656     ETYPE_AES256_CTS_HMAC_SHA1_96,
2657     "aes256-cts-hmac-sha1-96",
2658     NULL,
2659     16,
2660     1,
2661     16,
2662     &keytype_aes256,
2663     &checksum_sha1,
2664     &checksum_hmac_sha1_aes256,
2665     F_DERIVED,
2666     AES_CTS_encrypt,
2667     16,
2668     AES_PRF
2669 };
2670 static struct encryption_type enctype_des_cbc_none = {
2671     ETYPE_DES_CBC_NONE,
2672     "des-cbc-none",
2673     NULL,
2674     8,
2675     8,
2676     0,
2677     &keytype_des,
2678     &checksum_none,
2679     NULL,
2680     F_PSEUDO,
2681     DES_CBC_encrypt_null_ivec,
2682     0,
2683     NULL
2684 };
2685 static struct encryption_type enctype_des_cfb64_none = {
2686     ETYPE_DES_CFB64_NONE,
2687     "des-cfb64-none",
2688     NULL,
2689     1,
2690     1,
2691     0,
2692     &keytype_des,
2693     &checksum_none,
2694     NULL,
2695     F_PSEUDO,
2696     DES_CFB64_encrypt_null_ivec,
2697     0,
2698     NULL
2699 };
2700 static struct encryption_type enctype_des_pcbc_none = {
2701     ETYPE_DES_PCBC_NONE,
2702     "des-pcbc-none",
2703     NULL,
2704     8,
2705     8,
2706     0,
2707     &keytype_des,
2708     &checksum_none,
2709     NULL,
2710     F_PSEUDO,
2711     DES_PCBC_encrypt_key_ivec,
2712     0,
2713     NULL
2714 };
2715 static struct encryption_type enctype_des3_cbc_none = {
2716     ETYPE_DES3_CBC_NONE,
2717     "des3-cbc-none",
2718     NULL,
2719     8,
2720     8,
2721     0,
2722     &keytype_des3_derived,
2723     &checksum_none,
2724     NULL,
2725     F_PSEUDO,
2726     DES3_CBC_encrypt,
2727     0,
2728     NULL
2729 };
2730
2731 static struct encryption_type *etypes[] = {
2732     &enctype_null,
2733     &enctype_des_cbc_crc,
2734     &enctype_des_cbc_md4,
2735     &enctype_des_cbc_md5,
2736     &enctype_arcfour_hmac_md5,
2737     &enctype_des3_cbc_md5, 
2738     &enctype_des3_cbc_sha1,
2739     &enctype_old_des3_cbc_sha1,
2740     &enctype_aes128_cts_hmac_sha1,
2741     &enctype_aes256_cts_hmac_sha1,
2742     &enctype_des_cbc_none,
2743     &enctype_des_cfb64_none,
2744     &enctype_des_pcbc_none,
2745     &enctype_des3_cbc_none
2746 };
2747
2748 static unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]);
2749
2750
2751 static struct encryption_type *
2752 _find_enctype(krb5_enctype type)
2753 {
2754     int i;
2755     for(i = 0; i < num_etypes; i++)
2756         if(etypes[i]->type == type)
2757             return etypes[i];
2758     return NULL;
2759 }
2760
2761
2762 krb5_error_code KRB5_LIB_FUNCTION
2763 krb5_enctype_to_string(krb5_context context,
2764                        krb5_enctype etype,
2765                        char **string)
2766 {
2767     struct encryption_type *e;
2768     e = _find_enctype(etype);
2769     if(e == NULL) {
2770         krb5_set_error_string (context, "encryption type %d not supported",
2771                                etype);
2772         *string = NULL;
2773         return KRB5_PROG_ETYPE_NOSUPP;
2774     }
2775     *string = strdup(e->name);
2776     if(*string == NULL) {
2777         krb5_set_error_string(context, "malloc: out of memory");
2778         return ENOMEM;
2779     }
2780     return 0;
2781 }
2782
2783 krb5_error_code KRB5_LIB_FUNCTION
2784 krb5_string_to_enctype(krb5_context context,
2785                        const char *string,
2786                        krb5_enctype *etype)
2787 {
2788     int i;
2789     for(i = 0; i < num_etypes; i++)
2790         if(strcasecmp(etypes[i]->name, string) == 0){
2791             *etype = etypes[i]->type;
2792             return 0;
2793         }
2794     krb5_set_error_string (context, "encryption type %s not supported",
2795                            string);
2796     return KRB5_PROG_ETYPE_NOSUPP;
2797 }
2798
2799 krb5_error_code KRB5_LIB_FUNCTION
2800 _krb5_enctype_to_oid(krb5_context context,
2801                     krb5_enctype etype,
2802                     heim_oid *oid)
2803 {
2804     struct encryption_type *et = _find_enctype(etype);
2805     if(et == NULL) {
2806         krb5_set_error_string (context, "encryption type %d not supported",
2807                                etype);
2808         return KRB5_PROG_ETYPE_NOSUPP;
2809     }
2810     if(et->oid == NULL) {
2811         krb5_set_error_string (context, "%s have not oid", et->name);
2812         return KRB5_PROG_ETYPE_NOSUPP;
2813     }
2814     krb5_clear_error_string(context);
2815     return der_copy_oid(et->oid, oid);
2816 }
2817
2818 krb5_error_code KRB5_LIB_FUNCTION
2819 _krb5_oid_to_enctype(krb5_context context,
2820                      const heim_oid *oid,
2821                      krb5_enctype *etype)
2822 {
2823     int i;
2824     for(i = 0; i < num_etypes; i++) {
2825         if(etypes[i]->oid && der_heim_oid_cmp(etypes[i]->oid, oid) == 0) {
2826             *etype = etypes[i]->type;
2827             return 0;
2828         }
2829     }
2830     krb5_set_error_string(context, "enctype for oid not supported");
2831     return KRB5_PROG_ETYPE_NOSUPP;
2832 }
2833
2834 krb5_error_code KRB5_LIB_FUNCTION
2835 krb5_enctype_to_keytype(krb5_context context,
2836                         krb5_enctype etype,
2837                         krb5_keytype *keytype)
2838 {
2839     struct encryption_type *e = _find_enctype(etype);
2840     if(e == NULL) {
2841         krb5_set_error_string (context, "encryption type %d not supported",
2842                                etype);
2843         return KRB5_PROG_ETYPE_NOSUPP;
2844     }
2845     *keytype = e->keytype->type; /* XXX */
2846     return 0;
2847 }
2848
2849 #if 0
2850 krb5_error_code KRB5_LIB_FUNCTION
2851 krb5_keytype_to_enctype(krb5_context context,
2852                         krb5_keytype keytype,
2853                         krb5_enctype *etype)
2854 {
2855     struct key_type *kt = _find_keytype(keytype);
2856     krb5_warnx(context, "krb5_keytype_to_enctype(%u)", keytype);
2857     if(kt == NULL)
2858         return KRB5_PROG_KEYTYPE_NOSUPP;
2859     *etype = kt->best_etype;
2860     return 0;
2861 }
2862 #endif
2863     
2864 krb5_error_code KRB5_LIB_FUNCTION
2865 krb5_keytype_to_enctypes (krb5_context context,
2866                           krb5_keytype keytype,
2867                           unsigned *len,
2868                           krb5_enctype **val)
2869 {
2870     int i;
2871     unsigned n = 0;
2872     krb5_enctype *ret;
2873
2874     for (i = num_etypes - 1; i >= 0; --i) {
2875         if (etypes[i]->keytype->type == keytype
2876             && !(etypes[i]->flags & F_PSEUDO))
2877             ++n;
2878     }
2879     ret = malloc(n * sizeof(*ret));
2880     if (ret == NULL && n != 0) {
2881         krb5_set_error_string(context, "malloc: out of memory");
2882         return ENOMEM;
2883     }
2884     n = 0;
2885     for (i = num_etypes - 1; i >= 0; --i) {
2886         if (etypes[i]->keytype->type == keytype
2887             && !(etypes[i]->flags & F_PSEUDO))
2888             ret[n++] = etypes[i]->type;
2889     }
2890     *len = n;
2891     *val = ret;
2892     return 0;
2893 }
2894
2895 /*
2896  * First take the configured list of etypes for `keytype' if available,
2897  * else, do `krb5_keytype_to_enctypes'.
2898  */
2899
2900 krb5_error_code KRB5_LIB_FUNCTION
2901 krb5_keytype_to_enctypes_default (krb5_context context,
2902                                   krb5_keytype keytype,
2903                                   unsigned *len,
2904                                   krb5_enctype **val)
2905 {
2906     int i, n;
2907     krb5_enctype *ret;
2908
2909     if (keytype != KEYTYPE_DES || context->etypes_des == NULL)
2910         return krb5_keytype_to_enctypes (context, keytype, len, val);
2911
2912     for (n = 0; context->etypes_des[n]; ++n)
2913         ;
2914     ret = malloc (n * sizeof(*ret));
2915     if (ret == NULL && n != 0) {
2916         krb5_set_error_string(context, "malloc: out of memory");
2917         return ENOMEM;
2918     }
2919     for (i = 0; i < n; ++i)
2920         ret[i] = context->etypes_des[i];
2921     *len = n;
2922     *val = ret;
2923     return 0;
2924 }
2925
2926 krb5_error_code KRB5_LIB_FUNCTION
2927 krb5_enctype_valid(krb5_context context, 
2928                  krb5_enctype etype)
2929 {
2930     struct encryption_type *e = _find_enctype(etype);
2931     if(e == NULL) {
2932         krb5_set_error_string (context, "encryption type %d not supported",
2933                                etype);
2934         return KRB5_PROG_ETYPE_NOSUPP;
2935     }
2936     if (e->flags & F_DISABLED) {
2937         krb5_set_error_string (context, "encryption type %s is disabled",
2938                                e->name);
2939         return KRB5_PROG_ETYPE_NOSUPP;
2940     }
2941     return 0;
2942 }
2943
2944 krb5_error_code KRB5_LIB_FUNCTION
2945 krb5_cksumtype_valid(krb5_context context, 
2946                      krb5_cksumtype ctype)
2947 {
2948     struct checksum_type *c = _find_checksum(ctype);
2949     if (c == NULL) {
2950         krb5_set_error_string (context, "checksum type %d not supported",
2951                                ctype);
2952         return KRB5_PROG_SUMTYPE_NOSUPP;
2953     }
2954     if (c->flags & F_DISABLED) {
2955         krb5_set_error_string (context, "checksum type %s is disabled",
2956                                c->name);
2957         return KRB5_PROG_SUMTYPE_NOSUPP;
2958     }
2959     return 0;
2960 }
2961
2962
2963 /* if two enctypes have compatible keys */
2964 krb5_boolean KRB5_LIB_FUNCTION
2965 krb5_enctypes_compatible_keys(krb5_context context,
2966                               krb5_enctype etype1,
2967                               krb5_enctype etype2)
2968 {
2969     struct encryption_type *e1 = _find_enctype(etype1);
2970     struct encryption_type *e2 = _find_enctype(etype2);
2971     return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2972 }
2973
2974 static krb5_boolean
2975 derived_crypto(krb5_context context,
2976                krb5_crypto crypto)
2977 {
2978     return (crypto->et->flags & F_DERIVED) != 0;
2979 }
2980
2981 static krb5_boolean
2982 special_crypto(krb5_context context,
2983                krb5_crypto crypto)
2984 {
2985     return (crypto->et->flags & F_SPECIAL) != 0;
2986 }
2987
2988 #define CHECKSUMSIZE(C) ((C)->checksumsize)
2989 #define CHECKSUMTYPE(C) ((C)->type)
2990
2991 static krb5_error_code
2992 encrypt_internal_derived(krb5_context context,
2993                          krb5_crypto crypto,
2994                          unsigned usage,
2995                          const void *data,
2996                          size_t len,
2997                          krb5_data *result,
2998                          void *ivec)
2999 {
3000     size_t sz, block_sz, checksum_sz, total_sz;
3001     Checksum cksum;
3002     unsigned char *p, *q;
3003     krb5_error_code ret;
3004     struct key_data *dkey;
3005     const struct encryption_type *et = crypto->et;
3006     
3007     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
3008
3009     sz = et->confoundersize + len;
3010     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
3011     total_sz = block_sz + checksum_sz;
3012     p = calloc(1, total_sz);
3013     if(p == NULL) {
3014         krb5_set_error_string(context, "malloc: out of memory");
3015         return ENOMEM;
3016     }
3017     
3018     q = p;
3019     krb5_generate_random_block(q, et->confoundersize); /* XXX */
3020     q += et->confoundersize;
3021     memcpy(q, data, len);
3022     
3023     ret = create_checksum(context, 
3024                           et->keyed_checksum,
3025                           crypto, 
3026                           INTEGRITY_USAGE(usage),
3027                           p, 
3028                           block_sz,
3029                           &cksum);
3030     if(ret == 0 && cksum.checksum.length != checksum_sz) {
3031         free_Checksum (&cksum);
3032         krb5_clear_error_string (context);
3033         ret = KRB5_CRYPTO_INTERNAL;
3034     }
3035     if(ret)
3036         goto fail;
3037     memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
3038     free_Checksum (&cksum);
3039     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
3040     if(ret)
3041         goto fail;
3042     ret = _key_schedule(context, dkey);
3043     if(ret)
3044         goto fail;
3045 #ifdef CRYPTO_DEBUG
3046     krb5_crypto_debug(context, 1, block_sz, dkey->key);
3047 #endif
3048     ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
3049     if (ret)
3050         goto fail;
3051     result->data = p;
3052     result->length = total_sz;
3053     return 0;
3054  fail:
3055     memset(p, 0, total_sz);
3056     free(p);
3057     return ret;
3058 }
3059
3060
3061 static krb5_error_code
3062 encrypt_internal(krb5_context context,
3063                  krb5_crypto crypto,
3064                  const void *data,
3065                  size_t len,
3066                  krb5_data *result,
3067                  void *ivec)
3068 {
3069     size_t sz, block_sz, checksum_sz;
3070     Checksum cksum;
3071     unsigned char *p, *q;
3072     krb5_error_code ret;
3073     const struct encryption_type *et = crypto->et;
3074     
3075     checksum_sz = CHECKSUMSIZE(et->checksum);
3076     
3077     sz = et->confoundersize + checksum_sz + len;
3078     block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
3079     p = calloc(1, block_sz);
3080     if(p == NULL) {
3081         krb5_set_error_string(context, "malloc: out of memory");
3082         return ENOMEM;
3083     }
3084     
3085     q = p;
3086     krb5_generate_random_block(q, et->confoundersize); /* XXX */
3087     q += et->confoundersize;
3088     memset(q, 0, checksum_sz);
3089     q += checksum_sz;
3090     memcpy(q, data, len);
3091
3092     ret = create_checksum(context, 
3093                           et->checksum,
3094                           crypto,
3095                           0,
3096                           p, 
3097                           block_sz,
3098                           &cksum);
3099     if(ret == 0 && cksum.checksum.length != checksum_sz) {
3100         krb5_clear_error_string (context);
3101         free_Checksum(&cksum);
3102         ret = KRB5_CRYPTO_INTERNAL;
3103     }
3104     if(ret)
3105         goto fail;
3106     memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
3107     free_Checksum(&cksum);
3108     ret = _key_schedule(context, &crypto->key);
3109     if(ret)
3110         goto fail;
3111 #ifdef CRYPTO_DEBUG
3112     krb5_crypto_debug(context, 1, block_sz, crypto->key.key);
3113 #endif
3114     ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
3115     if (ret) {
3116         memset(p, 0, block_sz);
3117         free(p);
3118         return ret;
3119     }
3120     result->data = p;
3121     result->length = block_sz;
3122     return 0;
3123  fail:
3124     memset(p, 0, block_sz);
3125     free(p);
3126     return ret;
3127 }
3128
3129 static krb5_error_code
3130 encrypt_internal_special(krb5_context context,
3131                          krb5_crypto crypto,
3132                          int usage,
3133                          const void *data,
3134                          size_t len,
3135                          krb5_data *result,
3136                          void *ivec)
3137 {
3138     struct encryption_type *et = crypto->et;
3139     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
3140     size_t sz = len + cksum_sz + et->confoundersize;
3141     char *tmp, *p;
3142     krb5_error_code ret;
3143
3144     tmp = malloc (sz);
3145     if (tmp == NULL) {
3146         krb5_set_error_string(context, "malloc: out of memory");
3147         return ENOMEM;
3148     }
3149     p = tmp;
3150     memset (p, 0, cksum_sz);
3151     p += cksum_sz;
3152     krb5_generate_random_block(p, et->confoundersize);
3153     p += et->confoundersize;
3154     memcpy (p, data, len);
3155     ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
3156     if (ret) {
3157         memset(tmp, 0, sz);
3158         free(tmp);
3159         return ret;
3160     }
3161     result->data   = tmp;
3162     result->length = sz;
3163     return 0;
3164 }
3165
3166 static krb5_error_code
3167 decrypt_internal_derived(krb5_context context,
3168                          krb5_crypto crypto,
3169                          unsigned usage,
3170                          void *data,
3171                          size_t len,
3172                          krb5_data *result,
3173                          void *ivec)
3174 {
3175     size_t checksum_sz;
3176     Checksum cksum;
3177     unsigned char *p;
3178     krb5_error_code ret;
3179     struct key_data *dkey;
3180     struct encryption_type *et = crypto->et;
3181     unsigned long l;
3182     
3183     checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
3184     if (len < checksum_sz + et->confoundersize) {
3185         krb5_set_error_string(context, "Encrypted data shorter then "
3186                               "checksum + confunder");
3187         return KRB5_BAD_MSIZE;
3188     }
3189
3190     if (((len - checksum_sz) % et->padsize) != 0) {
3191         krb5_clear_error_string(context);
3192         return KRB5_BAD_MSIZE;
3193     }
3194
3195     p = malloc(len);
3196     if(len != 0 && p == NULL) {
3197         krb5_set_error_string(context, "malloc: out of memory");
3198         return ENOMEM;
3199     }
3200     memcpy(p, data, len);
3201
3202     len -= checksum_sz;
3203
3204     ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
3205     if(ret) {
3206         free(p);
3207         return ret;
3208     }
3209     ret = _key_schedule(context, dkey);
3210     if(ret) {
3211         free(p);
3212         return ret;
3213     }
3214 #ifdef CRYPTO_DEBUG
3215     krb5_crypto_debug(context, 0, len, dkey->key);
3216 #endif
3217     ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
3218     if (ret) {
3219         free(p);
3220         return ret;
3221     }
3222
3223     cksum.checksum.data   = p + len;
3224     cksum.checksum.length = checksum_sz;
3225     cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
3226
3227     ret = verify_checksum(context,
3228                           crypto,
3229                           INTEGRITY_USAGE(usage),
3230                           p,
3231                           len,
3232                           &cksum);
3233     if(ret) {
3234         free(p);
3235         return ret;
3236     }
3237     l = len - et->confoundersize;
3238     memmove(p, p + et->confoundersize, l);
3239     result->data = realloc(p, l);
3240     if(result->data == NULL && l != 0) {
3241         free(p);
3242         krb5_set_error_string(context, "malloc: out of memory");
3243         return ENOMEM;
3244     }
3245     result->length = l;
3246     return 0;
3247 }
3248
3249 static krb5_error_code
3250 decrypt_internal(krb5_context context,
3251                  krb5_crypto crypto,
3252                  void *data,
3253                  size_t len,
3254                  krb5_data *result,
3255                  void *ivec)
3256 {
3257     krb5_error_code ret;
3258     unsigned char *p;
3259     Checksum cksum;
3260     size_t checksum_sz, l;
3261     struct encryption_type *et = crypto->et;
3262     
3263     if ((len % et->padsize) != 0) {
3264         krb5_clear_error_string(context);
3265         return KRB5_BAD_MSIZE;
3266     }
3267
3268     checksum_sz = CHECKSUMSIZE(et->checksum);
3269     p = malloc(len);
3270     if(len != 0 && p == NULL) {
3271         krb5_set_error_string(context, "malloc: out of memory");
3272         return ENOMEM;
3273     }
3274     memcpy(p, data, len);
3275     
3276     ret = _key_schedule(context, &crypto->key);
3277     if(ret) {
3278         free(p);
3279         return ret;
3280     }
3281 #ifdef CRYPTO_DEBUG
3282     krb5_crypto_debug(context, 0, len, crypto->key.key);
3283 #endif
3284     ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
3285     if (ret) {
3286         free(p);
3287         return ret;
3288     }
3289     ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
3290     if(ret) {
3291         free(p);
3292         return ret;
3293     }
3294     memset(p + et->confoundersize, 0, checksum_sz);
3295     cksum.cksumtype = CHECKSUMTYPE(et->checksum);
3296     ret = verify_checksum(context, NULL, 0, p, len, &cksum);
3297     free_Checksum(&cksum);
3298     if(ret) {
3299         free(p);
3300         return ret;
3301     }
3302     l = len - et->confoundersize - checksum_sz;
3303     memmove(p, p + et->confoundersize + checksum_sz, l);
3304     result->data = realloc(p, l);
3305     if(result->data == NULL && l != 0) {
3306         free(p);
3307         krb5_set_error_string(context, "malloc: out of memory");
3308         return ENOMEM;
3309     }
3310     result->length = l;
3311     return 0;
3312 }
3313
3314 static krb5_error_code
3315 decrypt_internal_special(krb5_context context,
3316                          krb5_crypto crypto,
3317                          int usage,
3318                          void *data,
3319                          size_t len,
3320                          krb5_data *result,
3321                          void *ivec)
3322 {
3323     struct encryption_type *et = crypto->et;
3324     size_t cksum_sz = CHECKSUMSIZE(et->checksum);
3325     size_t sz = len - cksum_sz - et->confoundersize;
3326     unsigned char *p;
3327     krb5_error_code ret;
3328
3329     if ((len % et->padsize) != 0) {
3330         krb5_clear_error_string(context);
3331         return KRB5_BAD_MSIZE;
3332     }
3333
3334     p = malloc (len);
3335     if (p == NULL) {
3336         krb5_set_error_string(context, "malloc: out of memory");
3337         return ENOMEM;
3338     }
3339     memcpy(p, data, len);
3340     
3341     ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
3342     if (ret) {
3343         free(p);
3344         return ret;
3345     }
3346
3347     memmove (p, p + cksum_sz + et->confoundersize, sz);
3348     result->data = realloc(p, sz);
3349     if(result->data == NULL && sz != 0) {
3350         free(p);
3351         krb5_set_error_string(context, "malloc: out of memory");
3352         return ENOMEM;
3353     }
3354     result->length = sz;
3355     return 0;
3356 }
3357
3358
3359 krb5_error_code KRB5_LIB_FUNCTION
3360 krb5_encrypt_ivec(krb5_context context,
3361                   krb5_crypto crypto,
3362                   unsigned usage,
3363                   const void *data,
3364                   size_t len,
3365                   krb5_data *result,
3366                   void *ivec)
3367 {
3368     if(derived_crypto(context, crypto))
3369         return encrypt_internal_derived(context, crypto, usage, 
3370                                         data, len, result, ivec);
3371     else if (special_crypto(context, crypto))
3372         return encrypt_internal_special (context, crypto, usage,
3373                                          data, len, result, ivec);
3374     else
3375         return encrypt_internal(context, crypto, data, len, result, ivec);
3376 }
3377
3378 krb5_error_code KRB5_LIB_FUNCTION
3379 krb5_encrypt(krb5_context context,
3380              krb5_crypto crypto,
3381              unsigned usage,
3382              const void *data,
3383              size_t len,
3384              krb5_data *result)
3385 {
3386     return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
3387 }
3388
3389 krb5_error_code KRB5_LIB_FUNCTION
3390 krb5_encrypt_EncryptedData(krb5_context context,
3391                            krb5_crypto crypto,
3392                            unsigned usage,
3393                            void *data,
3394                            size_t len,
3395                            int kvno,
3396                            EncryptedData *result)
3397 {
3398     result->etype = CRYPTO_ETYPE(crypto);
3399     if(kvno){
3400         ALLOC(result->kvno, 1);
3401         *result->kvno = kvno;
3402     }else
3403         result->kvno = NULL;
3404     return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
3405 }
3406
3407 krb5_error_code KRB5_LIB_FUNCTION
3408 krb5_decrypt_ivec(krb5_context context,
3409                   krb5_crypto crypto,
3410                   unsigned usage,
3411                   void *data,
3412                   size_t len,
3413                   krb5_data *result,
3414                   void *ivec)
3415 {
3416     if(derived_crypto(context, crypto))
3417         return decrypt_internal_derived(context, crypto, usage, 
3418                                         data, len, result, ivec);
3419     else if (special_crypto (context, crypto))
3420         return decrypt_internal_special(context, crypto, usage,
3421                                         data, len, result, ivec);
3422     else
3423         return decrypt_internal(context, crypto, data, len, result, ivec);
3424 }
3425
3426 krb5_error_code KRB5_LIB_FUNCTION
3427 krb5_decrypt(krb5_context context,
3428              krb5_crypto crypto,
3429              unsigned usage,
3430              void *data,
3431              size_t len,
3432              krb5_data *result)
3433 {
3434     return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
3435                               NULL);
3436 }
3437
3438 krb5_error_code KRB5_LIB_FUNCTION
3439 krb5_decrypt_EncryptedData(krb5_context context,
3440                            krb5_crypto crypto,
3441                            unsigned usage,
3442                            const EncryptedData *e,
3443                            krb5_data *result)
3444 {
3445     return krb5_decrypt(context, crypto, usage, 
3446                         e->cipher.data, e->cipher.length, result);
3447 }
3448
3449 /************************************************************
3450  *                                                          *
3451  ************************************************************/
3452
3453 #define ENTROPY_NEEDED 128
3454
3455 static int
3456 seed_something(void)
3457 {
3458     char buf[1024], seedfile[256];
3459
3460     /* If there is a seed file, load it. But such a file cannot be trusted,
3461        so use 0 for the entropy estimate */
3462     if (RAND_file_name(seedfile, sizeof(seedfile))) {
3463         int fd;
3464         fd = open(seedfile, O_RDONLY);
3465         if (fd >= 0) {
3466             ssize_t ret;
3467             ret = read(fd, buf, sizeof(buf));
3468             if (ret > 0)
3469                 RAND_add(buf, ret, 0.0);
3470             close(fd);
3471         } else
3472             seedfile[0] = '\0';
3473     } else
3474         seedfile[0] = '\0';
3475
3476     /* Calling RAND_status() will try to use /dev/urandom if it exists so
3477        we do not have to deal with it. */
3478     if (RAND_status() != 1) {
3479         krb5_context context;
3480         const char *p;
3481
3482         /* Try using egd */
3483         if (!krb5_init_context(&context)) {
3484             p = krb5_config_get_string(context, NULL, "libdefaults",
3485                 "egd_socket", NULL);
3486             if (p != NULL)
3487                 RAND_egd_bytes(p, ENTROPY_NEEDED);
3488             krb5_free_context(context);
3489         }
3490     }
3491     
3492     if (RAND_status() == 1)     {
3493         /* Update the seed file */
3494         if (seedfile[0])
3495             RAND_write_file(seedfile);
3496
3497         return 0;
3498     } else
3499         return -1;
3500 }
3501
3502 void KRB5_LIB_FUNCTION
3503 krb5_generate_random_block(void *buf, size_t len)
3504 {
3505     static int rng_initialized = 0;
3506     
3507     HEIMDAL_MUTEX_lock(&crypto_mutex);
3508     if (!rng_initialized) {
3509         if (seed_something())
3510             krb5_abortx(NULL, "Fatal: could not seed the "
3511                         "random number generator");
3512         
3513         rng_initialized = 1;
3514     }
3515     HEIMDAL_MUTEX_unlock(&crypto_mutex);
3516     if (RAND_bytes(buf, len) != 1)
3517         krb5_abortx(NULL, "Failed to generate random block");
3518 }
3519
3520 static void
3521 DES3_postproc(krb5_context context,
3522               unsigned char *k, size_t len, struct key_data *key)
3523 {
3524     DES3_random_to_key(context, key->key, k, len);
3525
3526     if (key->schedule) {
3527         krb5_free_data(context, key->schedule);
3528         key->schedule = NULL;
3529     }
3530 }
3531
3532 static krb5_error_code
3533 derive_key(krb5_context context,
3534            struct encryption_type *et,
3535            struct key_data *key,
3536            const void *constant,
3537            size_t len)
3538 {
3539     unsigned char *k;
3540     unsigned int nblocks = 0, i;
3541     krb5_error_code ret = 0;
3542     struct key_type *kt = et->keytype;
3543
3544     ret = _key_schedule(context, key);
3545     if(ret)
3546         return ret;
3547     if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
3548         nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
3549         k = malloc(nblocks * et->blocksize);
3550         if(k == NULL) {
3551             krb5_set_error_string(context, "malloc: out of memory");
3552             return ENOMEM;
3553         }
3554         ret = _krb5_n_fold(constant, len, k, et->blocksize);
3555         if (ret) {
3556             free(k);
3557             krb5_set_error_string(context, "out of memory");
3558             return ret;
3559         }
3560         for(i = 0; i < nblocks; i++) {
3561             if(i > 0)
3562                 memcpy(k + i * et->blocksize, 
3563                        k + (i - 1) * et->blocksize,
3564                        et->blocksize);
3565             (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
3566                            1, 0, NULL);
3567         }
3568     } else {
3569         /* this case is probably broken, but won't be run anyway */
3570         void *c = malloc(len);
3571         size_t res_len = (kt->bits + 7) / 8;
3572
3573         if(len != 0 && c == NULL) {
3574             krb5_set_error_string(context, "malloc: out of memory");
3575             return ENOMEM;
3576         }
3577         memcpy(c, constant, len);
3578         (*et->encrypt)(context, key, c, len, 1, 0, NULL);
3579         k = malloc(res_len);
3580         if(res_len != 0 && k == NULL) {
3581             free(c);
3582             krb5_set_error_string(context, "malloc: out of memory");
3583             return ENOMEM;
3584         }
3585         ret = _krb5_n_fold(c, len, k, res_len);
3586         if (ret) {
3587             free(k);
3588             krb5_set_error_string(context, "out of memory");
3589             return ret;
3590         }
3591         free(c);
3592     }
3593     
3594     /* XXX keytype dependent post-processing */
3595     switch(kt->type) {
3596     case KEYTYPE_DES3:
3597         DES3_postproc(context, k, nblocks * et->blocksize, key);
3598         break;
3599     case KEYTYPE_AES128:
3600     case KEYTYPE_AES256:
3601         memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
3602         break;
3603     default:
3604         krb5_set_error_string(context,
3605                               "derive_key() called with unknown keytype (%u)", 
3606                               kt->type);
3607         ret = KRB5_CRYPTO_INTERNAL;
3608         break;
3609     }
3610     if (key->schedule) {
3611         krb5_free_data(context, key->schedule);
3612         key->schedule = NULL;
3613     }
3614     memset(k, 0, nblocks * et->blocksize);
3615     free(k);
3616     return ret;
3617 }
3618
3619 static struct key_data *
3620 _new_derived_key(krb5_crypto crypto, unsigned usage)
3621 {
3622     struct key_usage *d = crypto->key_usage;
3623     d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
3624     if(d == NULL)
3625         return NULL;
3626     crypto->key_usage = d;
3627     d += crypto->num_key_usage++;
3628     memset(d, 0, sizeof(*d));
3629     d->usage = usage;
3630     return &d->key;
3631 }
3632
3633 krb5_error_code KRB5_LIB_FUNCTION
3634 krb5_derive_key(krb5_context context,
3635                 const krb5_keyblock *key,
3636                 krb5_enctype etype,
3637                 const void *constant,
3638                 size_t constant_len,
3639                 krb5_keyblock **derived_key)
3640 {
3641     krb5_error_code ret;
3642     struct encryption_type *et;
3643     struct key_data d;
3644
3645     *derived_key = NULL;
3646
3647     et = _find_enctype (etype);
3648     if (et == NULL) {
3649         krb5_set_error_string(context, "encryption type %d not supported",
3650                               etype);
3651         return KRB5_PROG_ETYPE_NOSUPP;
3652     }
3653
3654     ret = krb5_copy_keyblock(context, key, &d.key);
3655     if (ret)
3656         return ret;
3657
3658     d.schedule = NULL;
3659     ret = derive_key(context, et, &d, constant, constant_len);
3660     if (ret == 0)
3661         ret = krb5_copy_keyblock(context, d.key, derived_key);
3662     free_key_data(context, &d);    
3663     return ret;
3664 }
3665
3666 static krb5_error_code
3667 _get_derived_key(krb5_context context, 
3668                  krb5_crypto crypto, 
3669                  unsigned usage, 
3670                  struct key_data **key)
3671 {
3672     int i;
3673     struct key_data *d;
3674     unsigned char constant[5];
3675
3676     for(i = 0; i < crypto->num_key_usage; i++)
3677         if(crypto->key_usage[i].usage == usage) {
3678             *key = &crypto->key_usage[i].key;
3679             return 0;
3680         }
3681     d = _new_derived_key(crypto, usage);
3682     if(d == NULL) {
3683         krb5_set_error_string(context, "malloc: out of memory");
3684         return ENOMEM;
3685     }
3686     krb5_copy_keyblock(context, crypto->key.key, &d->key);
3687     _krb5_put_int(constant, usage, 5);
3688     derive_key(context, crypto->et, d, constant, sizeof(constant));
3689     *key = d;
3690     return 0;
3691 }
3692
3693
3694 krb5_error_code KRB5_LIB_FUNCTION
3695 krb5_crypto_init(krb5_context context,
3696                  const krb5_keyblock *key,
3697                  krb5_enctype etype,
3698                  krb5_crypto *crypto)
3699 {
3700     krb5_error_code ret;
3701     ALLOC(*crypto, 1);
3702     if(*crypto == NULL) {
3703         krb5_set_error_string(context, "malloc: out of memory");
3704         return ENOMEM;
3705     }
3706     if(etype == ETYPE_NULL)
3707         etype = key->keytype;
3708     (*crypto)->et = _find_enctype(etype);
3709     if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
3710         free(*crypto);
3711         *crypto = NULL;
3712         krb5_set_error_string (context, "encryption type %d not supported",
3713                                etype);
3714         return KRB5_PROG_ETYPE_NOSUPP;
3715     }
3716     if((*crypto)->et->keytype->size != key->keyvalue.length) {
3717         free(*crypto);
3718         *crypto = NULL;
3719         krb5_set_error_string (context, "encryption key has bad length");
3720         return KRB5_BAD_KEYSIZE;
3721     }
3722     ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
3723     if(ret) {
3724         free(*crypto);
3725         *crypto = NULL;
3726         return ret;
3727     }
3728     (*crypto)->key.schedule = NULL;
3729     (*crypto)->num_key_usage = 0;
3730     (*crypto)->key_usage = NULL;
3731     return 0;
3732 }
3733
3734 static void
3735 free_key_data(krb5_context context, struct key_data *key)
3736 {
3737     krb5_free_keyblock(context, key->key);
3738     if(key->schedule) {
3739         memset(key->schedule->data, 0, key->schedule->length);
3740         krb5_free_data(context, key->schedule);
3741     }
3742 }
3743
3744 static void
3745 free_key_usage(krb5_context context, struct key_usage *ku)
3746 {
3747     free_key_data(context, &ku->key);
3748 }
3749
3750 krb5_error_code KRB5_LIB_FUNCTION
3751 krb5_crypto_destroy(krb5_context context,
3752                     krb5_crypto crypto)
3753 {
3754     int i;
3755     
3756     for(i = 0; i < crypto->num_key_usage; i++)
3757         free_key_usage(context, &crypto->key_usage[i]);
3758     free(crypto->key_usage);
3759     free_key_data(context, &crypto->key);
3760     free (crypto);
3761     return 0;
3762 }
3763
3764 krb5_error_code KRB5_LIB_FUNCTION
3765 krb5_crypto_getblocksize(krb5_context context,
3766                          krb5_crypto crypto,
3767                          size_t *blocksize)
3768 {
3769     *blocksize = crypto->et->blocksize;
3770     return 0;
3771 }
3772
3773 krb5_error_code KRB5_LIB_FUNCTION
3774 krb5_crypto_getenctype(krb5_context context,
3775                        krb5_crypto crypto,
3776                        krb5_enctype *enctype)
3777 {
3778     *enctype = crypto->et->type;
3779      return 0;
3780 }
3781
3782 krb5_error_code KRB5_LIB_FUNCTION
3783 krb5_crypto_getpadsize(krb5_context context,
3784                        krb5_crypto crypto,
3785                        size_t *padsize)      
3786 {
3787     *padsize = crypto->et->padsize;
3788     return 0;
3789 }
3790
3791 krb5_error_code KRB5_LIB_FUNCTION
3792 krb5_crypto_getconfoundersize(krb5_context context,
3793                               krb5_crypto crypto,
3794                               size_t *confoundersize)
3795 {
3796     *confoundersize = crypto->et->confoundersize;
3797     return 0;
3798 }
3799
3800 krb5_error_code KRB5_LIB_FUNCTION
3801 krb5_enctype_disable(krb5_context context,
3802                      krb5_enctype enctype)
3803 {
3804     struct encryption_type *et = _find_enctype(enctype);
3805     if(et == NULL) {
3806         if (context)
3807             krb5_set_error_string (context, "encryption type %d not supported",
3808                                    enctype);
3809         return KRB5_PROG_ETYPE_NOSUPP;
3810     }
3811     et->flags |= F_DISABLED;
3812     return 0;
3813 }
3814
3815 krb5_error_code KRB5_LIB_FUNCTION
3816 krb5_string_to_key_derived(krb5_context context,
3817                            const void *str,
3818                            size_t len,
3819                            krb5_enctype etype,
3820                            krb5_keyblock *key)
3821 {
3822     struct encryption_type *et = _find_enctype(etype);
3823     krb5_error_code ret;
3824     struct key_data kd;
3825     size_t keylen;
3826     u_char *tmp;
3827
3828     if(et == NULL) {
3829         krb5_set_error_string (context, "encryption type %d not supported",
3830                                etype);
3831         return KRB5_PROG_ETYPE_NOSUPP;
3832     }
3833     keylen = et->keytype->bits / 8;
3834
3835     ALLOC(kd.key, 1);
3836     if(kd.key == NULL) {
3837         krb5_set_error_string (context, "malloc: out of memory");
3838         return ENOMEM;
3839     }
3840     ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
3841     if(ret) {
3842         free(kd.key);
3843         return ret;
3844     }
3845     kd.key->keytype = etype;
3846     tmp = malloc (keylen);
3847     if(tmp == NULL) {
3848         krb5_free_keyblock(context, kd.key);
3849         krb5_set_error_string (context, "malloc: out of memory");
3850         return ENOMEM;
3851     }
3852     ret = _krb5_n_fold(str, len, tmp, keylen);
3853     if (ret) {
3854         free(tmp);
3855         krb5_set_error_string(context, "out of memory");
3856         return ret;
3857     }
3858     kd.schedule = NULL;
3859     DES3_postproc (context, tmp, keylen, &kd); /* XXX */
3860     memset(tmp, 0, keylen);
3861     free(tmp);
3862     ret = derive_key(context, 
3863                      et,
3864                      &kd,
3865                      "kerberos", /* XXX well known constant */
3866                      strlen("kerberos"));
3867     ret = krb5_copy_keyblock_contents(context, kd.key, key);
3868     free_key_data(context, &kd);
3869     return ret;
3870 }
3871
3872 static size_t
3873 wrapped_length (krb5_context context,
3874                 krb5_crypto  crypto,
3875                 size_t       data_len)
3876 {
3877     struct encryption_type *et = crypto->et;
3878     size_t padsize = et->padsize;
3879     size_t checksumsize = CHECKSUMSIZE(et->checksum);
3880     size_t res;
3881
3882     res =  et->confoundersize + checksumsize + data_len;
3883     res =  (res + padsize - 1) / padsize * padsize;
3884     return res;
3885 }
3886
3887 static size_t
3888 wrapped_length_dervied (krb5_context context,
3889                         krb5_crypto  crypto,
3890                         size_t       data_len)
3891 {
3892     struct encryption_type *et = crypto->et;
3893     size_t padsize = et->padsize;
3894     size_t res;
3895
3896     res =  et->confoundersize + data_len;
3897     res =  (res + padsize - 1) / padsize * padsize;
3898     if (et->keyed_checksum)
3899         res += et->keyed_checksum->checksumsize;
3900     else
3901         res += et->checksum->checksumsize;
3902     return res;
3903 }
3904
3905 /*
3906  * Return the size of an encrypted packet of length `data_len'
3907  */
3908
3909 size_t
3910 krb5_get_wrapped_length (krb5_context context,
3911                          krb5_crypto  crypto,
3912                          size_t       data_len)
3913 {
3914     if (derived_crypto (context, crypto))
3915         return wrapped_length_dervied (context, crypto, data_len);
3916     else
3917         return wrapped_length (context, crypto, data_len);
3918 }
3919
3920 /*
3921  * Return the size of an encrypted packet of length `data_len'
3922  */
3923
3924 static size_t
3925 crypto_overhead (krb5_context context,
3926                  krb5_crypto  crypto)
3927 {
3928     struct encryption_type *et = crypto->et;
3929     size_t res;
3930
3931     res = CHECKSUMSIZE(et->checksum);
3932     res += et->confoundersize;
3933     if (et->padsize > 1)
3934         res += et->padsize;
3935     return res;
3936 }
3937
3938 static size_t
3939 crypto_overhead_dervied (krb5_context context,
3940                          krb5_crypto  crypto)
3941 {
3942     struct encryption_type *et = crypto->et;
3943     size_t res;
3944
3945     if (et->keyed_checksum)
3946         res = CHECKSUMSIZE(et->keyed_checksum);
3947     else
3948         res = CHECKSUMSIZE(et->checksum);
3949     res += et->confoundersize;
3950     if (et->padsize > 1)
3951         res += et->padsize;
3952     return res;
3953 }
3954
3955 size_t
3956 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
3957 {
3958     if (derived_crypto (context, crypto))
3959         return crypto_overhead_dervied (context, crypto);
3960     else
3961         return crypto_overhead (context, crypto);
3962 }
3963
3964 krb5_error_code KRB5_LIB_FUNCTION
3965 krb5_random_to_key(krb5_context context,
3966                    krb5_enctype type,
3967                    const void *data,
3968                    size_t size,
3969                    krb5_keyblock *key)
3970 {
3971     krb5_error_code ret;
3972     struct encryption_type *et = _find_enctype(type);
3973     if(et == NULL) {
3974         krb5_set_error_string(context, "encryption type %d not supported",
3975                               type);
3976         return KRB5_PROG_ETYPE_NOSUPP;
3977     }
3978     if ((et->keytype->bits + 7) / 8 > size) {
3979         krb5_set_error_string(context, "encryption key %s needs %d bytes "
3980                               "of random to make an encryption key out of it",
3981                               et->name, (int)et->keytype->size);
3982         return KRB5_PROG_ETYPE_NOSUPP;
3983     }
3984     ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
3985     if(ret) 
3986         return ret;
3987     key->keytype = type;
3988     if (et->keytype->random_to_key)
3989         (*et->keytype->random_to_key)(context, key, data, size);
3990     else
3991         memcpy(key->keyvalue.data, data, et->keytype->size);
3992
3993     return 0;
3994 }
3995
3996 krb5_error_code
3997 _krb5_pk_octetstring2key(krb5_context context,
3998                          krb5_enctype type,
3999                          const void *dhdata,
4000                          size_t dhsize,
4001                          const heim_octet_string *c_n,
4002                          const heim_octet_string *k_n,
4003                          krb5_keyblock *key)
4004 {
4005     struct encryption_type *et = _find_enctype(type);
4006     krb5_error_code ret;
4007     size_t keylen, offset;
4008     void *keydata;
4009     unsigned char counter;
4010     unsigned char shaoutput[20];
4011
4012     if(et == NULL) {
4013         krb5_set_error_string(context, "encryption type %d not supported",
4014                               type);
4015         return KRB5_PROG_ETYPE_NOSUPP;
4016     }
4017     keylen = (et->keytype->bits + 7) / 8;
4018
4019     keydata = malloc(keylen);
4020     if (keydata == NULL) {
4021         krb5_set_error_string(context, "malloc: out of memory");
4022         return ENOMEM;
4023     }
4024
4025     counter = 0;
4026     offset = 0;
4027     do {
4028         SHA_CTX m;
4029         
4030         SHA1_Init(&m);
4031         SHA1_Update(&m, &counter, 1);
4032         SHA1_Update(&m, dhdata, dhsize);
4033         if (c_n)
4034             SHA1_Update(&m, c_n->data, c_n->length);
4035         if (k_n)
4036             SHA1_Update(&m, k_n->data, k_n->length);
4037         SHA1_Final(shaoutput, &m);
4038
4039         memcpy((unsigned char *)keydata + offset,
4040                shaoutput,
4041                min(keylen - offset, sizeof(shaoutput)));
4042
4043         offset += sizeof(shaoutput);
4044         counter++;
4045     } while(offset < keylen);
4046     memset(shaoutput, 0, sizeof(shaoutput));
4047
4048     ret = krb5_random_to_key(context, type, keydata, keylen, key);
4049     memset(keydata, 0, sizeof(keylen));
4050     free(keydata);
4051     return ret;
4052 }
4053
4054 krb5_error_code KRB5_LIB_FUNCTION
4055 krb5_crypto_prf_length(krb5_context context,
4056                        krb5_enctype type,
4057                        size_t *length)
4058 {
4059     struct encryption_type *et = _find_enctype(type);
4060
4061     if(et == NULL || et->prf_length == 0) {
4062         krb5_set_error_string(context, "encryption type %d not supported",
4063                               type);
4064         return KRB5_PROG_ETYPE_NOSUPP;
4065     }
4066
4067     *length = et->prf_length;
4068     return 0;
4069 }
4070
4071 krb5_error_code KRB5_LIB_FUNCTION
4072 krb5_crypto_prf(krb5_context context,
4073                 const krb5_crypto crypto,
4074                 const krb5_data *input, 
4075                 krb5_data *output)
4076 {
4077     struct encryption_type *et = crypto->et;
4078
4079     krb5_data_zero(output);
4080
4081     if(et->prf == NULL) {
4082         krb5_set_error_string(context, "kerberos prf for %s not supported",
4083                               et->name);
4084         return KRB5_PROG_ETYPE_NOSUPP;
4085     }
4086
4087     return (*et->prf)(context, crypto, input, output);
4088 }
4089         
4090
4091
4092
4093 #ifdef CRYPTO_DEBUG
4094
4095 static krb5_error_code
4096 krb5_get_keyid(krb5_context context,
4097                krb5_keyblock *key,
4098                uint32_t *keyid)
4099 {
4100     MD5_CTX md5;
4101     unsigned char tmp[16];
4102
4103     MD5_Init (&md5);
4104     MD5_Update (&md5, key->keyvalue.data, key->keyvalue.length);
4105     MD5_Final (tmp, &md5);
4106     *keyid = (tmp[12] << 24) | (tmp[13] << 16) | (tmp[14] << 8) | tmp[15];
4107     return 0;
4108 }
4109
4110 static void
4111 krb5_crypto_debug(krb5_context context,
4112                   int encryptp,
4113                   size_t len,
4114                   krb5_keyblock *key)
4115 {
4116     uint32_t keyid;
4117     char *kt;
4118     krb5_get_keyid(context, key, &keyid);
4119     krb5_enctype_to_string(context, key->keytype, &kt);
4120     krb5_warnx(context, "%s %lu bytes with key-id %#x (%s)", 
4121                encryptp ? "encrypting" : "decrypting",
4122                (unsigned long)len,
4123                keyid,
4124                kt);
4125     free(kt);
4126 }
4127
4128 #endif /* CRYPTO_DEBUG */
4129
4130 #if 0
4131 int
4132 main()
4133 {
4134 #if 0
4135     int i;
4136     krb5_context context;
4137     krb5_crypto crypto;
4138     struct key_data *d;
4139     krb5_keyblock key;
4140     char constant[4];
4141     unsigned usage = ENCRYPTION_USAGE(3);
4142     krb5_error_code ret;
4143
4144     ret = krb5_init_context(&context);
4145     if (ret)
4146         errx (1, "krb5_init_context failed: %d", ret);
4147
4148     key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
4149     key.keyvalue.data = "\xb3\x85\x58\x94\xd9\xdc\x7c\xc8"
4150         "\x25\xe9\x85\xab\x3e\xb5\xfb\x0e"
4151         "\xc8\xdf\xab\x26\x86\x64\x15\x25";
4152     key.keyvalue.length = 24;
4153
4154     krb5_crypto_init(context, &key, 0, &crypto);
4155
4156     d = _new_derived_key(crypto, usage);
4157     if(d == NULL)
4158         krb5_errx(context, 1, "_new_derived_key failed");
4159     krb5_copy_keyblock(context, crypto->key.key, &d->key);
4160     _krb5_put_int(constant, usage, 4);
4161     derive_key(context, crypto->et, d, constant, sizeof(constant));
4162     return 0;
4163 #else
4164     int i;
4165     krb5_context context;
4166     krb5_crypto crypto;
4167     struct key_data *d;
4168     krb5_keyblock key;
4169     krb5_error_code ret;
4170     Checksum res;
4171
4172     char *data = "what do ya want for nothing?";
4173
4174     ret = krb5_init_context(&context);
4175     if (ret)
4176         errx (1, "krb5_init_context failed: %d", ret);
4177
4178     key.keytype = ETYPE_NEW_DES3_CBC_SHA1;
4179     key.keyvalue.data = "Jefe";
4180     /* "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
4181        "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; */
4182     key.keyvalue.length = 4;
4183
4184     d = ecalloc(1, sizeof(*d));
4185     d->key = &key;
4186     res.checksum.length = 20;
4187     res.checksum.data = emalloc(res.checksum.length);
4188     SP_HMAC_SHA1_checksum(context, d, data, 28, &res);
4189
4190     return 0;
4191 #endif
4192 }
4193 #endif