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