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