s3: Add vfs_aio_posix
[Samba/gebeck_regimport.git] / source4 / heimdal / lib / krb5 / crypto.c
blob75d0a099d483e43fa5d495862af71ccd93132c1f
1 /*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5_locl.h"
36 struct _krb5_key_usage {
37 unsigned usage;
38 struct _krb5_key_data key;
42 #ifndef HEIMDAL_SMALLER
43 #define DES3_OLD_ENCTYPE 1
44 #endif
46 static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
47 unsigned, struct _krb5_key_data**);
48 static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
50 static void free_key_schedule(krb5_context,
51 struct _krb5_key_data *,
52 struct _krb5_encryption_type *);
54 /************************************************************
55 * *
56 ************************************************************/
58 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
59 krb5_enctype_keysize(krb5_context context,
60 krb5_enctype type,
61 size_t *keysize)
63 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
64 if(et == NULL) {
65 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
66 N_("encryption type %d not supported", ""),
67 type);
68 return KRB5_PROG_ETYPE_NOSUPP;
70 *keysize = et->keytype->size;
71 return 0;
74 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
75 krb5_enctype_keybits(krb5_context context,
76 krb5_enctype type,
77 size_t *keybits)
79 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
80 if(et == NULL) {
81 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
82 "encryption type %d not supported",
83 type);
84 return KRB5_PROG_ETYPE_NOSUPP;
86 *keybits = et->keytype->bits;
87 return 0;
90 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
91 krb5_generate_random_keyblock(krb5_context context,
92 krb5_enctype type,
93 krb5_keyblock *key)
95 krb5_error_code ret;
96 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
97 if(et == NULL) {
98 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
99 N_("encryption type %d not supported", ""),
100 type);
101 return KRB5_PROG_ETYPE_NOSUPP;
103 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
104 if(ret)
105 return ret;
106 key->keytype = type;
107 if(et->keytype->random_key)
108 (*et->keytype->random_key)(context, key);
109 else
110 krb5_generate_random_block(key->keyvalue.data,
111 key->keyvalue.length);
112 return 0;
115 static krb5_error_code
116 _key_schedule(krb5_context context,
117 struct _krb5_key_data *key)
119 krb5_error_code ret;
120 struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
121 struct _krb5_key_type *kt;
123 if (et == NULL) {
124 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
125 N_("encryption type %d not supported", ""),
126 key->key->keytype);
127 return KRB5_PROG_ETYPE_NOSUPP;
130 kt = et->keytype;
132 if(kt->schedule == NULL)
133 return 0;
134 if (key->schedule != NULL)
135 return 0;
136 ALLOC(key->schedule, 1);
137 if(key->schedule == NULL) {
138 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
139 return ENOMEM;
141 ret = krb5_data_alloc(key->schedule, kt->schedule_size);
142 if(ret) {
143 free(key->schedule);
144 key->schedule = NULL;
145 return ret;
147 (*kt->schedule)(context, kt, key);
148 return 0;
151 /************************************************************
153 ************************************************************/
155 static krb5_error_code
156 SHA1_checksum(krb5_context context,
157 struct _krb5_key_data *key,
158 const void *data,
159 size_t len,
160 unsigned usage,
161 Checksum *C)
163 if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
164 krb5_abortx(context, "sha1 checksum failed");
165 return 0;
168 /* HMAC according to RFC2104 */
169 krb5_error_code
170 _krb5_internal_hmac(krb5_context context,
171 struct _krb5_checksum_type *cm,
172 const void *data,
173 size_t len,
174 unsigned usage,
175 struct _krb5_key_data *keyblock,
176 Checksum *result)
178 unsigned char *ipad, *opad;
179 unsigned char *key;
180 size_t key_len;
181 size_t i;
183 ipad = malloc(cm->blocksize + len);
184 if (ipad == NULL)
185 return ENOMEM;
186 opad = malloc(cm->blocksize + cm->checksumsize);
187 if (opad == NULL) {
188 free(ipad);
189 return ENOMEM;
191 memset(ipad, 0x36, cm->blocksize);
192 memset(opad, 0x5c, cm->blocksize);
194 if(keyblock->key->keyvalue.length > cm->blocksize){
195 (*cm->checksum)(context,
196 keyblock,
197 keyblock->key->keyvalue.data,
198 keyblock->key->keyvalue.length,
199 usage,
200 result);
201 key = result->checksum.data;
202 key_len = result->checksum.length;
203 } else {
204 key = keyblock->key->keyvalue.data;
205 key_len = keyblock->key->keyvalue.length;
207 for(i = 0; i < key_len; i++){
208 ipad[i] ^= key[i];
209 opad[i] ^= key[i];
211 memcpy(ipad + cm->blocksize, data, len);
212 (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
213 usage, result);
214 memcpy(opad + cm->blocksize, result->checksum.data,
215 result->checksum.length);
216 (*cm->checksum)(context, keyblock, opad,
217 cm->blocksize + cm->checksumsize, usage, result);
218 memset(ipad, 0, cm->blocksize + len);
219 free(ipad);
220 memset(opad, 0, cm->blocksize + cm->checksumsize);
221 free(opad);
223 return 0;
226 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
227 krb5_hmac(krb5_context context,
228 krb5_cksumtype cktype,
229 const void *data,
230 size_t len,
231 unsigned usage,
232 krb5_keyblock *key,
233 Checksum *result)
235 struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
236 struct _krb5_key_data kd;
237 krb5_error_code ret;
239 if (c == NULL) {
240 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
241 N_("checksum type %d not supported", ""),
242 cktype);
243 return KRB5_PROG_SUMTYPE_NOSUPP;
246 kd.key = key;
247 kd.schedule = NULL;
249 ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result);
251 if (kd.schedule)
252 krb5_free_data(context, kd.schedule);
254 return ret;
257 krb5_error_code
258 _krb5_SP_HMAC_SHA1_checksum(krb5_context context,
259 struct _krb5_key_data *key,
260 const void *data,
261 size_t len,
262 unsigned usage,
263 Checksum *result)
265 struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
266 Checksum res;
267 char sha1_data[20];
268 krb5_error_code ret;
270 res.checksum.data = sha1_data;
271 res.checksum.length = sizeof(sha1_data);
273 ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res);
274 if (ret)
275 krb5_abortx(context, "hmac failed");
276 memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
277 return 0;
280 struct _krb5_checksum_type _krb5_checksum_sha1 = {
281 CKSUMTYPE_SHA1,
282 "sha1",
285 F_CPROOF,
286 SHA1_checksum,
287 NULL
290 struct _krb5_checksum_type *
291 _krb5_find_checksum(krb5_cksumtype type)
293 int i;
294 for(i = 0; i < _krb5_num_checksums; i++)
295 if(_krb5_checksum_types[i]->type == type)
296 return _krb5_checksum_types[i];
297 return NULL;
300 static krb5_error_code
301 get_checksum_key(krb5_context context,
302 krb5_crypto crypto,
303 unsigned usage, /* not krb5_key_usage */
304 struct _krb5_checksum_type *ct,
305 struct _krb5_key_data **key)
307 krb5_error_code ret = 0;
309 if(ct->flags & F_DERIVED)
310 ret = _get_derived_key(context, crypto, usage, key);
311 else if(ct->flags & F_VARIANT) {
312 size_t i;
314 *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
315 if(*key == NULL) {
316 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
317 return ENOMEM;
319 ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
320 if(ret)
321 return ret;
322 for(i = 0; i < (*key)->key->keyvalue.length; i++)
323 ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
324 } else {
325 *key = &crypto->key;
327 if(ret == 0)
328 ret = _key_schedule(context, *key);
329 return ret;
332 static krb5_error_code
333 create_checksum (krb5_context context,
334 struct _krb5_checksum_type *ct,
335 krb5_crypto crypto,
336 unsigned usage,
337 void *data,
338 size_t len,
339 Checksum *result)
341 krb5_error_code ret;
342 struct _krb5_key_data *dkey;
343 int keyed_checksum;
345 if (ct->flags & F_DISABLED) {
346 krb5_clear_error_message (context);
347 return KRB5_PROG_SUMTYPE_NOSUPP;
349 keyed_checksum = (ct->flags & F_KEYED) != 0;
350 if(keyed_checksum && crypto == NULL) {
351 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
352 N_("Checksum type %s is keyed but no "
353 "crypto context (key) was passed in", ""),
354 ct->name);
355 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
357 if(keyed_checksum) {
358 ret = get_checksum_key(context, crypto, usage, ct, &dkey);
359 if (ret)
360 return ret;
361 } else
362 dkey = NULL;
363 result->cksumtype = ct->type;
364 ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
365 if (ret)
366 return (ret);
367 return (*ct->checksum)(context, dkey, data, len, usage, result);
370 static int
371 arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
373 return (ct->type == CKSUMTYPE_HMAC_MD5) &&
374 (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
377 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
378 krb5_create_checksum(krb5_context context,
379 krb5_crypto crypto,
380 krb5_key_usage usage,
381 int type,
382 void *data,
383 size_t len,
384 Checksum *result)
386 struct _krb5_checksum_type *ct = NULL;
387 unsigned keyusage;
389 /* type 0 -> pick from crypto */
390 if (type) {
391 ct = _krb5_find_checksum(type);
392 } else if (crypto) {
393 ct = crypto->et->keyed_checksum;
394 if (ct == NULL)
395 ct = crypto->et->checksum;
398 if(ct == NULL) {
399 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
400 N_("checksum type %d not supported", ""),
401 type);
402 return KRB5_PROG_SUMTYPE_NOSUPP;
405 if (arcfour_checksum_p(ct, crypto)) {
406 keyusage = usage;
407 _krb5_usage2arcfour(context, &keyusage);
408 } else
409 keyusage = CHECKSUM_USAGE(usage);
411 return create_checksum(context, ct, crypto, keyusage,
412 data, len, result);
415 static krb5_error_code
416 verify_checksum(krb5_context context,
417 krb5_crypto crypto,
418 unsigned usage, /* not krb5_key_usage */
419 void *data,
420 size_t len,
421 Checksum *cksum)
423 krb5_error_code ret;
424 struct _krb5_key_data *dkey;
425 int keyed_checksum;
426 Checksum c;
427 struct _krb5_checksum_type *ct;
429 ct = _krb5_find_checksum(cksum->cksumtype);
430 if (ct == NULL || (ct->flags & F_DISABLED)) {
431 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
432 N_("checksum type %d not supported", ""),
433 cksum->cksumtype);
434 return KRB5_PROG_SUMTYPE_NOSUPP;
436 if(ct->checksumsize != cksum->checksum.length) {
437 krb5_clear_error_message (context);
438 krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
439 N_("Decrypt integrity check failed for checksum type %s, "
440 "length was %u, expected %u", ""),
441 ct->name, (unsigned)cksum->checksum.length,
442 (unsigned)ct->checksumsize);
444 return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
446 keyed_checksum = (ct->flags & F_KEYED) != 0;
447 if(keyed_checksum) {
448 struct _krb5_checksum_type *kct;
449 if (crypto == NULL) {
450 krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
451 N_("Checksum type %s is keyed but no "
452 "crypto context (key) was passed in", ""),
453 ct->name);
454 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
456 kct = crypto->et->keyed_checksum;
457 if (kct == NULL || kct->type != ct->type) {
458 krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
459 N_("Checksum type %s is keyed, but "
460 "the key type %s passed didnt have that checksum "
461 "type as the keyed type", ""),
462 ct->name, crypto->et->name);
463 return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
466 ret = get_checksum_key(context, crypto, usage, ct, &dkey);
467 if (ret)
468 return ret;
469 } else
470 dkey = NULL;
473 * If checksum have a verify function, lets use that instead of
474 * calling ->checksum and then compare result.
477 if(ct->verify) {
478 ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
479 if (ret)
480 krb5_set_error_message(context, ret,
481 N_("Decrypt integrity check failed for checksum "
482 "type %s, key type %s", ""),
483 ct->name, (crypto != NULL)? crypto->et->name : "(none)");
484 return ret;
487 ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
488 if (ret)
489 return ret;
491 ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
492 if (ret) {
493 krb5_data_free(&c.checksum);
494 return ret;
497 if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
498 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
499 krb5_set_error_message(context, ret,
500 N_("Decrypt integrity check failed for checksum "
501 "type %s, key type %s", ""),
502 ct->name, crypto ? crypto->et->name : "(unkeyed)");
503 } else {
504 ret = 0;
506 krb5_data_free (&c.checksum);
507 return ret;
510 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
511 krb5_verify_checksum(krb5_context context,
512 krb5_crypto crypto,
513 krb5_key_usage usage,
514 void *data,
515 size_t len,
516 Checksum *cksum)
518 struct _krb5_checksum_type *ct;
519 unsigned keyusage;
521 ct = _krb5_find_checksum(cksum->cksumtype);
522 if(ct == NULL) {
523 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
524 N_("checksum type %d not supported", ""),
525 cksum->cksumtype);
526 return KRB5_PROG_SUMTYPE_NOSUPP;
529 if (arcfour_checksum_p(ct, crypto)) {
530 keyusage = usage;
531 _krb5_usage2arcfour(context, &keyusage);
532 } else
533 keyusage = CHECKSUM_USAGE(usage);
535 return verify_checksum(context, crypto, keyusage,
536 data, len, cksum);
539 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
540 krb5_crypto_get_checksum_type(krb5_context context,
541 krb5_crypto crypto,
542 krb5_cksumtype *type)
544 struct _krb5_checksum_type *ct = NULL;
546 if (crypto != NULL) {
547 ct = crypto->et->keyed_checksum;
548 if (ct == NULL)
549 ct = crypto->et->checksum;
552 if (ct == NULL) {
553 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
554 N_("checksum type not found", ""));
555 return KRB5_PROG_SUMTYPE_NOSUPP;
558 *type = ct->type;
560 return 0;
564 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
565 krb5_checksumsize(krb5_context context,
566 krb5_cksumtype type,
567 size_t *size)
569 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
570 if(ct == NULL) {
571 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
572 N_("checksum type %d not supported", ""),
573 type);
574 return KRB5_PROG_SUMTYPE_NOSUPP;
576 *size = ct->checksumsize;
577 return 0;
580 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
581 krb5_checksum_is_keyed(krb5_context context,
582 krb5_cksumtype type)
584 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
585 if(ct == NULL) {
586 if (context)
587 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
588 N_("checksum type %d not supported", ""),
589 type);
590 return KRB5_PROG_SUMTYPE_NOSUPP;
592 return ct->flags & F_KEYED;
595 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
596 krb5_checksum_is_collision_proof(krb5_context context,
597 krb5_cksumtype type)
599 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
600 if(ct == NULL) {
601 if (context)
602 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
603 N_("checksum type %d not supported", ""),
604 type);
605 return KRB5_PROG_SUMTYPE_NOSUPP;
607 return ct->flags & F_CPROOF;
610 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
611 krb5_checksum_disable(krb5_context context,
612 krb5_cksumtype type)
614 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
615 if(ct == NULL) {
616 if (context)
617 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
618 N_("checksum type %d not supported", ""),
619 type);
620 return KRB5_PROG_SUMTYPE_NOSUPP;
622 ct->flags |= F_DISABLED;
623 return 0;
626 /************************************************************
628 ************************************************************/
630 struct _krb5_encryption_type *
631 _krb5_find_enctype(krb5_enctype type)
633 int i;
634 for(i = 0; i < _krb5_num_etypes; i++)
635 if(_krb5_etypes[i]->type == type)
636 return _krb5_etypes[i];
637 return NULL;
641 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
642 krb5_enctype_to_string(krb5_context context,
643 krb5_enctype etype,
644 char **string)
646 struct _krb5_encryption_type *e;
647 e = _krb5_find_enctype(etype);
648 if(e == NULL) {
649 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
650 N_("encryption type %d not supported", ""),
651 etype);
652 *string = NULL;
653 return KRB5_PROG_ETYPE_NOSUPP;
655 *string = strdup(e->name);
656 if(*string == NULL) {
657 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
658 return ENOMEM;
660 return 0;
663 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
664 krb5_string_to_enctype(krb5_context context,
665 const char *string,
666 krb5_enctype *etype)
668 int i;
669 for(i = 0; i < _krb5_num_etypes; i++)
670 if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
671 *etype = _krb5_etypes[i]->type;
672 return 0;
674 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
675 N_("encryption type %s not supported", ""),
676 string);
677 return KRB5_PROG_ETYPE_NOSUPP;
680 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
681 krb5_enctype_to_keytype(krb5_context context,
682 krb5_enctype etype,
683 krb5_keytype *keytype)
685 struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
686 if(e == NULL) {
687 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
688 N_("encryption type %d not supported", ""),
689 etype);
690 return KRB5_PROG_ETYPE_NOSUPP;
692 *keytype = e->keytype->type; /* XXX */
693 return 0;
697 * Check if a enctype is valid, return 0 if it is.
699 * @param context Kerberos context
700 * @param etype enctype to check if its valid or not
702 * @return Return an error code for an failure or 0 on success (enctype valid).
703 * @ingroup krb5_crypto
706 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
707 krb5_enctype_valid(krb5_context context,
708 krb5_enctype etype)
710 struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
711 if(e && (e->flags & F_DISABLED) == 0)
712 return 0;
713 if (context == NULL)
714 return KRB5_PROG_ETYPE_NOSUPP;
715 if(e == NULL) {
716 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
717 N_("encryption type %d not supported", ""),
718 etype);
719 return KRB5_PROG_ETYPE_NOSUPP;
721 /* Must be (e->flags & F_DISABLED) */
722 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
723 N_("encryption type %s is disabled", ""),
724 e->name);
725 return KRB5_PROG_ETYPE_NOSUPP;
729 * Return the coresponding encryption type for a checksum type.
731 * @param context Kerberos context
732 * @param ctype The checksum type to get the result enctype for
733 * @param etype The returned encryption, when the matching etype is
734 * not found, etype is set to ETYPE_NULL.
736 * @return Return an error code for an failure or 0 on success.
737 * @ingroup krb5_crypto
741 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
742 krb5_cksumtype_to_enctype(krb5_context context,
743 krb5_cksumtype ctype,
744 krb5_enctype *etype)
746 int i;
748 *etype = ETYPE_NULL;
750 for(i = 0; i < _krb5_num_etypes; i++) {
751 if(_krb5_etypes[i]->keyed_checksum &&
752 _krb5_etypes[i]->keyed_checksum->type == ctype)
754 *etype = _krb5_etypes[i]->type;
755 return 0;
759 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
760 N_("checksum type %d not supported", ""),
761 (int)ctype);
762 return KRB5_PROG_SUMTYPE_NOSUPP;
766 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
767 krb5_cksumtype_valid(krb5_context context,
768 krb5_cksumtype ctype)
770 struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
771 if (c == NULL) {
772 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
773 N_("checksum type %d not supported", ""),
774 ctype);
775 return KRB5_PROG_SUMTYPE_NOSUPP;
777 if (c->flags & F_DISABLED) {
778 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
779 N_("checksum type %s is disabled", ""),
780 c->name);
781 return KRB5_PROG_SUMTYPE_NOSUPP;
783 return 0;
787 static krb5_boolean
788 derived_crypto(krb5_context context,
789 krb5_crypto crypto)
791 return (crypto->et->flags & F_DERIVED) != 0;
794 static krb5_boolean
795 special_crypto(krb5_context context,
796 krb5_crypto crypto)
798 return (crypto->et->flags & F_SPECIAL) != 0;
801 #define CHECKSUMSIZE(C) ((C)->checksumsize)
802 #define CHECKSUMTYPE(C) ((C)->type)
804 static krb5_error_code
805 encrypt_internal_derived(krb5_context context,
806 krb5_crypto crypto,
807 unsigned usage,
808 const void *data,
809 size_t len,
810 krb5_data *result,
811 void *ivec)
813 size_t sz, block_sz, checksum_sz, total_sz;
814 Checksum cksum;
815 unsigned char *p, *q;
816 krb5_error_code ret;
817 struct _krb5_key_data *dkey;
818 const struct _krb5_encryption_type *et = crypto->et;
820 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
822 sz = et->confoundersize + len;
823 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
824 total_sz = block_sz + checksum_sz;
825 p = calloc(1, total_sz);
826 if(p == NULL) {
827 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
828 return ENOMEM;
831 q = p;
832 krb5_generate_random_block(q, et->confoundersize); /* XXX */
833 q += et->confoundersize;
834 memcpy(q, data, len);
836 ret = create_checksum(context,
837 et->keyed_checksum,
838 crypto,
839 INTEGRITY_USAGE(usage),
841 block_sz,
842 &cksum);
843 if(ret == 0 && cksum.checksum.length != checksum_sz) {
844 free_Checksum (&cksum);
845 krb5_clear_error_message (context);
846 ret = KRB5_CRYPTO_INTERNAL;
848 if(ret)
849 goto fail;
850 memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
851 free_Checksum (&cksum);
852 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
853 if(ret)
854 goto fail;
855 ret = _key_schedule(context, dkey);
856 if(ret)
857 goto fail;
858 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
859 if (ret)
860 goto fail;
861 result->data = p;
862 result->length = total_sz;
863 return 0;
864 fail:
865 memset(p, 0, total_sz);
866 free(p);
867 return ret;
871 static krb5_error_code
872 encrypt_internal(krb5_context context,
873 krb5_crypto crypto,
874 const void *data,
875 size_t len,
876 krb5_data *result,
877 void *ivec)
879 size_t sz, block_sz, checksum_sz;
880 Checksum cksum;
881 unsigned char *p, *q;
882 krb5_error_code ret;
883 const struct _krb5_encryption_type *et = crypto->et;
885 checksum_sz = CHECKSUMSIZE(et->checksum);
887 sz = et->confoundersize + checksum_sz + len;
888 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
889 p = calloc(1, block_sz);
890 if(p == NULL) {
891 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
892 return ENOMEM;
895 q = p;
896 krb5_generate_random_block(q, et->confoundersize); /* XXX */
897 q += et->confoundersize;
898 memset(q, 0, checksum_sz);
899 q += checksum_sz;
900 memcpy(q, data, len);
902 ret = create_checksum(context,
903 et->checksum,
904 crypto,
907 block_sz,
908 &cksum);
909 if(ret == 0 && cksum.checksum.length != checksum_sz) {
910 krb5_clear_error_message (context);
911 free_Checksum(&cksum);
912 ret = KRB5_CRYPTO_INTERNAL;
914 if(ret)
915 goto fail;
916 memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
917 free_Checksum(&cksum);
918 ret = _key_schedule(context, &crypto->key);
919 if(ret)
920 goto fail;
921 ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
922 if (ret) {
923 memset(p, 0, block_sz);
924 free(p);
925 return ret;
927 result->data = p;
928 result->length = block_sz;
929 return 0;
930 fail:
931 memset(p, 0, block_sz);
932 free(p);
933 return ret;
936 static krb5_error_code
937 encrypt_internal_special(krb5_context context,
938 krb5_crypto crypto,
939 int usage,
940 const void *data,
941 size_t len,
942 krb5_data *result,
943 void *ivec)
945 struct _krb5_encryption_type *et = crypto->et;
946 size_t cksum_sz = CHECKSUMSIZE(et->checksum);
947 size_t sz = len + cksum_sz + et->confoundersize;
948 char *tmp, *p;
949 krb5_error_code ret;
951 tmp = malloc (sz);
952 if (tmp == NULL) {
953 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
954 return ENOMEM;
956 p = tmp;
957 memset (p, 0, cksum_sz);
958 p += cksum_sz;
959 krb5_generate_random_block(p, et->confoundersize);
960 p += et->confoundersize;
961 memcpy (p, data, len);
962 ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
963 if (ret) {
964 memset(tmp, 0, sz);
965 free(tmp);
966 return ret;
968 result->data = tmp;
969 result->length = sz;
970 return 0;
973 static krb5_error_code
974 decrypt_internal_derived(krb5_context context,
975 krb5_crypto crypto,
976 unsigned usage,
977 void *data,
978 size_t len,
979 krb5_data *result,
980 void *ivec)
982 size_t checksum_sz;
983 Checksum cksum;
984 unsigned char *p;
985 krb5_error_code ret;
986 struct _krb5_key_data *dkey;
987 struct _krb5_encryption_type *et = crypto->et;
988 unsigned long l;
990 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
991 if (len < checksum_sz + et->confoundersize) {
992 krb5_set_error_message(context, KRB5_BAD_MSIZE,
993 N_("Encrypted data shorter then "
994 "checksum + confunder", ""));
995 return KRB5_BAD_MSIZE;
998 if (((len - checksum_sz) % et->padsize) != 0) {
999 krb5_clear_error_message(context);
1000 return KRB5_BAD_MSIZE;
1003 p = malloc(len);
1004 if(len != 0 && p == NULL) {
1005 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1006 return ENOMEM;
1008 memcpy(p, data, len);
1010 len -= checksum_sz;
1012 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1013 if(ret) {
1014 free(p);
1015 return ret;
1017 ret = _key_schedule(context, dkey);
1018 if(ret) {
1019 free(p);
1020 return ret;
1022 ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1023 if (ret) {
1024 free(p);
1025 return ret;
1028 cksum.checksum.data = p + len;
1029 cksum.checksum.length = checksum_sz;
1030 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1032 ret = verify_checksum(context,
1033 crypto,
1034 INTEGRITY_USAGE(usage),
1036 len,
1037 &cksum);
1038 if(ret) {
1039 free(p);
1040 return ret;
1042 l = len - et->confoundersize;
1043 memmove(p, p + et->confoundersize, l);
1044 result->data = realloc(p, l);
1045 if(result->data == NULL && l != 0) {
1046 free(p);
1047 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1048 return ENOMEM;
1050 result->length = l;
1051 return 0;
1054 static krb5_error_code
1055 decrypt_internal(krb5_context context,
1056 krb5_crypto crypto,
1057 void *data,
1058 size_t len,
1059 krb5_data *result,
1060 void *ivec)
1062 krb5_error_code ret;
1063 unsigned char *p;
1064 Checksum cksum;
1065 size_t checksum_sz, l;
1066 struct _krb5_encryption_type *et = crypto->et;
1068 if ((len % et->padsize) != 0) {
1069 krb5_clear_error_message(context);
1070 return KRB5_BAD_MSIZE;
1072 checksum_sz = CHECKSUMSIZE(et->checksum);
1073 if (len < checksum_sz + et->confoundersize) {
1074 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1075 N_("Encrypted data shorter then "
1076 "checksum + confunder", ""));
1077 return KRB5_BAD_MSIZE;
1080 p = malloc(len);
1081 if(len != 0 && p == NULL) {
1082 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1083 return ENOMEM;
1085 memcpy(p, data, len);
1087 ret = _key_schedule(context, &crypto->key);
1088 if(ret) {
1089 free(p);
1090 return ret;
1092 ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1093 if (ret) {
1094 free(p);
1095 return ret;
1097 ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1098 if(ret) {
1099 free(p);
1100 return ret;
1102 memset(p + et->confoundersize, 0, checksum_sz);
1103 cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1104 ret = verify_checksum(context, NULL, 0, p, len, &cksum);
1105 free_Checksum(&cksum);
1106 if(ret) {
1107 free(p);
1108 return ret;
1110 l = len - et->confoundersize - checksum_sz;
1111 memmove(p, p + et->confoundersize + checksum_sz, l);
1112 result->data = realloc(p, l);
1113 if(result->data == NULL && l != 0) {
1114 free(p);
1115 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1116 return ENOMEM;
1118 result->length = l;
1119 return 0;
1122 static krb5_error_code
1123 decrypt_internal_special(krb5_context context,
1124 krb5_crypto crypto,
1125 int usage,
1126 void *data,
1127 size_t len,
1128 krb5_data *result,
1129 void *ivec)
1131 struct _krb5_encryption_type *et = crypto->et;
1132 size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1133 size_t sz = len - cksum_sz - et->confoundersize;
1134 unsigned char *p;
1135 krb5_error_code ret;
1137 if ((len % et->padsize) != 0) {
1138 krb5_clear_error_message(context);
1139 return KRB5_BAD_MSIZE;
1141 if (len < cksum_sz + et->confoundersize) {
1142 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1143 N_("Encrypted data shorter then "
1144 "checksum + confunder", ""));
1145 return KRB5_BAD_MSIZE;
1148 p = malloc (len);
1149 if (p == NULL) {
1150 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1151 return ENOMEM;
1153 memcpy(p, data, len);
1155 ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1156 if (ret) {
1157 free(p);
1158 return ret;
1161 memmove (p, p + cksum_sz + et->confoundersize, sz);
1162 result->data = realloc(p, sz);
1163 if(result->data == NULL && sz != 0) {
1164 free(p);
1165 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1166 return ENOMEM;
1168 result->length = sz;
1169 return 0;
1172 static krb5_crypto_iov *
1173 find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type)
1175 size_t i;
1176 for (i = 0; i < num_data; i++)
1177 if (data[i].flags == type)
1178 return &data[i];
1179 return NULL;
1183 * Inline encrypt a kerberos message
1185 * @param context Kerberos context
1186 * @param crypto Kerberos crypto context
1187 * @param usage Key usage for this buffer
1188 * @param data array of buffers to process
1189 * @param num_data length of array
1190 * @param ivec initial cbc/cts vector
1192 * @return Return an error code or 0.
1193 * @ingroup krb5_crypto
1195 * Kerberos encrypted data look like this:
1197 * 1. KRB5_CRYPTO_TYPE_HEADER
1198 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1199 * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1200 * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1201 * commonly used headers and trailers.
1202 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1203 * 4. KRB5_CRYPTO_TYPE_TRAILER
1206 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1207 krb5_encrypt_iov_ivec(krb5_context context,
1208 krb5_crypto crypto,
1209 unsigned usage,
1210 krb5_crypto_iov *data,
1211 int num_data,
1212 void *ivec)
1214 size_t headersz, trailersz, len;
1215 int i;
1216 size_t sz, block_sz, pad_sz;
1217 Checksum cksum;
1218 unsigned char *p, *q;
1219 krb5_error_code ret;
1220 struct _krb5_key_data *dkey;
1221 const struct _krb5_encryption_type *et = crypto->et;
1222 krb5_crypto_iov *tiv, *piv, *hiv;
1224 if (num_data < 0) {
1225 krb5_clear_error_message(context);
1226 return KRB5_CRYPTO_INTERNAL;
1229 if(!derived_crypto(context, crypto)) {
1230 krb5_clear_error_message(context);
1231 return KRB5_CRYPTO_INTERNAL;
1234 headersz = et->confoundersize;
1235 trailersz = CHECKSUMSIZE(et->keyed_checksum);
1237 for (len = 0, i = 0; i < num_data; i++) {
1238 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1239 continue;
1240 len += data[i].data.length;
1243 sz = headersz + len;
1244 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1246 pad_sz = block_sz - sz;
1248 /* header */
1250 hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1251 if (hiv == NULL || hiv->data.length != headersz)
1252 return KRB5_BAD_MSIZE;
1254 krb5_generate_random_block(hiv->data.data, hiv->data.length);
1256 /* padding */
1257 piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1258 /* its ok to have no TYPE_PADDING if there is no padding */
1259 if (piv == NULL && pad_sz != 0)
1260 return KRB5_BAD_MSIZE;
1261 if (piv) {
1262 if (piv->data.length < pad_sz)
1263 return KRB5_BAD_MSIZE;
1264 piv->data.length = pad_sz;
1265 if (pad_sz)
1266 memset(piv->data.data, pad_sz, pad_sz);
1267 else
1268 piv = NULL;
1271 /* trailer */
1272 tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1273 if (tiv == NULL || tiv->data.length != trailersz)
1274 return KRB5_BAD_MSIZE;
1277 * XXX replace with EVP_Sign? at least make create_checksum an iov
1278 * function.
1279 * XXX CTS EVP is broken, can't handle multi buffers :(
1282 len = block_sz;
1283 for (i = 0; i < num_data; i++) {
1284 if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1285 continue;
1286 len += data[i].data.length;
1289 p = q = malloc(len);
1291 memcpy(q, hiv->data.data, hiv->data.length);
1292 q += hiv->data.length;
1293 for (i = 0; i < num_data; i++) {
1294 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1295 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1296 continue;
1297 memcpy(q, data[i].data.data, data[i].data.length);
1298 q += data[i].data.length;
1300 if (piv)
1301 memset(q, 0, piv->data.length);
1303 ret = create_checksum(context,
1304 et->keyed_checksum,
1305 crypto,
1306 INTEGRITY_USAGE(usage),
1308 len,
1309 &cksum);
1310 free(p);
1311 if(ret == 0 && cksum.checksum.length != trailersz) {
1312 free_Checksum (&cksum);
1313 krb5_clear_error_message (context);
1314 ret = KRB5_CRYPTO_INTERNAL;
1316 if(ret)
1317 return ret;
1319 /* save cksum at end */
1320 memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1321 free_Checksum (&cksum);
1323 /* XXX replace with EVP_Cipher */
1324 p = q = malloc(block_sz);
1325 if(p == NULL)
1326 return ENOMEM;
1328 memcpy(q, hiv->data.data, hiv->data.length);
1329 q += hiv->data.length;
1331 for (i = 0; i < num_data; i++) {
1332 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1333 continue;
1334 memcpy(q, data[i].data.data, data[i].data.length);
1335 q += data[i].data.length;
1337 if (piv)
1338 memset(q, 0, piv->data.length);
1341 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1342 if(ret) {
1343 free(p);
1344 return ret;
1346 ret = _key_schedule(context, dkey);
1347 if(ret) {
1348 free(p);
1349 return ret;
1352 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1353 if (ret) {
1354 free(p);
1355 return ret;
1358 /* now copy data back to buffers */
1359 q = p;
1361 memcpy(hiv->data.data, q, hiv->data.length);
1362 q += hiv->data.length;
1364 for (i = 0; i < num_data; i++) {
1365 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1366 continue;
1367 memcpy(data[i].data.data, q, data[i].data.length);
1368 q += data[i].data.length;
1370 if (piv)
1371 memcpy(piv->data.data, q, pad_sz);
1373 free(p);
1375 return ret;
1379 * Inline decrypt a Kerberos message.
1381 * @param context Kerberos context
1382 * @param crypto Kerberos crypto context
1383 * @param usage Key usage for this buffer
1384 * @param data array of buffers to process
1385 * @param num_data length of array
1386 * @param ivec initial cbc/cts vector
1388 * @return Return an error code or 0.
1389 * @ingroup krb5_crypto
1391 * 1. KRB5_CRYPTO_TYPE_HEADER
1392 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1393 * any order, however the receiver have to aware of the
1394 * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1395 * protocol headers and trailers. The output data will be of same
1396 * size as the input data or shorter.
1399 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1400 krb5_decrypt_iov_ivec(krb5_context context,
1401 krb5_crypto crypto,
1402 unsigned usage,
1403 krb5_crypto_iov *data,
1404 unsigned int num_data,
1405 void *ivec)
1407 unsigned int i;
1408 size_t headersz, trailersz, len;
1409 Checksum cksum;
1410 unsigned char *p, *q;
1411 krb5_error_code ret;
1412 struct _krb5_key_data *dkey;
1413 struct _krb5_encryption_type *et = crypto->et;
1414 krb5_crypto_iov *tiv, *hiv;
1416 if(!derived_crypto(context, crypto)) {
1417 krb5_clear_error_message(context);
1418 return KRB5_CRYPTO_INTERNAL;
1421 headersz = et->confoundersize;
1423 hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1424 if (hiv == NULL || hiv->data.length != headersz)
1425 return KRB5_BAD_MSIZE;
1427 /* trailer */
1428 trailersz = CHECKSUMSIZE(et->keyed_checksum);
1430 tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1431 if (tiv->data.length != trailersz)
1432 return KRB5_BAD_MSIZE;
1434 /* Find length of data we will decrypt */
1436 len = headersz;
1437 for (i = 0; i < num_data; i++) {
1438 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1439 continue;
1440 len += data[i].data.length;
1443 if ((len % et->padsize) != 0) {
1444 krb5_clear_error_message(context);
1445 return KRB5_BAD_MSIZE;
1448 /* XXX replace with EVP_Cipher */
1450 p = q = malloc(len);
1451 if (p == NULL)
1452 return ENOMEM;
1454 memcpy(q, hiv->data.data, hiv->data.length);
1455 q += hiv->data.length;
1457 for (i = 0; i < num_data; i++) {
1458 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1459 continue;
1460 memcpy(q, data[i].data.data, data[i].data.length);
1461 q += data[i].data.length;
1464 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1465 if(ret) {
1466 free(p);
1467 return ret;
1469 ret = _key_schedule(context, dkey);
1470 if(ret) {
1471 free(p);
1472 return ret;
1475 ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1476 if (ret) {
1477 free(p);
1478 return ret;
1481 /* copy data back to buffers */
1482 memcpy(hiv->data.data, p, hiv->data.length);
1483 q = p + hiv->data.length;
1484 for (i = 0; i < num_data; i++) {
1485 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1486 continue;
1487 memcpy(data[i].data.data, q, data[i].data.length);
1488 q += data[i].data.length;
1491 free(p);
1493 /* check signature */
1494 for (i = 0; i < num_data; i++) {
1495 if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1496 continue;
1497 len += data[i].data.length;
1500 p = q = malloc(len);
1501 if (p == NULL)
1502 return ENOMEM;
1504 memcpy(q, hiv->data.data, hiv->data.length);
1505 q += hiv->data.length;
1506 for (i = 0; i < num_data; i++) {
1507 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1508 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1509 continue;
1510 memcpy(q, data[i].data.data, data[i].data.length);
1511 q += data[i].data.length;
1514 cksum.checksum.data = tiv->data.data;
1515 cksum.checksum.length = tiv->data.length;
1516 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1518 ret = verify_checksum(context,
1519 crypto,
1520 INTEGRITY_USAGE(usage),
1522 len,
1523 &cksum);
1524 free(p);
1525 return ret;
1529 * Create a Kerberos message checksum.
1531 * @param context Kerberos context
1532 * @param crypto Kerberos crypto context
1533 * @param usage Key usage for this buffer
1534 * @param data array of buffers to process
1535 * @param num_data length of array
1536 * @param type output data
1538 * @return Return an error code or 0.
1539 * @ingroup krb5_crypto
1542 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1543 krb5_create_checksum_iov(krb5_context context,
1544 krb5_crypto crypto,
1545 unsigned usage,
1546 krb5_crypto_iov *data,
1547 unsigned int num_data,
1548 krb5_cksumtype *type)
1550 Checksum cksum;
1551 krb5_crypto_iov *civ;
1552 krb5_error_code ret;
1553 size_t i;
1554 size_t len;
1555 char *p, *q;
1557 if(!derived_crypto(context, crypto)) {
1558 krb5_clear_error_message(context);
1559 return KRB5_CRYPTO_INTERNAL;
1562 civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1563 if (civ == NULL)
1564 return KRB5_BAD_MSIZE;
1566 len = 0;
1567 for (i = 0; i < num_data; i++) {
1568 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1569 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1570 continue;
1571 len += data[i].data.length;
1574 p = q = malloc(len);
1576 for (i = 0; i < num_data; i++) {
1577 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1578 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1579 continue;
1580 memcpy(q, data[i].data.data, data[i].data.length);
1581 q += data[i].data.length;
1584 ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1585 free(p);
1586 if (ret)
1587 return ret;
1589 if (type)
1590 *type = cksum.cksumtype;
1592 if (cksum.checksum.length > civ->data.length) {
1593 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1594 N_("Checksum larger then input buffer", ""));
1595 free_Checksum(&cksum);
1596 return KRB5_BAD_MSIZE;
1599 civ->data.length = cksum.checksum.length;
1600 memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1601 free_Checksum(&cksum);
1603 return 0;
1607 * Verify a Kerberos message checksum.
1609 * @param context Kerberos context
1610 * @param crypto Kerberos crypto context
1611 * @param usage Key usage for this buffer
1612 * @param data array of buffers to process
1613 * @param num_data length of array
1614 * @param type return checksum type if not NULL
1616 * @return Return an error code or 0.
1617 * @ingroup krb5_crypto
1620 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1621 krb5_verify_checksum_iov(krb5_context context,
1622 krb5_crypto crypto,
1623 unsigned usage,
1624 krb5_crypto_iov *data,
1625 unsigned int num_data,
1626 krb5_cksumtype *type)
1628 struct _krb5_encryption_type *et = crypto->et;
1629 Checksum cksum;
1630 krb5_crypto_iov *civ;
1631 krb5_error_code ret;
1632 size_t i;
1633 size_t len;
1634 char *p, *q;
1636 if(!derived_crypto(context, crypto)) {
1637 krb5_clear_error_message(context);
1638 return KRB5_CRYPTO_INTERNAL;
1641 civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1642 if (civ == NULL)
1643 return KRB5_BAD_MSIZE;
1645 len = 0;
1646 for (i = 0; i < num_data; i++) {
1647 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1648 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1649 continue;
1650 len += data[i].data.length;
1653 p = q = malloc(len);
1655 for (i = 0; i < num_data; i++) {
1656 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1657 data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1658 continue;
1659 memcpy(q, data[i].data.data, data[i].data.length);
1660 q += data[i].data.length;
1663 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1664 cksum.checksum.length = civ->data.length;
1665 cksum.checksum.data = civ->data.data;
1667 ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1668 free(p);
1670 if (ret == 0 && type)
1671 *type = cksum.cksumtype;
1673 return ret;
1677 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1678 krb5_crypto_length(krb5_context context,
1679 krb5_crypto crypto,
1680 int type,
1681 size_t *len)
1683 if (!derived_crypto(context, crypto)) {
1684 krb5_set_error_message(context, EINVAL, "not a derived crypto");
1685 return EINVAL;
1688 switch(type) {
1689 case KRB5_CRYPTO_TYPE_EMPTY:
1690 *len = 0;
1691 return 0;
1692 case KRB5_CRYPTO_TYPE_HEADER:
1693 *len = crypto->et->blocksize;
1694 return 0;
1695 case KRB5_CRYPTO_TYPE_DATA:
1696 case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1697 /* len must already been filled in */
1698 return 0;
1699 case KRB5_CRYPTO_TYPE_PADDING:
1700 if (crypto->et->padsize > 1)
1701 *len = crypto->et->padsize;
1702 else
1703 *len = 0;
1704 return 0;
1705 case KRB5_CRYPTO_TYPE_TRAILER:
1706 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1707 return 0;
1708 case KRB5_CRYPTO_TYPE_CHECKSUM:
1709 if (crypto->et->keyed_checksum)
1710 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1711 else
1712 *len = CHECKSUMSIZE(crypto->et->checksum);
1713 return 0;
1715 krb5_set_error_message(context, EINVAL,
1716 "%d not a supported type", type);
1717 return EINVAL;
1721 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1722 krb5_crypto_length_iov(krb5_context context,
1723 krb5_crypto crypto,
1724 krb5_crypto_iov *data,
1725 unsigned int num_data)
1727 krb5_error_code ret;
1728 size_t i;
1730 for (i = 0; i < num_data; i++) {
1731 ret = krb5_crypto_length(context, crypto,
1732 data[i].flags,
1733 &data[i].data.length);
1734 if (ret)
1735 return ret;
1737 return 0;
1741 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1742 krb5_encrypt_ivec(krb5_context context,
1743 krb5_crypto crypto,
1744 unsigned usage,
1745 const void *data,
1746 size_t len,
1747 krb5_data *result,
1748 void *ivec)
1750 if(derived_crypto(context, crypto))
1751 return encrypt_internal_derived(context, crypto, usage,
1752 data, len, result, ivec);
1753 else if (special_crypto(context, crypto))
1754 return encrypt_internal_special (context, crypto, usage,
1755 data, len, result, ivec);
1756 else
1757 return encrypt_internal(context, crypto, data, len, result, ivec);
1760 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1761 krb5_encrypt(krb5_context context,
1762 krb5_crypto crypto,
1763 unsigned usage,
1764 const void *data,
1765 size_t len,
1766 krb5_data *result)
1768 return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
1771 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1772 krb5_encrypt_EncryptedData(krb5_context context,
1773 krb5_crypto crypto,
1774 unsigned usage,
1775 void *data,
1776 size_t len,
1777 int kvno,
1778 EncryptedData *result)
1780 result->etype = CRYPTO_ETYPE(crypto);
1781 if(kvno){
1782 ALLOC(result->kvno, 1);
1783 *result->kvno = kvno;
1784 }else
1785 result->kvno = NULL;
1786 return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
1789 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1790 krb5_decrypt_ivec(krb5_context context,
1791 krb5_crypto crypto,
1792 unsigned usage,
1793 void *data,
1794 size_t len,
1795 krb5_data *result,
1796 void *ivec)
1798 if(derived_crypto(context, crypto))
1799 return decrypt_internal_derived(context, crypto, usage,
1800 data, len, result, ivec);
1801 else if (special_crypto (context, crypto))
1802 return decrypt_internal_special(context, crypto, usage,
1803 data, len, result, ivec);
1804 else
1805 return decrypt_internal(context, crypto, data, len, result, ivec);
1808 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1809 krb5_decrypt(krb5_context context,
1810 krb5_crypto crypto,
1811 unsigned usage,
1812 void *data,
1813 size_t len,
1814 krb5_data *result)
1816 return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
1817 NULL);
1820 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1821 krb5_decrypt_EncryptedData(krb5_context context,
1822 krb5_crypto crypto,
1823 unsigned usage,
1824 const EncryptedData *e,
1825 krb5_data *result)
1827 return krb5_decrypt(context, crypto, usage,
1828 e->cipher.data, e->cipher.length, result);
1831 /************************************************************
1833 ************************************************************/
1835 krb5_error_code
1836 _krb5_derive_key(krb5_context context,
1837 struct _krb5_encryption_type *et,
1838 struct _krb5_key_data *key,
1839 const void *constant,
1840 size_t len)
1842 unsigned char *k = NULL;
1843 unsigned int nblocks = 0, i;
1844 krb5_error_code ret = 0;
1845 struct _krb5_key_type *kt = et->keytype;
1847 ret = _key_schedule(context, key);
1848 if(ret)
1849 return ret;
1850 if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
1851 nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
1852 k = malloc(nblocks * et->blocksize);
1853 if(k == NULL) {
1854 ret = ENOMEM;
1855 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1856 goto out;
1858 ret = _krb5_n_fold(constant, len, k, et->blocksize);
1859 if (ret) {
1860 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1861 goto out;
1864 for(i = 0; i < nblocks; i++) {
1865 if(i > 0)
1866 memcpy(k + i * et->blocksize,
1867 k + (i - 1) * et->blocksize,
1868 et->blocksize);
1869 (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
1870 1, 0, NULL);
1872 } else {
1873 /* this case is probably broken, but won't be run anyway */
1874 void *c = malloc(len);
1875 size_t res_len = (kt->bits + 7) / 8;
1877 if(len != 0 && c == NULL) {
1878 ret = ENOMEM;
1879 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1880 goto out;
1882 memcpy(c, constant, len);
1883 (*et->encrypt)(context, key, c, len, 1, 0, NULL);
1884 k = malloc(res_len);
1885 if(res_len != 0 && k == NULL) {
1886 free(c);
1887 ret = ENOMEM;
1888 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1889 goto out;
1891 ret = _krb5_n_fold(c, len, k, res_len);
1892 free(c);
1893 if (ret) {
1894 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1895 goto out;
1899 /* XXX keytype dependent post-processing */
1900 switch(kt->type) {
1901 case KRB5_ENCTYPE_OLD_DES3_CBC_SHA1:
1902 _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
1903 break;
1904 case KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96:
1905 case KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96:
1906 memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
1907 break;
1908 default:
1909 ret = KRB5_CRYPTO_INTERNAL;
1910 krb5_set_error_message(context, ret,
1911 N_("derive_key() called with unknown keytype (%u)", ""),
1912 kt->type);
1913 break;
1915 out:
1916 if (key->schedule) {
1917 free_key_schedule(context, key, et);
1918 key->schedule = NULL;
1920 if (k) {
1921 memset(k, 0, nblocks * et->blocksize);
1922 free(k);
1924 return ret;
1927 static struct _krb5_key_data *
1928 _new_derived_key(krb5_crypto crypto, unsigned usage)
1930 struct _krb5_key_usage *d = crypto->key_usage;
1931 d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
1932 if(d == NULL)
1933 return NULL;
1934 crypto->key_usage = d;
1935 d += crypto->num_key_usage++;
1936 memset(d, 0, sizeof(*d));
1937 d->usage = usage;
1938 return &d->key;
1941 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1942 krb5_derive_key(krb5_context context,
1943 const krb5_keyblock *key,
1944 krb5_enctype etype,
1945 const void *constant,
1946 size_t constant_len,
1947 krb5_keyblock **derived_key)
1949 krb5_error_code ret;
1950 struct _krb5_encryption_type *et;
1951 struct _krb5_key_data d;
1953 *derived_key = NULL;
1955 et = _krb5_find_enctype (etype);
1956 if (et == NULL) {
1957 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
1958 N_("encryption type %d not supported", ""),
1959 etype);
1960 return KRB5_PROG_ETYPE_NOSUPP;
1963 ret = krb5_copy_keyblock(context, key, &d.key);
1964 if (ret)
1965 return ret;
1967 d.schedule = NULL;
1968 ret = _krb5_derive_key(context, et, &d, constant, constant_len);
1969 if (ret == 0)
1970 ret = krb5_copy_keyblock(context, d.key, derived_key);
1971 _krb5_free_key_data(context, &d, et);
1972 return ret;
1975 static krb5_error_code
1976 _get_derived_key(krb5_context context,
1977 krb5_crypto crypto,
1978 unsigned usage,
1979 struct _krb5_key_data **key)
1981 int i;
1982 struct _krb5_key_data *d;
1983 unsigned char constant[5];
1985 for(i = 0; i < crypto->num_key_usage; i++)
1986 if(crypto->key_usage[i].usage == usage) {
1987 *key = &crypto->key_usage[i].key;
1988 return 0;
1990 d = _new_derived_key(crypto, usage);
1991 if(d == NULL) {
1992 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1993 return ENOMEM;
1995 krb5_copy_keyblock(context, crypto->key.key, &d->key);
1996 _krb5_put_int(constant, usage, 5);
1997 _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
1998 *key = d;
1999 return 0;
2003 * Create a crypto context used for all encryption and signature
2004 * operation. The encryption type to use is taken from the key, but
2005 * can be overridden with the enctype parameter. This can be useful
2006 * for encryptions types which is compatiable (DES for example).
2008 * To free the crypto context, use krb5_crypto_destroy().
2010 * @param context Kerberos context
2011 * @param key the key block information with all key data
2012 * @param etype the encryption type
2013 * @param crypto the resulting crypto context
2015 * @return Return an error code or 0.
2017 * @ingroup krb5_crypto
2020 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2021 krb5_crypto_init(krb5_context context,
2022 const krb5_keyblock *key,
2023 krb5_enctype etype,
2024 krb5_crypto *crypto)
2026 krb5_error_code ret;
2027 ALLOC(*crypto, 1);
2028 if(*crypto == NULL) {
2029 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2030 return ENOMEM;
2032 if(etype == ETYPE_NULL)
2033 etype = key->keytype;
2034 (*crypto)->et = _krb5_find_enctype(etype);
2035 if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2036 free(*crypto);
2037 *crypto = NULL;
2038 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2039 N_("encryption type %d not supported", ""),
2040 etype);
2041 return KRB5_PROG_ETYPE_NOSUPP;
2043 if((*crypto)->et->keytype->size != key->keyvalue.length) {
2044 free(*crypto);
2045 *crypto = NULL;
2046 krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2047 "encryption key has bad length");
2048 return KRB5_BAD_KEYSIZE;
2050 ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2051 if(ret) {
2052 free(*crypto);
2053 *crypto = NULL;
2054 return ret;
2056 (*crypto)->key.schedule = NULL;
2057 (*crypto)->num_key_usage = 0;
2058 (*crypto)->key_usage = NULL;
2059 return 0;
2062 static void
2063 free_key_schedule(krb5_context context,
2064 struct _krb5_key_data *key,
2065 struct _krb5_encryption_type *et)
2067 if (et->keytype->cleanup)
2068 (*et->keytype->cleanup)(context, key);
2069 memset(key->schedule->data, 0, key->schedule->length);
2070 krb5_free_data(context, key->schedule);
2073 void
2074 _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2075 struct _krb5_encryption_type *et)
2077 krb5_free_keyblock(context, key->key);
2078 if(key->schedule) {
2079 free_key_schedule(context, key, et);
2080 key->schedule = NULL;
2084 static void
2085 free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2086 struct _krb5_encryption_type *et)
2088 _krb5_free_key_data(context, &ku->key, et);
2092 * Free a crypto context created by krb5_crypto_init().
2094 * @param context Kerberos context
2095 * @param crypto crypto context to free
2097 * @return Return an error code or 0.
2099 * @ingroup krb5_crypto
2102 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2103 krb5_crypto_destroy(krb5_context context,
2104 krb5_crypto crypto)
2106 int i;
2108 for(i = 0; i < crypto->num_key_usage; i++)
2109 free_key_usage(context, &crypto->key_usage[i], crypto->et);
2110 free(crypto->key_usage);
2111 _krb5_free_key_data(context, &crypto->key, crypto->et);
2112 free (crypto);
2113 return 0;
2117 * Return the blocksize used algorithm referenced by the crypto context
2119 * @param context Kerberos context
2120 * @param crypto crypto context to query
2121 * @param blocksize the resulting blocksize
2123 * @return Return an error code or 0.
2125 * @ingroup krb5_crypto
2128 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2129 krb5_crypto_getblocksize(krb5_context context,
2130 krb5_crypto crypto,
2131 size_t *blocksize)
2133 *blocksize = crypto->et->blocksize;
2134 return 0;
2138 * Return the encryption type used by the crypto context
2140 * @param context Kerberos context
2141 * @param crypto crypto context to query
2142 * @param enctype the resulting encryption type
2144 * @return Return an error code or 0.
2146 * @ingroup krb5_crypto
2149 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2150 krb5_crypto_getenctype(krb5_context context,
2151 krb5_crypto crypto,
2152 krb5_enctype *enctype)
2154 *enctype = crypto->et->type;
2155 return 0;
2159 * Return the padding size used by the crypto context
2161 * @param context Kerberos context
2162 * @param crypto crypto context to query
2163 * @param padsize the return padding size
2165 * @return Return an error code or 0.
2167 * @ingroup krb5_crypto
2170 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2171 krb5_crypto_getpadsize(krb5_context context,
2172 krb5_crypto crypto,
2173 size_t *padsize)
2175 *padsize = crypto->et->padsize;
2176 return 0;
2180 * Return the confounder size used by the crypto context
2182 * @param context Kerberos context
2183 * @param crypto crypto context to query
2184 * @param confoundersize the returned confounder size
2186 * @return Return an error code or 0.
2188 * @ingroup krb5_crypto
2191 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2192 krb5_crypto_getconfoundersize(krb5_context context,
2193 krb5_crypto crypto,
2194 size_t *confoundersize)
2196 *confoundersize = crypto->et->confoundersize;
2197 return 0;
2202 * Disable encryption type
2204 * @param context Kerberos 5 context
2205 * @param enctype encryption type to disable
2207 * @return Return an error code or 0.
2209 * @ingroup krb5_crypto
2212 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2213 krb5_enctype_disable(krb5_context context,
2214 krb5_enctype enctype)
2216 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2217 if(et == NULL) {
2218 if (context)
2219 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2220 N_("encryption type %d not supported", ""),
2221 enctype);
2222 return KRB5_PROG_ETYPE_NOSUPP;
2224 et->flags |= F_DISABLED;
2225 return 0;
2229 * Enable encryption type
2231 * @param context Kerberos 5 context
2232 * @param enctype encryption type to enable
2234 * @return Return an error code or 0.
2236 * @ingroup krb5_crypto
2239 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2240 krb5_enctype_enable(krb5_context context,
2241 krb5_enctype enctype)
2243 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2244 if(et == NULL) {
2245 if (context)
2246 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2247 N_("encryption type %d not supported", ""),
2248 enctype);
2249 return KRB5_PROG_ETYPE_NOSUPP;
2251 et->flags &= ~F_DISABLED;
2252 return 0;
2256 * Enable or disable all weak encryption types
2258 * @param context Kerberos 5 context
2259 * @param enable true to enable, false to disable
2261 * @return Return an error code or 0.
2263 * @ingroup krb5_crypto
2266 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2267 krb5_allow_weak_crypto(krb5_context context,
2268 krb5_boolean enable)
2270 int i;
2272 for(i = 0; i < _krb5_num_etypes; i++)
2273 if(_krb5_etypes[i]->flags & F_WEAK) {
2274 if(enable)
2275 _krb5_etypes[i]->flags &= ~F_DISABLED;
2276 else
2277 _krb5_etypes[i]->flags |= F_DISABLED;
2279 return 0;
2282 static size_t
2283 wrapped_length (krb5_context context,
2284 krb5_crypto crypto,
2285 size_t data_len)
2287 struct _krb5_encryption_type *et = crypto->et;
2288 size_t padsize = et->padsize;
2289 size_t checksumsize = CHECKSUMSIZE(et->checksum);
2290 size_t res;
2292 res = et->confoundersize + checksumsize + data_len;
2293 res = (res + padsize - 1) / padsize * padsize;
2294 return res;
2297 static size_t
2298 wrapped_length_dervied (krb5_context context,
2299 krb5_crypto crypto,
2300 size_t data_len)
2302 struct _krb5_encryption_type *et = crypto->et;
2303 size_t padsize = et->padsize;
2304 size_t res;
2306 res = et->confoundersize + data_len;
2307 res = (res + padsize - 1) / padsize * padsize;
2308 if (et->keyed_checksum)
2309 res += et->keyed_checksum->checksumsize;
2310 else
2311 res += et->checksum->checksumsize;
2312 return res;
2316 * Return the size of an encrypted packet of length `data_len'
2319 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2320 krb5_get_wrapped_length (krb5_context context,
2321 krb5_crypto crypto,
2322 size_t data_len)
2324 if (derived_crypto (context, crypto))
2325 return wrapped_length_dervied (context, crypto, data_len);
2326 else
2327 return wrapped_length (context, crypto, data_len);
2331 * Return the size of an encrypted packet of length `data_len'
2334 static size_t
2335 crypto_overhead (krb5_context context,
2336 krb5_crypto crypto)
2338 struct _krb5_encryption_type *et = crypto->et;
2339 size_t res;
2341 res = CHECKSUMSIZE(et->checksum);
2342 res += et->confoundersize;
2343 if (et->padsize > 1)
2344 res += et->padsize;
2345 return res;
2348 static size_t
2349 crypto_overhead_dervied (krb5_context context,
2350 krb5_crypto crypto)
2352 struct _krb5_encryption_type *et = crypto->et;
2353 size_t res;
2355 if (et->keyed_checksum)
2356 res = CHECKSUMSIZE(et->keyed_checksum);
2357 else
2358 res = CHECKSUMSIZE(et->checksum);
2359 res += et->confoundersize;
2360 if (et->padsize > 1)
2361 res += et->padsize;
2362 return res;
2365 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2366 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2368 if (derived_crypto (context, crypto))
2369 return crypto_overhead_dervied (context, crypto);
2370 else
2371 return crypto_overhead (context, crypto);
2375 * Converts the random bytestring to a protocol key according to
2376 * Kerberos crypto frame work. It may be assumed that all the bits of
2377 * the input string are equally random, even though the entropy
2378 * present in the random source may be limited.
2380 * @param context Kerberos 5 context
2381 * @param type the enctype resulting key will be of
2382 * @param data input random data to convert to a key
2383 * @param size size of input random data, at least krb5_enctype_keysize() long
2384 * @param key key, output key, free with krb5_free_keyblock_contents()
2386 * @return Return an error code or 0.
2388 * @ingroup krb5_crypto
2391 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2392 krb5_random_to_key(krb5_context context,
2393 krb5_enctype type,
2394 const void *data,
2395 size_t size,
2396 krb5_keyblock *key)
2398 krb5_error_code ret;
2399 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2400 if(et == NULL) {
2401 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2402 N_("encryption type %d not supported", ""),
2403 type);
2404 return KRB5_PROG_ETYPE_NOSUPP;
2406 if ((et->keytype->bits + 7) / 8 > size) {
2407 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2408 N_("encryption key %s needs %d bytes "
2409 "of random to make an encryption key "
2410 "out of it", ""),
2411 et->name, (int)et->keytype->size);
2412 return KRB5_PROG_ETYPE_NOSUPP;
2414 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2415 if(ret)
2416 return ret;
2417 key->keytype = type;
2418 if (et->keytype->random_to_key)
2419 (*et->keytype->random_to_key)(context, key, data, size);
2420 else
2421 memcpy(key->keyvalue.data, data, et->keytype->size);
2423 return 0;
2428 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2429 krb5_crypto_prf_length(krb5_context context,
2430 krb5_enctype type,
2431 size_t *length)
2433 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2435 if(et == NULL || et->prf_length == 0) {
2436 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2437 N_("encryption type %d not supported", ""),
2438 type);
2439 return KRB5_PROG_ETYPE_NOSUPP;
2442 *length = et->prf_length;
2443 return 0;
2446 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2447 krb5_crypto_prf(krb5_context context,
2448 const krb5_crypto crypto,
2449 const krb5_data *input,
2450 krb5_data *output)
2452 struct _krb5_encryption_type *et = crypto->et;
2454 krb5_data_zero(output);
2456 if(et->prf == NULL) {
2457 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2458 "kerberos prf for %s not supported",
2459 et->name);
2460 return KRB5_PROG_ETYPE_NOSUPP;
2463 return (*et->prf)(context, crypto, input, output);
2466 static krb5_error_code
2467 krb5_crypto_prfplus(krb5_context context,
2468 const krb5_crypto crypto,
2469 const krb5_data *input,
2470 size_t length,
2471 krb5_data *output)
2473 krb5_error_code ret;
2474 krb5_data input2;
2475 unsigned char i = 1;
2476 unsigned char *p;
2478 krb5_data_zero(&input2);
2479 krb5_data_zero(output);
2481 krb5_clear_error_message(context);
2483 ret = krb5_data_alloc(output, length);
2484 if (ret) goto out;
2485 ret = krb5_data_alloc(&input2, input->length + 1);
2486 if (ret) goto out;
2488 krb5_clear_error_message(context);
2490 memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2492 p = output->data;
2494 while (length) {
2495 krb5_data block;
2497 ((unsigned char *)input2.data)[0] = i++;
2499 ret = krb5_crypto_prf(context, crypto, &input2, &block);
2500 if (ret)
2501 goto out;
2503 if (block.length < length) {
2504 memcpy(p, block.data, block.length);
2505 length -= block.length;
2506 } else {
2507 memcpy(p, block.data, length);
2508 length = 0;
2510 p += block.length;
2511 krb5_data_free(&block);
2514 out:
2515 krb5_data_free(&input2);
2516 if (ret)
2517 krb5_data_free(output);
2518 return 0;
2522 * The FX-CF2 key derivation function, used in FAST and preauth framework.
2524 * @param context Kerberos 5 context
2525 * @param crypto1 first key to combine
2526 * @param crypto2 second key to combine
2527 * @param pepper1 factor to combine with first key to garante uniqueness
2528 * @param pepper2 factor to combine with second key to garante uniqueness
2529 * @param enctype the encryption type of the resulting key
2530 * @param res allocated key, free with krb5_free_keyblock_contents()
2532 * @return Return an error code or 0.
2534 * @ingroup krb5_crypto
2537 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2538 krb5_crypto_fx_cf2(krb5_context context,
2539 const krb5_crypto crypto1,
2540 const krb5_crypto crypto2,
2541 krb5_data *pepper1,
2542 krb5_data *pepper2,
2543 krb5_enctype enctype,
2544 krb5_keyblock *res)
2546 krb5_error_code ret;
2547 krb5_data os1, os2;
2548 size_t i, keysize;
2550 memset(res, 0, sizeof(*res));
2552 ret = krb5_enctype_keysize(context, enctype, &keysize);
2553 if (ret)
2554 return ret;
2556 ret = krb5_data_alloc(&res->keyvalue, keysize);
2557 if (ret)
2558 goto out;
2559 ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2560 if (ret)
2561 goto out;
2562 ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2563 if (ret)
2564 goto out;
2566 res->keytype = enctype;
2568 unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data;
2569 for (i = 0; i < keysize; i++)
2570 p3[i] = p1[i] ^ p2[i];
2572 out:
2573 if (ret)
2574 krb5_data_free(&res->keyvalue);
2575 krb5_data_free(&os1);
2576 krb5_data_free(&os2);
2578 return ret;
2583 #ifndef HEIMDAL_SMALLER
2586 * Deprecated: keytypes doesn't exists, they are really enctypes.
2588 * @ingroup krb5_deprecated
2591 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2592 krb5_keytype_to_enctypes (krb5_context context,
2593 krb5_keytype keytype,
2594 unsigned *len,
2595 krb5_enctype **val)
2596 KRB5_DEPRECATED_FUNCTION("Use X instead")
2598 int i;
2599 unsigned n = 0;
2600 krb5_enctype *ret;
2602 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2603 if (_krb5_etypes[i]->keytype->type == keytype
2604 && !(_krb5_etypes[i]->flags & F_PSEUDO)
2605 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2606 ++n;
2608 if (n == 0) {
2609 krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
2610 "Keytype have no mapping");
2611 return KRB5_PROG_KEYTYPE_NOSUPP;
2614 ret = malloc(n * sizeof(*ret));
2615 if (ret == NULL && n != 0) {
2616 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2617 return ENOMEM;
2619 n = 0;
2620 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2621 if (_krb5_etypes[i]->keytype->type == keytype
2622 && !(_krb5_etypes[i]->flags & F_PSEUDO)
2623 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2624 ret[n++] = _krb5_etypes[i]->type;
2626 *len = n;
2627 *val = ret;
2628 return 0;
2632 * Deprecated: keytypes doesn't exists, they are really enctypes.
2634 * @ingroup krb5_deprecated
2637 /* if two enctypes have compatible keys */
2638 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2639 krb5_enctypes_compatible_keys(krb5_context context,
2640 krb5_enctype etype1,
2641 krb5_enctype etype2)
2642 KRB5_DEPRECATED_FUNCTION("Use X instead")
2644 struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
2645 struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
2646 return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2649 #endif /* HEIMDAL_SMALLER */