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