krb5: crypto.c avoid realloc to trim memory allocation
[heimdal.git] / lib / krb5 / crypto.c
blobd32d7e3ca76575cb07295475733a13d82e4b7f67
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 * Converts etype to a user readable string and sets as a side effect
56 * the krb5_error_message containing this string. Returns
57 * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
58 * which case the error code of the etype convesion is returned.
61 static krb5_error_code
62 unsupported_enctype(krb5_context context, krb5_enctype etype)
64 krb5_error_code ret;
65 char *name;
67 ret = krb5_enctype_to_string(context, etype, &name);
68 if (ret)
69 return ret;
71 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
72 N_("Encryption type %s not supported", ""),
73 name);
74 free(name);
75 return KRB5_PROG_ETYPE_NOSUPP;
82 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83 krb5_enctype_keysize(krb5_context context,
84 krb5_enctype type,
85 size_t *keysize)
87 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
88 if(et == NULL) {
89 return unsupported_enctype (context, type);
91 *keysize = et->keytype->size;
92 return 0;
95 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
96 krb5_enctype_keybits(krb5_context context,
97 krb5_enctype type,
98 size_t *keybits)
100 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
101 if(et == NULL) {
102 return unsupported_enctype (context, type);
104 *keybits = et->keytype->bits;
105 return 0;
108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
109 krb5_generate_random_keyblock(krb5_context context,
110 krb5_enctype type,
111 krb5_keyblock *key)
113 krb5_error_code ret;
114 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
115 if(et == NULL) {
116 return unsupported_enctype (context, type);
118 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
119 if(ret)
120 return ret;
121 key->keytype = type;
122 if(et->keytype->random_key)
123 (*et->keytype->random_key)(context, key);
124 else
125 krb5_generate_random_block(key->keyvalue.data,
126 key->keyvalue.length);
127 return 0;
130 static krb5_error_code
131 _key_schedule(krb5_context context,
132 struct _krb5_key_data *key)
134 krb5_error_code ret;
135 struct _krb5_encryption_type *et;
136 struct _krb5_key_type *kt;
138 if (key->schedule != NULL)
139 return 0;
141 et = _krb5_find_enctype(key->key->keytype);
143 if (et == NULL) {
144 return unsupported_enctype (context,
145 key->key->keytype);
148 kt = et->keytype;
150 if(kt->schedule == NULL)
151 return 0;
152 ALLOC(key->schedule, 1);
153 if (key->schedule == NULL)
154 return krb5_enomem(context);
155 ret = krb5_data_alloc(key->schedule, kt->schedule_size);
156 if(ret) {
157 free(key->schedule);
158 key->schedule = NULL;
159 return ret;
161 (*kt->schedule)(context, kt, key);
162 return 0;
165 /************************************************************
167 ************************************************************/
169 static krb5_error_code
170 EVP_unkeyed_checksum(krb5_context context,
171 krb5_crypto crypto,
172 struct _krb5_key_data *key,
173 unsigned usage,
174 const struct krb5_crypto_iov *iov,
175 int niov,
176 Checksum *C,
177 const EVP_MD *md)
179 if (_krb5_evp_digest_iov(crypto,
180 iov, niov,
181 C->checksum.data, NULL,
182 md, NULL) != 1)
183 krb5_abortx(context, "unkeyed checksum failed");
185 return 0;
188 #define EVP_SHA_CHECKSUM(name) \
190 static krb5_error_code \
191 SHA ## name ##_checksum(krb5_context context, \
192 krb5_crypto crypto, \
193 struct _krb5_key_data *key, \
194 unsigned usage, \
195 const struct krb5_crypto_iov *iov, \
196 int niov, \
197 Checksum *C) \
199 return EVP_unkeyed_checksum(context, crypto, key, \
200 usage, iov, niov, \
201 C, EVP_sha##name()); \
204 EVP_SHA_CHECKSUM(1)
205 EVP_SHA_CHECKSUM(256)
206 EVP_SHA_CHECKSUM(384)
207 EVP_SHA_CHECKSUM(512)
209 /* HMAC according to RFC2104 */
210 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
211 _krb5_internal_hmac_iov(krb5_context context,
212 krb5_crypto crypto,
213 struct _krb5_checksum_type *cm,
214 unsigned usage,
215 const struct krb5_crypto_iov *iov,
216 int niov,
217 struct _krb5_key_data *keyblock,
218 Checksum *result)
220 unsigned char *ipad, *opad;
221 unsigned char *key;
222 struct krb5_crypto_iov *working;
223 size_t key_len;
224 size_t i;
226 ipad = malloc(cm->blocksize);
227 if (ipad == NULL)
228 return ENOMEM;
230 opad = malloc(cm->blocksize + cm->checksumsize);
231 if (opad == NULL) {
232 free(ipad);
233 return ENOMEM;
236 working = calloc(niov + 1, sizeof(struct krb5_crypto_iov));
237 if (working == NULL) {
238 free(ipad);
239 free(opad);
240 return ENOMEM;
243 memset(ipad, 0x36, cm->blocksize);
244 memset(opad, 0x5c, cm->blocksize);
246 if(keyblock->key->keyvalue.length > cm->blocksize){
247 working[0].data = keyblock->key->keyvalue;
248 working[0].flags = KRB5_CRYPTO_TYPE_DATA;
249 (*cm->checksum)(context,
250 crypto,
251 keyblock,
252 usage,
253 working,
255 result);
256 key = result->checksum.data;
257 key_len = result->checksum.length;
258 } else {
259 key = keyblock->key->keyvalue.data;
260 key_len = keyblock->key->keyvalue.length;
262 for(i = 0; i < key_len; i++){
263 ipad[i] ^= key[i];
264 opad[i] ^= key[i];
267 working[0].data.data = ipad;
268 working[0].data.length = cm->blocksize;
269 working[0].flags = KRB5_CRYPTO_TYPE_DATA;
270 for (i = 0; i < niov; i++)
271 working[i + 1] = iov[i];
273 (*cm->checksum)(context, crypto, keyblock, usage, working, niov + 1, result);
274 memcpy(opad + cm->blocksize, result->checksum.data,
275 result->checksum.length);
277 working[0].data.data = opad;
278 working[0].data.length = cm->blocksize + cm->checksumsize;
279 working[0].flags = KRB5_CRYPTO_TYPE_DATA;
280 (*cm->checksum)(context, crypto, keyblock, usage, working, 1, result);
281 memset(ipad, 0, cm->blocksize);
282 free(ipad);
283 memset(opad, 0, cm->blocksize + cm->checksumsize);
284 free(opad);
285 free(working);
287 return 0;
290 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
291 _krb5_internal_hmac(krb5_context context,
292 krb5_crypto crypto,
293 struct _krb5_checksum_type *cm,
294 const void *data,
295 size_t len,
296 unsigned usage,
297 struct _krb5_key_data *keyblock,
298 Checksum *result)
300 struct krb5_crypto_iov iov[1];
302 iov[0].data.data = (void *) data;
303 iov[0].data.length = len;
304 iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
305 return _krb5_internal_hmac_iov(context, crypto, cm, usage, iov, 1,
306 keyblock, result);
309 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
310 krb5_hmac(krb5_context context,
311 krb5_cksumtype cktype,
312 const void *data,
313 size_t len,
314 unsigned usage,
315 krb5_keyblock *key,
316 Checksum *result)
318 struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
319 struct _krb5_key_data kd;
321 krb5_error_code ret;
323 if (c == NULL) {
324 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
325 N_("checksum type %d not supported", ""),
326 cktype);
327 return KRB5_PROG_SUMTYPE_NOSUPP;
330 kd.key = key;
331 kd.schedule = NULL;
333 ret = _krb5_internal_hmac(context, NULL, c, data, len, usage, &kd, result);
335 if (kd.schedule)
336 krb5_free_data(context, kd.schedule);
338 return ret;
341 krb5_error_code
342 _krb5_SP_HMAC_SHA1_checksum(krb5_context context,
343 krb5_crypto crypto,
344 struct _krb5_key_data *key,
345 unsigned usage,
346 const struct krb5_crypto_iov *iov,
347 int niov,
348 Checksum *result)
350 krb5_error_code ret;
351 unsigned char hmac[EVP_MAX_MD_SIZE];
352 unsigned int hmaclen = sizeof(hmac);
354 ret = _krb5_evp_hmac_iov(context, crypto, key, iov, niov, hmac, &hmaclen,
355 EVP_sha1(), NULL);
356 if (ret)
357 return ret;
359 heim_assert(result->checksum.length <= hmaclen,
360 "SHA1 checksum too short");
361 memcpy(result->checksum.data, hmac, result->checksum.length);
363 return 0;
366 krb5_error_code
367 _krb5_SP_HMAC_SHA1_verify(krb5_context context,
368 krb5_crypto crypto,
369 struct _krb5_key_data *key,
370 unsigned usage,
371 const struct krb5_crypto_iov *iov,
372 int niov,
373 Checksum *verify)
375 krb5_error_code ret;
376 unsigned char hmac[EVP_MAX_MD_SIZE];
377 unsigned int hmaclen = sizeof(hmac);
378 krb5_data data;
380 ret = _krb5_evp_hmac_iov(context, crypto, key, iov, niov, hmac, &hmaclen,
381 EVP_sha1(), NULL);
382 if (ret)
383 return ret;
385 data.data = hmac;
386 data.length = min(hmaclen, verify->checksum.length);
388 if(krb5_data_ct_cmp(&data, &verify->checksum) != 0)
389 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
391 return 0;
394 #define SHA_CHECKSUM(name, blocksize, outputsize) \
395 struct _krb5_checksum_type _krb5_checksum_sha##name = { \
396 CKSUMTYPE_SHA##name, \
397 "sha" #name, \
398 blocksize, \
399 outputsize, \
400 F_CPROOF, \
401 SHA##name##_checksum, \
402 NULL \
405 SHA_CHECKSUM(1, 64, 20);
406 SHA_CHECKSUM(256, 64, 32);
407 SHA_CHECKSUM(384, 128, 48);
408 SHA_CHECKSUM(512, 128, 64);
410 KRB5_LIB_FUNCTION struct _krb5_checksum_type * KRB5_LIB_CALL
411 _krb5_find_checksum(krb5_cksumtype type)
413 int i;
414 for(i = 0; i < _krb5_num_checksums; i++)
415 if(_krb5_checksum_types[i]->type == type)
416 return _krb5_checksum_types[i];
417 return NULL;
420 static krb5_error_code
421 get_checksum_key(krb5_context context,
422 krb5_crypto crypto,
423 unsigned usage, /* not krb5_key_usage */
424 struct _krb5_checksum_type *ct,
425 struct _krb5_key_data **key)
427 krb5_error_code ret = 0;
428 struct _krb5_checksum_type *kct = NULL;
430 if (crypto == NULL) {
431 krb5_set_error_message(context, KRB5_BAD_ENCTYPE,
432 N_("Checksum type %s is keyed but no "
433 "crypto context (key) was passed in", ""),
434 ct->name);
435 return KRB5_BAD_ENCTYPE;
437 kct = crypto->et->keyed_checksum;
438 if (kct == NULL || kct->type != ct->type) {
439 krb5_set_error_message(context, KRB5_BAD_ENCTYPE,
440 N_("Checksum type %s is keyed, but "
441 "the key type %s passed didnt have that checksum "
442 "type as the keyed type", ""),
443 ct->name, crypto->et->name);
444 return KRB5_BAD_ENCTYPE;
447 if(ct->flags & F_DERIVED)
448 ret = _get_derived_key(context, crypto, usage, key);
449 else if(ct->flags & F_VARIANT) {
450 size_t i;
452 *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
453 if (*key == NULL)
454 return krb5_enomem(context);
455 ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
456 if(ret)
457 return ret;
458 for(i = 0; i < (*key)->key->keyvalue.length; i++)
459 ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
460 } else {
461 *key = &crypto->key;
463 if(ret == 0)
464 ret = _key_schedule(context, *key);
465 return ret;
468 static krb5_error_code
469 create_checksum_iov(krb5_context context,
470 struct _krb5_checksum_type *ct,
471 krb5_crypto crypto,
472 unsigned usage,
473 struct krb5_crypto_iov *iov,
474 int niov,
475 krb5_flags flags,
476 Checksum *result)
478 krb5_error_code ret;
479 struct _krb5_key_data *dkey;
481 if (ct->flags & F_DISABLED) {
482 krb5_clear_error_message (context);
483 return KRB5_PROG_SUMTYPE_NOSUPP;
485 if (ct->flags & F_KEYED) {
486 ret = get_checksum_key(context, crypto, usage, ct, &dkey);
487 if (ret)
488 return ret;
489 } else if ((flags & KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM) == 0) {
490 return EINVAL;
491 } else
492 dkey = NULL;
494 result->cksumtype = ct->type;
496 return (*ct->checksum)(context, crypto, dkey, usage, iov, niov, result);
499 static krb5_error_code
500 create_checksum (krb5_context context,
501 struct _krb5_checksum_type *ct,
502 krb5_crypto crypto,
503 unsigned usage,
504 void *data,
505 size_t len,
506 krb5_flags flags,
507 Checksum *result)
509 int ret;
510 struct krb5_crypto_iov iov[1];
512 ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
513 if (ret)
514 return ret;
516 iov[0].data.data = data;
517 iov[0].data.length = len;
518 iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
520 return create_checksum_iov(context, ct, crypto, usage, iov, 1, flags, result);
523 static int
524 arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
526 return (ct->type == CKSUMTYPE_HMAC_MD5) &&
527 (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
530 static inline krb5_flags
531 crypto_flags(krb5_crypto crypto)
533 /* If caller didn't specify a key, unkeyed checksums are the only option */
534 if (crypto == NULL)
535 return KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM;
536 else
537 return crypto->flags;
540 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
541 krb5_create_checksum(krb5_context context,
542 krb5_crypto crypto,
543 krb5_key_usage usage,
544 int type,
545 void *data,
546 size_t len,
547 Checksum *result)
549 struct _krb5_checksum_type *ct = NULL;
550 unsigned keyusage;
552 /* type 0 -> pick from crypto */
553 if (type) {
554 ct = _krb5_find_checksum(type);
555 } else if (crypto) {
556 ct = crypto->et->keyed_checksum;
557 if (ct == NULL)
558 ct = crypto->et->checksum;
561 if(ct == NULL) {
562 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
563 N_("checksum type %d not supported", ""),
564 type);
565 return KRB5_PROG_SUMTYPE_NOSUPP;
568 if (arcfour_checksum_p(ct, crypto)) {
569 keyusage = usage;
570 _krb5_usage2arcfour(context, &keyusage);
571 } else
572 keyusage = CHECKSUM_USAGE(usage);
574 return create_checksum(context, ct, crypto, keyusage, data, len,
575 crypto_flags(crypto), result);
578 static krb5_error_code
579 verify_checksum_iov(krb5_context context,
580 krb5_crypto crypto,
581 unsigned usage, /* not krb5_key_usage */
582 struct krb5_crypto_iov *iov,
583 int niov,
584 krb5_flags flags,
585 Checksum *cksum)
587 krb5_error_code ret;
588 struct _krb5_key_data *dkey;
589 Checksum c;
590 struct _krb5_checksum_type *ct;
592 ct = _krb5_find_checksum(cksum->cksumtype);
593 if (ct == NULL || (ct->flags & F_DISABLED)) {
594 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
595 N_("checksum type %d not supported", ""),
596 cksum->cksumtype);
597 return KRB5_PROG_SUMTYPE_NOSUPP;
599 if(ct->checksumsize != cksum->checksum.length) {
600 krb5_clear_error_message (context);
601 krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
602 N_("Decrypt integrity check failed for checksum type %s, "
603 "length was %u, expected %u", ""),
604 ct->name, (unsigned)cksum->checksum.length,
605 (unsigned)ct->checksumsize);
607 return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
609 if (ct->flags & F_KEYED) {
610 ret = get_checksum_key(context, crypto, usage, ct, &dkey);
611 if (ret)
612 return ret;
613 } else if ((flags & KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM) == 0) {
614 krb5_clear_error_message (context);
615 krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
616 N_("Unkeyed checksum type %s provided where keyed "
617 "checksum was expected", ""), ct->name);
619 return KRB5KRB_AP_ERR_INAPP_CKSUM;
620 } else
621 dkey = NULL;
624 * If checksum have a verify function, lets use that instead of
625 * calling ->checksum and then compare result.
628 if(ct->verify) {
629 ret = (*ct->verify)(context, crypto, dkey, usage, iov, niov, cksum);
630 if (ret)
631 krb5_set_error_message(context, ret,
632 N_("Decrypt integrity check failed for checksum "
633 "type %s, key type %s", ""),
634 ct->name, (crypto != NULL)? crypto->et->name : "(none)");
635 return ret;
638 ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
639 if (ret)
640 return ret;
642 ret = (*ct->checksum)(context, crypto, dkey, usage, iov, niov, &c);
643 if (ret) {
644 krb5_data_free(&c.checksum);
645 return ret;
648 if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
649 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
650 krb5_set_error_message(context, ret,
651 N_("Decrypt integrity check failed for checksum "
652 "type %s, key type %s", ""),
653 ct->name, crypto ? crypto->et->name : "(unkeyed)");
654 } else {
655 ret = 0;
657 krb5_data_free (&c.checksum);
658 return ret;
661 static krb5_error_code
662 verify_checksum(krb5_context context,
663 krb5_crypto crypto,
664 unsigned usage, /* not krb5_key_usage */
665 void *data,
666 size_t len,
667 krb5_flags flags,
668 Checksum *cksum)
670 struct krb5_crypto_iov iov[1];
672 iov[0].data.data = data;
673 iov[0].data.length = len;
674 iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
676 return verify_checksum_iov(context, crypto, usage, iov, 1, flags, cksum);
679 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
680 krb5_verify_checksum(krb5_context context,
681 krb5_crypto crypto,
682 krb5_key_usage usage,
683 void *data,
684 size_t len,
685 Checksum *cksum)
687 struct _krb5_checksum_type *ct;
688 unsigned keyusage;
690 ct = _krb5_find_checksum(cksum->cksumtype);
691 if(ct == NULL) {
692 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
693 N_("checksum type %d not supported", ""),
694 cksum->cksumtype);
695 return KRB5_PROG_SUMTYPE_NOSUPP;
698 if (arcfour_checksum_p(ct, crypto)) {
699 keyusage = usage;
700 _krb5_usage2arcfour(context, &keyusage);
701 } else
702 keyusage = CHECKSUM_USAGE(usage);
704 return verify_checksum(context, crypto, keyusage,
705 data, len, crypto_flags(crypto), cksum);
708 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
709 krb5_crypto_get_checksum_type(krb5_context context,
710 krb5_crypto crypto,
711 krb5_cksumtype *type)
713 struct _krb5_checksum_type *ct = NULL;
715 if (crypto != NULL) {
716 ct = crypto->et->keyed_checksum;
717 if (ct == NULL)
718 ct = crypto->et->checksum;
721 if (ct == NULL) {
722 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
723 N_("checksum type not found", ""));
724 return KRB5_PROG_SUMTYPE_NOSUPP;
727 *type = ct->type;
729 return 0;
733 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
734 krb5_checksumsize(krb5_context context,
735 krb5_cksumtype type,
736 size_t *size)
738 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
739 if(ct == NULL) {
740 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
741 N_("checksum type %d not supported", ""),
742 type);
743 return KRB5_PROG_SUMTYPE_NOSUPP;
745 *size = ct->checksumsize;
746 return 0;
749 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
750 krb5_checksum_is_keyed(krb5_context context,
751 krb5_cksumtype type)
753 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
754 if(ct == NULL) {
755 if (context)
756 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
757 N_("checksum type %d not supported", ""),
758 type);
759 return KRB5_PROG_SUMTYPE_NOSUPP;
761 return ct->flags & F_KEYED;
764 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
765 krb5_checksum_is_collision_proof(krb5_context context,
766 krb5_cksumtype type)
768 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
769 if(ct == NULL) {
770 if (context)
771 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
772 N_("checksum type %d not supported", ""),
773 type);
774 return KRB5_PROG_SUMTYPE_NOSUPP;
776 return ct->flags & F_CPROOF;
779 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
780 krb5_checksum_disable(krb5_context context,
781 krb5_cksumtype type)
783 struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
784 if(ct == NULL) {
785 if (context)
786 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
787 N_("checksum type %d not supported", ""),
788 type);
789 return KRB5_PROG_SUMTYPE_NOSUPP;
791 ct->flags |= F_DISABLED;
792 return 0;
795 /************************************************************
797 ************************************************************/
799 KRB5_LIB_FUNCTION struct _krb5_encryption_type * KRB5_LIB_CALL
800 _krb5_find_enctype(krb5_enctype type)
802 int i;
803 for(i = 0; i < _krb5_num_etypes; i++)
804 if(_krb5_etypes[i]->type == type)
805 return _krb5_etypes[i];
806 return NULL;
810 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
811 krb5_enctype_to_string(krb5_context context,
812 krb5_enctype etype,
813 char **string)
815 struct _krb5_encryption_type *e;
816 e = _krb5_find_enctype(etype);
817 if(e == NULL) {
818 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
819 N_("encryption type %d not supported", ""),
820 etype);
821 *string = NULL;
822 return KRB5_PROG_ETYPE_NOSUPP;
824 *string = strdup(e->name);
825 if (*string == NULL)
826 return krb5_enomem(context);
827 return 0;
830 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
831 krb5_string_to_enctype(krb5_context context,
832 const char *string,
833 krb5_enctype *etype)
835 int i;
836 for(i = 0; i < _krb5_num_etypes; i++) {
837 if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
838 *etype = _krb5_etypes[i]->type;
839 return 0;
841 if(_krb5_etypes[i]->alias != NULL &&
842 strcasecmp(_krb5_etypes[i]->alias, string) == 0){
843 *etype = _krb5_etypes[i]->type;
844 return 0;
847 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
848 N_("encryption type %s not supported", ""),
849 string);
850 return KRB5_PROG_ETYPE_NOSUPP;
853 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
854 krb5_enctype_to_keytype(krb5_context context,
855 krb5_enctype etype,
856 krb5_keytype *keytype)
858 struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
859 if(e == NULL) {
860 return unsupported_enctype (context, etype);
862 *keytype = e->keytype->type; /* XXX */
863 return 0;
867 * Check if a enctype is valid, return 0 if it is.
869 * @param context Kerberos context
870 * @param etype enctype to check if its valid or not
872 * @return Return an error code for an failure or 0 on success (enctype valid).
873 * @ingroup krb5_crypto
876 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
877 krb5_enctype_valid(krb5_context context,
878 krb5_enctype etype)
880 struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
881 if(e && (e->flags & F_DISABLED) == 0)
882 return 0;
883 if (context == NULL)
884 return KRB5_PROG_ETYPE_NOSUPP;
885 if(e == NULL) {
886 return unsupported_enctype (context, etype);
888 /* Must be (e->flags & F_DISABLED) */
889 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
890 N_("encryption type %s is disabled", ""),
891 e->name);
892 return KRB5_PROG_ETYPE_NOSUPP;
896 * Return the coresponding encryption type for a checksum type.
898 * @param context Kerberos context
899 * @param ctype The checksum type to get the result enctype for
900 * @param etype The returned encryption, when the matching etype is
901 * not found, etype is set to ETYPE_NULL.
903 * @return Return an error code for an failure or 0 on success.
904 * @ingroup krb5_crypto
908 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
909 krb5_cksumtype_to_enctype(krb5_context context,
910 krb5_cksumtype ctype,
911 krb5_enctype *etype)
913 int i;
915 *etype = ETYPE_NULL;
917 for(i = 0; i < _krb5_num_etypes; i++) {
918 if(_krb5_etypes[i]->keyed_checksum &&
919 _krb5_etypes[i]->keyed_checksum->type == ctype)
921 *etype = _krb5_etypes[i]->type;
922 return 0;
926 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
927 N_("checksum type %d not supported", ""),
928 (int)ctype);
929 return KRB5_PROG_SUMTYPE_NOSUPP;
933 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
934 krb5_cksumtype_valid(krb5_context context,
935 krb5_cksumtype ctype)
937 struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
938 if (c == NULL) {
939 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
940 N_("checksum type %d not supported", ""),
941 ctype);
942 return KRB5_PROG_SUMTYPE_NOSUPP;
944 if (c->flags & F_DISABLED) {
945 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
946 N_("checksum type %s is disabled", ""),
947 c->name);
948 return KRB5_PROG_SUMTYPE_NOSUPP;
950 return 0;
953 static krb5_boolean
954 derived_crypto(krb5_context context,
955 krb5_crypto crypto)
957 return (crypto->et->flags & F_DERIVED) != 0;
960 #define CHECKSUMSIZE(C) ((C)->checksumsize)
961 #define CHECKSUMTYPE(C) ((C)->type)
963 static krb5_error_code
964 encrypt_internal_derived(krb5_context context,
965 krb5_crypto crypto,
966 unsigned usage,
967 const void *data,
968 size_t len,
969 krb5_data *result,
970 void *ivec)
972 size_t sz, block_sz, checksum_sz, total_sz;
973 Checksum cksum;
974 unsigned char *p, *q;
975 krb5_error_code ret;
976 struct _krb5_key_data *dkey;
977 const struct _krb5_encryption_type *et = crypto->et;
979 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
981 sz = et->confoundersize + len;
982 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
983 total_sz = block_sz + checksum_sz;
984 p = calloc(1, total_sz);
985 if (p == NULL)
986 return krb5_enomem(context);
988 q = p;
989 krb5_generate_random_block(q, et->confoundersize); /* XXX */
990 q += et->confoundersize;
991 memcpy(q, data, len);
993 ret = create_checksum(context,
994 et->keyed_checksum,
995 crypto,
996 INTEGRITY_USAGE(usage),
998 block_sz,
1000 &cksum);
1001 if(ret == 0 && cksum.checksum.length != checksum_sz) {
1002 free_Checksum (&cksum);
1003 krb5_clear_error_message (context);
1004 ret = KRB5_CRYPTO_INTERNAL;
1006 if(ret)
1007 goto fail;
1008 memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
1009 free_Checksum (&cksum);
1010 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1011 if(ret)
1012 goto fail;
1013 ret = _key_schedule(context, dkey);
1014 if(ret)
1015 goto fail;
1016 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1017 if (ret)
1018 goto fail;
1019 result->data = p;
1020 result->length = total_sz;
1021 return 0;
1022 fail:
1023 memset(p, 0, total_sz);
1024 free(p);
1025 return ret;
1028 static krb5_error_code
1029 encrypt_internal_enc_then_cksum(krb5_context context,
1030 krb5_crypto crypto,
1031 unsigned usage,
1032 const void *data,
1033 size_t len,
1034 krb5_data *result,
1035 void *ivec)
1037 size_t sz, block_sz, checksum_sz, total_sz;
1038 Checksum cksum;
1039 unsigned char *p, *q, *ivc = NULL;
1040 krb5_error_code ret;
1041 struct _krb5_key_data *dkey;
1042 const struct _krb5_encryption_type *et = crypto->et;
1044 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1046 sz = et->confoundersize + len;
1047 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1048 total_sz = block_sz + checksum_sz;
1049 p = calloc(1, total_sz);
1050 if (p == NULL)
1051 return krb5_enomem(context);
1053 q = p;
1054 krb5_generate_random_block(q, et->confoundersize); /* XXX */
1055 q += et->confoundersize;
1056 memcpy(q, data, len);
1058 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1059 if(ret)
1060 goto fail;
1061 ret = _key_schedule(context, dkey);
1062 if(ret)
1063 goto fail;
1065 /* XXX EVP style update API would avoid needing to allocate here */
1066 ivc = malloc(et->blocksize + block_sz);
1067 if (ivc == NULL) {
1068 ret = krb5_enomem(context);
1069 goto fail;
1071 if (ivec)
1072 memcpy(ivc, ivec, et->blocksize);
1073 else
1074 memset(ivc, 0, et->blocksize);
1076 ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1077 if (ret)
1078 goto fail;
1079 memcpy(&ivc[et->blocksize], p, block_sz);
1081 ret = create_checksum(context,
1082 et->keyed_checksum,
1083 crypto,
1084 INTEGRITY_USAGE(usage),
1085 ivc,
1086 et->blocksize + block_sz,
1088 &cksum);
1089 if(ret == 0 && cksum.checksum.length != checksum_sz) {
1090 free_Checksum (&cksum);
1091 krb5_clear_error_message (context);
1092 ret = KRB5_CRYPTO_INTERNAL;
1094 if(ret)
1095 goto fail;
1096 memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
1097 free_Checksum (&cksum);
1098 result->data = p;
1099 result->length = total_sz;
1100 free(ivc);
1101 return 0;
1102 fail:
1103 memset_s(p, total_sz, 0, total_sz);
1104 free(p);
1105 free(ivc);
1106 return ret;
1109 static krb5_error_code
1110 encrypt_internal(krb5_context context,
1111 krb5_crypto crypto,
1112 const void *data,
1113 size_t len,
1114 krb5_data *result,
1115 void *ivec)
1117 size_t sz, block_sz, checksum_sz;
1118 Checksum cksum;
1119 unsigned char *p, *q;
1120 krb5_error_code ret;
1121 const struct _krb5_encryption_type *et = crypto->et;
1123 checksum_sz = CHECKSUMSIZE(et->checksum);
1125 sz = et->confoundersize + checksum_sz + len;
1126 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1127 p = calloc(1, block_sz);
1128 if (p == NULL)
1129 return krb5_enomem(context);
1131 q = p;
1132 krb5_generate_random_block(q, et->confoundersize); /* XXX */
1133 q += et->confoundersize;
1134 memset(q, 0, checksum_sz);
1135 q += checksum_sz;
1136 memcpy(q, data, len);
1138 ret = create_checksum(context,
1139 et->checksum,
1140 crypto,
1143 block_sz,
1144 KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM,
1145 &cksum);
1146 if(ret == 0 && cksum.checksum.length != checksum_sz) {
1147 krb5_clear_error_message (context);
1148 free_Checksum(&cksum);
1149 ret = KRB5_CRYPTO_INTERNAL;
1151 if(ret)
1152 goto fail;
1153 memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
1154 free_Checksum(&cksum);
1155 ret = _key_schedule(context, &crypto->key);
1156 if(ret)
1157 goto fail;
1158 ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
1159 if (ret) {
1160 memset(p, 0, block_sz);
1161 free(p);
1162 return ret;
1164 result->data = p;
1165 result->length = block_sz;
1166 return 0;
1167 fail:
1168 memset(p, 0, block_sz);
1169 free(p);
1170 return ret;
1173 static krb5_error_code
1174 encrypt_internal_special(krb5_context context,
1175 krb5_crypto crypto,
1176 int usage,
1177 const void *data,
1178 size_t len,
1179 krb5_data *result,
1180 void *ivec)
1182 struct _krb5_encryption_type *et = crypto->et;
1183 size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1184 size_t sz = len + cksum_sz + et->confoundersize;
1185 char *tmp, *p;
1186 krb5_error_code ret;
1188 tmp = malloc (sz);
1189 if (tmp == NULL)
1190 return krb5_enomem(context);
1191 p = tmp;
1192 memset (p, 0, cksum_sz);
1193 p += cksum_sz;
1194 krb5_generate_random_block(p, et->confoundersize);
1195 p += et->confoundersize;
1196 memcpy (p, data, len);
1197 ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
1198 if (ret) {
1199 memset(tmp, 0, sz);
1200 free(tmp);
1201 return ret;
1203 result->data = tmp;
1204 result->length = sz;
1205 return 0;
1208 static krb5_error_code
1209 decrypt_internal_derived(krb5_context context,
1210 krb5_crypto crypto,
1211 unsigned usage,
1212 void *data,
1213 size_t len,
1214 krb5_data *result,
1215 void *ivec)
1217 size_t checksum_sz;
1218 Checksum cksum;
1219 unsigned char *p;
1220 krb5_error_code ret;
1221 struct _krb5_key_data *dkey;
1222 struct _krb5_encryption_type *et = crypto->et;
1223 unsigned long l;
1225 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1226 if (len < checksum_sz + et->confoundersize) {
1227 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1228 N_("Encrypted data shorter then "
1229 "checksum + confunder", ""));
1230 return KRB5_BAD_MSIZE;
1233 if (((len - checksum_sz) % et->padsize) != 0) {
1234 krb5_clear_error_message(context);
1235 return KRB5_BAD_MSIZE;
1238 p = malloc(len);
1239 if (len != 0 && p == NULL)
1240 return krb5_enomem(context);
1241 memcpy(p, data, len);
1243 len -= checksum_sz;
1245 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1246 if(ret) {
1247 free(p);
1248 return ret;
1250 ret = _key_schedule(context, dkey);
1251 if(ret) {
1252 free(p);
1253 return ret;
1255 ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1256 if (ret) {
1257 free(p);
1258 return ret;
1261 cksum.checksum.data = p + len;
1262 cksum.checksum.length = checksum_sz;
1263 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1265 ret = verify_checksum(context,
1266 crypto,
1267 INTEGRITY_USAGE(usage),
1269 len,
1271 &cksum);
1272 if(ret) {
1273 free(p);
1274 return ret;
1276 l = len - et->confoundersize;
1277 memmove(p, p + et->confoundersize, l);
1278 result->length = l;
1279 return 0;
1282 static krb5_error_code
1283 decrypt_internal_enc_then_cksum(krb5_context context,
1284 krb5_crypto crypto,
1285 unsigned usage,
1286 void *data,
1287 size_t len,
1288 krb5_data *result,
1289 void *ivec)
1291 size_t checksum_sz;
1292 Checksum cksum;
1293 unsigned char *p;
1294 krb5_error_code ret;
1295 struct _krb5_key_data *dkey;
1296 struct _krb5_encryption_type *et = crypto->et;
1297 unsigned long l;
1299 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1300 if (len < checksum_sz + et->confoundersize) {
1301 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1302 N_("Encrypted data shorter then "
1303 "checksum + confunder", ""));
1304 return KRB5_BAD_MSIZE;
1307 if (((len - checksum_sz) % et->padsize) != 0) {
1308 krb5_clear_error_message(context);
1309 return KRB5_BAD_MSIZE;
1312 len -= checksum_sz;
1314 p = malloc(et->blocksize + len);
1315 if (p == NULL)
1316 return krb5_enomem(context);
1318 if (ivec)
1319 memcpy(p, ivec, et->blocksize);
1320 else
1321 memset(p, 0, et->blocksize);
1322 memcpy(&p[et->blocksize], data, len);
1324 cksum.checksum.data = (unsigned char *)data + len;
1325 cksum.checksum.length = checksum_sz;
1326 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1328 ret = verify_checksum(context,
1329 crypto,
1330 INTEGRITY_USAGE(usage),
1332 et->blocksize + len,
1334 &cksum);
1335 if(ret) {
1336 free(p);
1337 return ret;
1340 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1341 if(ret) {
1342 free(p);
1343 return ret;
1345 ret = _key_schedule(context, dkey);
1346 if(ret) {
1347 free(p);
1348 return ret;
1350 ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec);
1351 if (ret) {
1352 free(p);
1353 return ret;
1356 l = len - et->confoundersize;
1357 memmove(p, p + et->blocksize + et->confoundersize, l);
1358 result->length = l;
1359 return 0;
1362 static krb5_error_code
1363 decrypt_internal(krb5_context context,
1364 krb5_crypto crypto,
1365 void *data,
1366 size_t len,
1367 krb5_data *result,
1368 void *ivec)
1370 krb5_error_code ret;
1371 unsigned char *p;
1372 Checksum cksum;
1373 size_t checksum_sz, l;
1374 struct _krb5_encryption_type *et = crypto->et;
1376 if ((len % et->padsize) != 0) {
1377 krb5_clear_error_message(context);
1378 return KRB5_BAD_MSIZE;
1380 checksum_sz = CHECKSUMSIZE(et->checksum);
1381 if (len < checksum_sz + et->confoundersize) {
1382 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1383 N_("Encrypted data shorter then "
1384 "checksum + confunder", ""));
1385 return KRB5_BAD_MSIZE;
1388 p = malloc(len);
1389 if (len != 0 && p == NULL)
1390 return krb5_enomem(context);
1391 memcpy(p, data, len);
1393 ret = _key_schedule(context, &crypto->key);
1394 if(ret) {
1395 free(p);
1396 return ret;
1398 ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1399 if (ret) {
1400 free(p);
1401 return ret;
1403 ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1404 if(ret) {
1405 free(p);
1406 return ret;
1408 memset(p + et->confoundersize, 0, checksum_sz);
1409 cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1410 ret = verify_checksum(context, NULL, 0, p, len,
1411 KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM, &cksum);
1412 free_Checksum(&cksum);
1413 if(ret) {
1414 free(p);
1415 return ret;
1417 l = len - et->confoundersize - checksum_sz;
1418 memmove(p, p + et->confoundersize + checksum_sz, l);
1419 result->length = l;
1420 return 0;
1423 static krb5_error_code
1424 decrypt_internal_special(krb5_context context,
1425 krb5_crypto crypto,
1426 int usage,
1427 void *data,
1428 size_t len,
1429 krb5_data *result,
1430 void *ivec)
1432 struct _krb5_encryption_type *et = crypto->et;
1433 size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1434 size_t sz = len - cksum_sz - et->confoundersize;
1435 unsigned char *p;
1436 krb5_error_code ret;
1438 if ((len % et->padsize) != 0) {
1439 krb5_clear_error_message(context);
1440 return KRB5_BAD_MSIZE;
1442 if (len < cksum_sz + et->confoundersize) {
1443 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1444 N_("Encrypted data shorter then "
1445 "checksum + confunder", ""));
1446 return KRB5_BAD_MSIZE;
1449 p = malloc (len);
1450 if (p == NULL)
1451 return krb5_enomem(context);
1452 memcpy(p, data, len);
1454 ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1455 if (ret) {
1456 free(p);
1457 return ret;
1460 memmove (p, p + cksum_sz + et->confoundersize, sz);
1461 result->length = sz;
1462 return 0;
1465 static krb5_crypto_iov *
1466 iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type)
1468 size_t i;
1469 for (i = 0; i < num_data; i++)
1470 if (data[i].flags == type)
1471 return &data[i];
1472 return NULL;
1475 static size_t
1476 iov_enc_data_len(krb5_crypto_iov *data, int num_data)
1478 size_t i, len;
1480 for (len = 0, i = 0; i < num_data; i++) {
1481 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1482 continue;
1483 len += data[i].data.length;
1486 return len;
1489 static size_t
1490 iov_sign_data_len(krb5_crypto_iov *data, int num_data)
1492 size_t i, len;
1494 for (len = 0, i = 0; i < num_data; i++) {
1495 /* Can't use should_sign, because we must only count data, not
1496 * header/trailer */
1497 if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1498 data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
1499 len += data[i].data.length;
1502 return len;
1505 static krb5_error_code
1506 iov_coalesce(krb5_context context,
1507 krb5_data *prefix,
1508 krb5_crypto_iov *data,
1509 int num_data,
1510 krb5_boolean inc_sign_data,
1511 krb5_data *out)
1513 unsigned char *p, *q;
1514 krb5_crypto_iov *hiv, *piv;
1515 size_t len;
1516 unsigned int i;
1518 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1520 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1522 len = 0;
1523 if (prefix)
1524 len += prefix->length;
1525 len += hiv->data.length;
1526 if (inc_sign_data)
1527 len += iov_sign_data_len(data, num_data);
1528 else
1529 len += iov_enc_data_len(data, num_data);
1530 if (piv)
1531 len += piv->data.length;
1533 p = q = malloc(len);
1534 if (p == NULL)
1535 return krb5_enomem(context);
1537 if (prefix) {
1538 memcpy(q, prefix->data, prefix->length);
1539 q += prefix->length;
1541 memcpy(q, hiv->data.data, hiv->data.length);
1542 q += hiv->data.length;
1543 for (i = 0; i < num_data; i++) {
1544 if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1545 (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) {
1546 memcpy(q, data[i].data.data, data[i].data.length);
1547 q += data[i].data.length;
1550 if (piv)
1551 memset(q, 0, piv->data.length);
1553 out->length = len;
1554 out->data = p;
1556 return 0;
1559 static krb5_error_code
1560 iov_uncoalesce(krb5_context context,
1561 krb5_data *enc_data,
1562 krb5_crypto_iov *data,
1563 int num_data)
1565 unsigned char *q = enc_data->data;
1566 krb5_crypto_iov *hiv, *piv;
1567 unsigned int i;
1569 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1571 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1573 memcpy(hiv->data.data, q, hiv->data.length);
1574 q += hiv->data.length;
1576 for (i = 0; i < num_data; i++) {
1577 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1578 continue;
1579 memcpy(data[i].data.data, q, data[i].data.length);
1580 q += data[i].data.length;
1582 if (piv)
1583 memcpy(piv->data.data, q, piv->data.length);
1585 return 0;
1588 static krb5_error_code
1589 iov_pad_validate(const struct _krb5_encryption_type *et,
1590 krb5_crypto_iov *data,
1591 int num_data,
1592 krb5_crypto_iov **ppiv)
1594 krb5_crypto_iov *piv;
1595 size_t sz, headersz, block_sz, pad_sz, len;
1597 len = iov_enc_data_len(data, num_data);
1599 headersz = et->confoundersize;
1601 sz = headersz + len;
1602 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1604 pad_sz = block_sz - sz;
1606 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1607 /* its ok to have no TYPE_PADDING if there is no padding */
1608 if (piv == NULL && pad_sz != 0)
1609 return KRB5_BAD_MSIZE;
1610 if (piv) {
1611 if (piv->data.length < pad_sz)
1612 return KRB5_BAD_MSIZE;
1613 piv->data.length = pad_sz;
1614 if (pad_sz)
1615 memset(piv->data.data, 0, pad_sz);
1616 else
1617 piv = NULL;
1620 *ppiv = piv;
1621 return 0;
1625 * Inline encrypt a kerberos message
1627 * @param context Kerberos context
1628 * @param crypto Kerberos crypto context
1629 * @param usage Key usage for this buffer
1630 * @param data array of buffers to process
1631 * @param num_data length of array
1632 * @param ivec initial cbc/cts vector
1634 * @return Return an error code or 0.
1635 * @ingroup krb5_crypto
1637 * Kerberos encrypted data look like this:
1639 * 1. KRB5_CRYPTO_TYPE_HEADER
1640 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1641 * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1642 * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1643 * commonly used headers and trailers.
1644 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1645 * 4. KRB5_CRYPTO_TYPE_TRAILER
1648 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1649 krb5_encrypt_iov_ivec(krb5_context context,
1650 krb5_crypto crypto,
1651 unsigned usage,
1652 krb5_crypto_iov *data,
1653 int num_data,
1654 void *ivec)
1656 size_t headersz, trailersz;
1657 Checksum cksum;
1658 krb5_data enc_data, sign_data;
1659 krb5_error_code ret;
1660 struct _krb5_key_data *dkey;
1661 const struct _krb5_encryption_type *et = crypto->et;
1662 krb5_crypto_iov *tiv, *piv, *hiv;
1664 if (num_data < 0) {
1665 krb5_clear_error_message(context);
1666 return KRB5_CRYPTO_INTERNAL;
1669 if(!derived_crypto(context, crypto)) {
1670 krb5_clear_error_message(context);
1671 return KRB5_CRYPTO_INTERNAL;
1674 krb5_data_zero(&enc_data);
1675 krb5_data_zero(&sign_data);
1677 headersz = et->confoundersize;
1678 trailersz = CHECKSUMSIZE(et->keyed_checksum);
1680 /* header */
1681 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1682 if (hiv == NULL || hiv->data.length != headersz)
1683 return KRB5_BAD_MSIZE;
1684 krb5_generate_random_block(hiv->data.data, hiv->data.length);
1686 /* padding */
1687 ret = iov_pad_validate(et, data, num_data, &piv);
1688 if(ret)
1689 goto cleanup;
1691 /* trailer */
1692 tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1693 if (tiv == NULL || tiv->data.length != trailersz) {
1694 ret = KRB5_BAD_MSIZE;
1695 goto cleanup;
1698 if (et->flags & F_ENC_THEN_CKSUM) {
1699 unsigned char old_ivec[EVP_MAX_IV_LENGTH];
1700 krb5_data ivec_data;
1702 heim_assert(et->blocksize <= sizeof(old_ivec),
1703 "blocksize too big for ivec buffer");
1705 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1706 if(ret)
1707 goto cleanup;
1709 ret = _key_schedule(context, dkey);
1710 if(ret)
1711 goto cleanup;
1713 if (ivec)
1714 memcpy(old_ivec, ivec, et->blocksize);
1715 else
1716 memset(old_ivec, 0, et->blocksize);
1718 if (et->encrypt_iov != NULL) {
1719 ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage,
1720 ivec);
1721 if (ret)
1722 goto cleanup;
1723 } else {
1724 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1725 if (ret)
1726 goto cleanup;
1728 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1729 1, usage, ivec);
1730 if (ret)
1731 goto cleanup;
1733 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1734 if (ret)
1735 goto cleanup;
1738 ivec_data.length = et->blocksize;
1739 ivec_data.data = old_ivec;
1741 ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1742 if(ret)
1743 goto cleanup;
1745 ret = create_checksum(context,
1746 et->keyed_checksum,
1747 crypto,
1748 INTEGRITY_USAGE(usage),
1749 sign_data.data,
1750 sign_data.length,
1752 &cksum);
1754 if(ret == 0 && cksum.checksum.length != trailersz) {
1755 free_Checksum (&cksum);
1756 krb5_clear_error_message (context);
1757 ret = KRB5_CRYPTO_INTERNAL;
1759 if (ret)
1760 goto cleanup;
1762 /* save cksum at end */
1763 memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1764 free_Checksum (&cksum);
1766 } else {
1767 cksum.checksum = tiv->data;
1768 ret = create_checksum_iov(context,
1769 et->keyed_checksum,
1770 crypto,
1771 INTEGRITY_USAGE(usage),
1772 data,
1773 num_data,
1775 &cksum);
1776 if (ret)
1777 goto cleanup;
1779 /* create_checksum may realloc the derived key space, so any keys
1780 * obtained before it was called may no longer be valid */
1781 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1782 if(ret)
1783 goto cleanup;
1785 ret = _key_schedule(context, dkey);
1786 if(ret)
1787 goto cleanup;
1789 if (et->encrypt_iov != NULL) {
1790 ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage,
1791 ivec);
1792 if (ret)
1793 goto cleanup;
1794 } else {
1795 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1796 if (ret)
1797 goto cleanup;
1799 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1800 1, usage, ivec);
1801 if (ret)
1802 goto cleanup;
1804 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1805 if (ret)
1806 goto cleanup;
1810 cleanup:
1811 if (enc_data.data) {
1812 memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1813 krb5_data_free(&enc_data);
1815 if (sign_data.data) {
1816 memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1817 krb5_data_free(&sign_data);
1819 return ret;
1823 * Inline decrypt a Kerberos message.
1825 * @param context Kerberos context
1826 * @param crypto Kerberos crypto context
1827 * @param usage Key usage for this buffer
1828 * @param data array of buffers to process
1829 * @param num_data length of array
1830 * @param ivec initial cbc/cts vector
1832 * @return Return an error code or 0.
1833 * @ingroup krb5_crypto
1835 * 1. KRB5_CRYPTO_TYPE_HEADER
1836 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1837 * any order, however the receiver have to aware of the
1838 * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1839 * protocol headers and trailers. The output data will be of same
1840 * size as the input data or shorter.
1843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1844 krb5_decrypt_iov_ivec(krb5_context context,
1845 krb5_crypto crypto,
1846 unsigned usage,
1847 krb5_crypto_iov *data,
1848 unsigned int num_data,
1849 void *ivec)
1851 Checksum cksum;
1852 krb5_data enc_data, sign_data;
1853 krb5_error_code ret;
1854 struct _krb5_key_data *dkey;
1855 struct _krb5_encryption_type *et = crypto->et;
1856 krb5_crypto_iov *tiv, *hiv;
1858 if(!derived_crypto(context, crypto)) {
1859 krb5_clear_error_message(context);
1860 return KRB5_CRYPTO_INTERNAL;
1863 /* header */
1864 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1865 if (hiv == NULL || hiv->data.length != et->confoundersize)
1866 return KRB5_BAD_MSIZE;
1868 /* trailer */
1869 tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1870 if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum))
1871 return KRB5_BAD_MSIZE;
1873 /* padding */
1874 if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) {
1875 krb5_clear_error_message(context);
1876 return KRB5_BAD_MSIZE;
1879 krb5_data_zero(&enc_data);
1880 krb5_data_zero(&sign_data);
1882 if (!(et->flags & F_ENC_THEN_CKSUM)) {
1883 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1884 if(ret)
1885 goto cleanup;
1887 ret = _key_schedule(context, dkey);
1888 if(ret)
1889 goto cleanup;
1891 if (et->encrypt_iov != NULL) {
1892 ret = (*et->encrypt_iov)(context, dkey, data, num_data,
1893 0, usage, ivec);
1894 if(ret)
1895 goto cleanup;
1896 } else {
1897 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1898 if(ret)
1899 goto cleanup;
1901 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1902 0, usage, ivec);
1903 if(ret)
1904 goto cleanup;
1906 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1907 if(ret)
1908 goto cleanup;
1911 cksum.checksum.data = tiv->data.data;
1912 cksum.checksum.length = tiv->data.length;
1913 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1915 ret = verify_checksum_iov(context, crypto, INTEGRITY_USAGE(usage),
1916 data, num_data, 0, &cksum);
1917 if(ret)
1918 goto cleanup;
1919 } else {
1920 krb5_data ivec_data;
1921 static unsigned char zero_ivec[EVP_MAX_IV_LENGTH];
1923 heim_assert(et->blocksize <= sizeof(zero_ivec),
1924 "blocksize too big for ivec buffer");
1926 ivec_data.length = et->blocksize;
1927 ivec_data.data = ivec ? ivec : zero_ivec;
1929 ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1930 if(ret)
1931 goto cleanup;
1933 cksum.checksum.data = tiv->data.data;
1934 cksum.checksum.length = tiv->data.length;
1935 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1937 ret = verify_checksum(context,
1938 crypto,
1939 INTEGRITY_USAGE(usage),
1940 sign_data.data,
1941 sign_data.length,
1943 &cksum);
1944 if(ret)
1945 goto cleanup;
1947 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1948 if(ret)
1949 goto cleanup;
1951 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1952 if(ret)
1953 goto cleanup;
1955 ret = _key_schedule(context, dkey);
1956 if(ret)
1957 goto cleanup;
1959 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1960 0, usage, ivec);
1961 if(ret)
1962 goto cleanup;
1964 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1965 if(ret)
1966 goto cleanup;
1969 cleanup:
1970 if (enc_data.data) {
1971 memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1972 krb5_data_free(&enc_data);
1974 if (sign_data.data) {
1975 memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1976 krb5_data_free(&sign_data);
1978 return ret;
1982 * Create a Kerberos message checksum.
1984 * @param context Kerberos context
1985 * @param crypto Kerberos crypto context
1986 * @param usage Key usage for this buffer
1987 * @param data array of buffers to process
1988 * @param num_data length of array
1989 * @param type output data
1991 * @return Return an error code or 0.
1992 * @ingroup krb5_crypto
1995 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1996 krb5_create_checksum_iov(krb5_context context,
1997 krb5_crypto crypto,
1998 unsigned usage,
1999 krb5_crypto_iov *data,
2000 unsigned int num_data,
2001 krb5_cksumtype *type)
2003 Checksum cksum;
2004 krb5_crypto_iov *civ;
2005 struct _krb5_checksum_type *ct;
2006 unsigned keyusage;
2007 krb5_error_code ret;
2009 civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
2010 if (civ == NULL)
2011 return KRB5_BAD_MSIZE;
2013 ct = crypto->et->keyed_checksum;
2014 if (ct == NULL)
2015 ct = crypto->et->checksum;
2017 if(ct == NULL) {
2018 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2019 N_("checksum type not found", ""));
2020 return KRB5_PROG_SUMTYPE_NOSUPP;
2023 if (arcfour_checksum_p(ct, crypto)) {
2024 keyusage = usage;
2025 _krb5_usage2arcfour(context, &keyusage);
2026 } else
2027 keyusage = CHECKSUM_USAGE(usage);
2029 if (ct->checksumsize > civ->data.length) {
2030 krb5_set_error_message(context, KRB5_BAD_MSIZE,
2031 N_("Checksum larger then input buffer", ""));
2032 return KRB5_BAD_MSIZE;
2035 cksum.checksum = civ->data;
2036 ret = create_checksum_iov(context, ct, crypto, keyusage,
2037 data, num_data, crypto_flags(crypto), &cksum);
2039 if (ret == 0 && type)
2040 *type = cksum.cksumtype;
2042 return ret;
2046 * Verify a Kerberos message checksum.
2048 * @param context Kerberos context
2049 * @param crypto Kerberos crypto context
2050 * @param usage Key usage for this buffer
2051 * @param data array of buffers to process
2052 * @param num_data length of array
2053 * @param type return checksum type if not NULL
2055 * @return Return an error code or 0.
2056 * @ingroup krb5_crypto
2059 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2060 krb5_verify_checksum_iov(krb5_context context,
2061 krb5_crypto crypto,
2062 unsigned usage,
2063 krb5_crypto_iov *data,
2064 unsigned int num_data,
2065 krb5_cksumtype *type)
2067 struct _krb5_encryption_type *et = crypto->et;
2068 struct _krb5_checksum_type *ct;
2069 Checksum cksum;
2070 krb5_crypto_iov *civ;
2071 krb5_error_code ret;
2072 unsigned keyusage;
2074 civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
2075 if (civ == NULL)
2076 return KRB5_BAD_MSIZE;
2078 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
2079 cksum.checksum.length = civ->data.length;
2080 cksum.checksum.data = civ->data.data;
2082 ct = _krb5_find_checksum(cksum.cksumtype);
2083 if(ct == NULL) {
2084 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2085 N_("checksum type %d not supported", ""),
2086 cksum.cksumtype);
2087 return KRB5_PROG_SUMTYPE_NOSUPP;
2090 if (arcfour_checksum_p(ct, crypto)) {
2091 keyusage = usage;
2092 _krb5_usage2arcfour(context, &keyusage);
2093 } else
2094 keyusage = CHECKSUM_USAGE(usage);
2096 ret = verify_checksum_iov(context, crypto, keyusage, data, num_data,
2097 crypto_flags(crypto), &cksum);
2099 if (ret == 0 && type)
2100 *type = cksum.cksumtype;
2102 return ret;
2106 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2107 krb5_crypto_length(krb5_context context,
2108 krb5_crypto crypto,
2109 int type,
2110 size_t *len)
2112 if (!derived_crypto(context, crypto)) {
2113 krb5_set_error_message(context, EINVAL, "not a derived crypto");
2114 return EINVAL;
2117 switch(type) {
2118 case KRB5_CRYPTO_TYPE_EMPTY:
2119 *len = 0;
2120 return 0;
2121 case KRB5_CRYPTO_TYPE_HEADER:
2122 *len = crypto->et->blocksize;
2123 return 0;
2124 case KRB5_CRYPTO_TYPE_DATA:
2125 case KRB5_CRYPTO_TYPE_SIGN_ONLY:
2126 /* len must already been filled in */
2127 return 0;
2128 case KRB5_CRYPTO_TYPE_PADDING:
2129 if (crypto->et->padsize > 1)
2130 *len = crypto->et->padsize;
2131 else
2132 *len = 0;
2133 return 0;
2134 case KRB5_CRYPTO_TYPE_TRAILER:
2135 if (crypto->et->keyed_checksum)
2136 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
2137 else
2138 *len = 0;
2139 return 0;
2140 case KRB5_CRYPTO_TYPE_CHECKSUM:
2141 if (crypto->et->keyed_checksum)
2142 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
2143 else
2144 *len = CHECKSUMSIZE(crypto->et->checksum);
2145 return 0;
2147 krb5_set_error_message(context, EINVAL,
2148 "%d not a supported type", type);
2149 return EINVAL;
2153 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2154 krb5_crypto_length_iov(krb5_context context,
2155 krb5_crypto crypto,
2156 krb5_crypto_iov *data,
2157 unsigned int num_data)
2159 krb5_error_code ret;
2160 size_t i;
2162 for (i = 0; i < num_data; i++) {
2163 ret = krb5_crypto_length(context, crypto,
2164 data[i].flags,
2165 &data[i].data.length);
2166 if (ret)
2167 return ret;
2169 return 0;
2173 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2174 krb5_encrypt_ivec(krb5_context context,
2175 krb5_crypto crypto,
2176 unsigned usage,
2177 const void *data,
2178 size_t len,
2179 krb5_data *result,
2180 void *ivec)
2182 krb5_error_code ret;
2184 switch (crypto->et->flags & F_CRYPTO_MASK) {
2185 case F_RFC3961_ENC:
2186 ret = encrypt_internal_derived(context, crypto, usage,
2187 data, len, result, ivec);
2188 break;
2189 case F_SPECIAL:
2190 ret = encrypt_internal_special (context, crypto, usage,
2191 data, len, result, ivec);
2192 break;
2193 case F_ENC_THEN_CKSUM:
2194 ret = encrypt_internal_enc_then_cksum(context, crypto, usage,
2195 data, len, result, ivec);
2196 break;
2197 default:
2198 ret = encrypt_internal(context, crypto, data, len, result, ivec);
2199 break;
2202 return ret;
2205 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2206 krb5_encrypt(krb5_context context,
2207 krb5_crypto crypto,
2208 unsigned usage,
2209 const void *data,
2210 size_t len,
2211 krb5_data *result)
2213 return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
2216 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2217 krb5_encrypt_EncryptedData(krb5_context context,
2218 krb5_crypto crypto,
2219 unsigned usage,
2220 void *data,
2221 size_t len,
2222 int kvno,
2223 EncryptedData *result)
2225 result->etype = CRYPTO_ETYPE(crypto);
2226 if(kvno){
2227 ALLOC(result->kvno, 1);
2228 *result->kvno = kvno;
2229 }else
2230 result->kvno = NULL;
2231 return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
2234 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2235 krb5_decrypt_ivec(krb5_context context,
2236 krb5_crypto crypto,
2237 unsigned usage,
2238 void *data,
2239 size_t len,
2240 krb5_data *result,
2241 void *ivec)
2243 krb5_error_code ret;
2245 switch (crypto->et->flags & F_CRYPTO_MASK) {
2246 case F_RFC3961_ENC:
2247 ret = decrypt_internal_derived(context, crypto, usage,
2248 data, len, result, ivec);
2249 break;
2250 case F_SPECIAL:
2251 ret = decrypt_internal_special(context, crypto, usage,
2252 data, len, result, ivec);
2253 break;
2254 case F_ENC_THEN_CKSUM:
2255 ret = decrypt_internal_enc_then_cksum(context, crypto, usage,
2256 data, len, result, ivec);
2257 break;
2258 default:
2259 ret = decrypt_internal(context, crypto, data, len, result, ivec);
2260 break;
2263 return ret;
2266 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2267 krb5_decrypt(krb5_context context,
2268 krb5_crypto crypto,
2269 unsigned usage,
2270 void *data,
2271 size_t len,
2272 krb5_data *result)
2274 return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
2275 NULL);
2278 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2279 krb5_decrypt_EncryptedData(krb5_context context,
2280 krb5_crypto crypto,
2281 unsigned usage,
2282 const EncryptedData *e,
2283 krb5_data *result)
2285 return krb5_decrypt(context, crypto, usage,
2286 e->cipher.data, e->cipher.length, result);
2289 /************************************************************
2291 ************************************************************/
2293 static krb5_error_code
2294 derive_key_rfc3961(krb5_context context,
2295 struct _krb5_encryption_type *et,
2296 struct _krb5_key_data *key,
2297 const void *constant,
2298 size_t len)
2301 unsigned char *k = NULL;
2302 unsigned int nblocks = 0, i;
2303 krb5_error_code ret = 0;
2304 struct _krb5_key_type *kt = et->keytype;
2306 if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
2307 nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
2308 k = malloc(nblocks * et->blocksize);
2309 if(k == NULL) {
2310 ret = krb5_enomem(context);
2311 goto out;
2313 ret = _krb5_n_fold(constant, len, k, et->blocksize);
2314 if (ret) {
2315 krb5_enomem(context);
2316 goto out;
2319 for(i = 0; i < nblocks; i++) {
2320 if(i > 0)
2321 memcpy(k + i * et->blocksize,
2322 k + (i - 1) * et->blocksize,
2323 et->blocksize);
2324 ret = (*et->encrypt)(context, key, k + i * et->blocksize,
2325 et->blocksize, 1, 0, NULL);
2326 if (ret) {
2327 krb5_set_error_message(context, ret, N_("encrypt failed", ""));
2328 goto out;
2331 } else {
2332 /* this case is probably broken, but won't be run anyway */
2333 void *c = malloc(len);
2334 size_t res_len = (kt->bits + 7) / 8;
2336 if(len != 0 && c == NULL) {
2337 ret = krb5_enomem(context);
2338 goto out;
2340 memcpy(c, constant, len);
2341 ret = (*et->encrypt)(context, key, c, len, 1, 0, NULL);
2342 if (ret) {
2343 free(c);
2344 krb5_set_error_message(context, ret, N_("encrypt failed", ""));
2345 goto out;
2347 k = malloc(res_len);
2348 if(res_len != 0 && k == NULL) {
2349 free(c);
2350 ret = krb5_enomem(context);
2351 goto out;
2353 ret = _krb5_n_fold(c, len, k, res_len);
2354 free(c);
2355 if (ret) {
2356 krb5_enomem(context);
2357 goto out;
2361 if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1)
2362 _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
2363 else
2364 memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
2366 out:
2367 if (k) {
2368 memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize);
2369 free(k);
2371 return ret;
2374 static krb5_error_code
2375 derive_key_sp800_hmac(krb5_context context,
2376 struct _krb5_encryption_type *et,
2377 struct _krb5_key_data *key,
2378 const void *constant,
2379 size_t len)
2381 krb5_error_code ret;
2382 struct _krb5_key_type *kt = et->keytype;
2383 krb5_data label;
2384 const EVP_MD *md = NULL;
2385 const unsigned char *c = constant;
2386 size_t key_len;
2387 krb5_data K1;
2389 ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md);
2390 if (ret)
2391 return ret;
2394 * PRF usage: not handled here (output cannot be longer)
2395 * Integrity usage: truncated hash (half length)
2396 * Encryption usage: base key length
2398 if (len == 5 && (c[4] == 0x99 || c[4] == 0x55))
2399 key_len = EVP_MD_size(md) / 2;
2400 else
2401 key_len = kt->size;
2403 ret = krb5_data_alloc(&K1, key_len);
2404 if (ret)
2405 return ret;
2407 label.data = (void *)constant;
2408 label.length = len;
2410 ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue,
2411 &label, NULL, md, &K1);
2412 if (ret == 0) {
2413 if (key->key->keyvalue.length > key_len)
2414 key->key->keyvalue.length = key_len;
2415 memcpy(key->key->keyvalue.data, K1.data, key_len);
2418 memset_s(K1.data, K1.length, 0, K1.length);
2419 krb5_data_free(&K1);
2421 return ret;
2424 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2425 _krb5_derive_key(krb5_context context,
2426 struct _krb5_encryption_type *et,
2427 struct _krb5_key_data *key,
2428 const void *constant,
2429 size_t len)
2431 krb5_error_code ret;
2433 ret = _key_schedule(context, key);
2434 if(ret)
2435 return ret;
2437 switch (et->flags & F_KDF_MASK) {
2438 case F_RFC3961_KDF:
2439 ret = derive_key_rfc3961(context, et, key, constant, len);
2440 break;
2441 case F_SP800_108_HMAC_KDF:
2442 ret = derive_key_sp800_hmac(context, et, key, constant, len);
2443 break;
2444 default:
2445 ret = KRB5_CRYPTO_INTERNAL;
2446 krb5_set_error_message(context, ret,
2447 N_("derive_key() called with unknown keytype (%u)", ""),
2448 et->keytype->type);
2449 break;
2452 if (key->schedule) {
2453 free_key_schedule(context, key, et);
2454 key->schedule = NULL;
2457 return ret;
2460 static struct _krb5_key_data *
2461 _new_derived_key(krb5_crypto crypto, unsigned usage)
2463 struct _krb5_key_usage *d = crypto->key_usage;
2464 d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
2465 if(d == NULL)
2466 return NULL;
2467 crypto->key_usage = d;
2468 d += crypto->num_key_usage++;
2469 memset(d, 0, sizeof(*d));
2470 d->usage = usage;
2471 return &d->key;
2474 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2475 krb5_derive_key(krb5_context context,
2476 const krb5_keyblock *key,
2477 krb5_enctype etype,
2478 const void *constant,
2479 size_t constant_len,
2480 krb5_keyblock **derived_key)
2482 krb5_error_code ret;
2483 struct _krb5_encryption_type *et;
2484 struct _krb5_key_data d;
2486 *derived_key = NULL;
2488 et = _krb5_find_enctype (etype);
2489 if (et == NULL) {
2490 return unsupported_enctype (context, etype);
2493 ret = krb5_copy_keyblock(context, key, &d.key);
2494 if (ret)
2495 return ret;
2497 d.schedule = NULL;
2498 ret = _krb5_derive_key(context, et, &d, constant, constant_len);
2499 if (ret == 0)
2500 ret = krb5_copy_keyblock(context, d.key, derived_key);
2501 _krb5_free_key_data(context, &d, et);
2502 return ret;
2505 static krb5_error_code
2506 _get_derived_key(krb5_context context,
2507 krb5_crypto crypto,
2508 unsigned usage,
2509 struct _krb5_key_data **key)
2511 int i;
2512 struct _krb5_key_data *d;
2513 unsigned char constant[5];
2515 *key = NULL;
2516 for(i = 0; i < crypto->num_key_usage; i++)
2517 if(crypto->key_usage[i].usage == usage) {
2518 *key = &crypto->key_usage[i].key;
2519 return 0;
2521 d = _new_derived_key(crypto, usage);
2522 if (d == NULL)
2523 return krb5_enomem(context);
2524 *key = d;
2525 krb5_copy_keyblock(context, crypto->key.key, &d->key);
2526 _krb5_put_int(constant, usage, sizeof(constant));
2527 return _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2531 * Create a crypto context used for all encryption and signature
2532 * operation. The encryption type to use is taken from the key, but
2533 * can be overridden with the enctype parameter. This can be useful
2534 * for encryptions types which is compatiable (DES for example).
2536 * To free the crypto context, use krb5_crypto_destroy().
2538 * @param context Kerberos context
2539 * @param key the key block information with all key data
2540 * @param etype the encryption type
2541 * @param crypto the resulting crypto context
2543 * @return Return an error code or 0.
2545 * @ingroup krb5_crypto
2548 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2549 krb5_crypto_init(krb5_context context,
2550 const krb5_keyblock *key,
2551 krb5_enctype etype,
2552 krb5_crypto *crypto)
2554 krb5_error_code ret;
2555 ALLOC(*crypto, 1);
2556 if (*crypto == NULL)
2557 return krb5_enomem(context);
2558 if(etype == ETYPE_NULL)
2559 etype = key->keytype;
2560 (*crypto)->et = _krb5_find_enctype(etype);
2561 if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2562 free(*crypto);
2563 *crypto = NULL;
2564 return unsupported_enctype(context, etype);
2566 if((*crypto)->et->keytype->size != key->keyvalue.length) {
2567 free(*crypto);
2568 *crypto = NULL;
2569 krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2570 "encryption key has bad length");
2571 return KRB5_BAD_KEYSIZE;
2573 ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2574 if(ret) {
2575 free(*crypto);
2576 *crypto = NULL;
2577 return ret;
2579 (*crypto)->key.schedule = NULL;
2580 (*crypto)->num_key_usage = 0;
2581 (*crypto)->key_usage = NULL;
2582 (*crypto)->flags = 0;
2583 return 0;
2586 static void
2587 free_key_schedule(krb5_context context,
2588 struct _krb5_key_data *key,
2589 struct _krb5_encryption_type *et)
2591 if (et->keytype->cleanup)
2592 (*et->keytype->cleanup)(context, key);
2593 memset(key->schedule->data, 0, key->schedule->length);
2594 krb5_free_data(context, key->schedule);
2597 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2598 _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2599 struct _krb5_encryption_type *et)
2601 krb5_free_keyblock(context, key->key);
2602 if(key->schedule) {
2603 free_key_schedule(context, key, et);
2604 key->schedule = NULL;
2608 static void
2609 free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2610 struct _krb5_encryption_type *et)
2612 _krb5_free_key_data(context, &ku->key, et);
2616 * Free a crypto context created by krb5_crypto_init().
2618 * @param context Kerberos context
2619 * @param crypto crypto context to free
2621 * @return Return an error code or 0.
2623 * @ingroup krb5_crypto
2626 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2627 krb5_crypto_destroy(krb5_context context,
2628 krb5_crypto crypto)
2630 int i;
2632 for(i = 0; i < crypto->num_key_usage; i++)
2633 free_key_usage(context, &crypto->key_usage[i], crypto->et);
2634 free(crypto->key_usage);
2635 _krb5_free_key_data(context, &crypto->key, crypto->et);
2637 if (crypto->mdctx)
2638 EVP_MD_CTX_destroy(crypto->mdctx);
2640 if (crypto->hmacctx)
2641 HMAC_CTX_free(crypto->hmacctx);
2643 free (crypto);
2644 return 0;
2648 * Return the blocksize used algorithm referenced by the crypto context
2650 * @param context Kerberos context
2651 * @param crypto crypto context to query
2652 * @param blocksize the resulting blocksize
2654 * @return Return an error code or 0.
2656 * @ingroup krb5_crypto
2659 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2660 krb5_crypto_getblocksize(krb5_context context,
2661 krb5_crypto crypto,
2662 size_t *blocksize)
2664 *blocksize = crypto->et->blocksize;
2665 return 0;
2669 * Return the encryption type used by the crypto context
2671 * @param context Kerberos context
2672 * @param crypto crypto context to query
2673 * @param enctype the resulting encryption type
2675 * @return Return an error code or 0.
2677 * @ingroup krb5_crypto
2680 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2681 krb5_crypto_getenctype(krb5_context context,
2682 krb5_crypto crypto,
2683 krb5_enctype *enctype)
2685 *enctype = crypto->et->type;
2686 return 0;
2690 * Return the padding size used by the crypto context
2692 * @param context Kerberos context
2693 * @param crypto crypto context to query
2694 * @param padsize the return padding size
2696 * @return Return an error code or 0.
2698 * @ingroup krb5_crypto
2701 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2702 krb5_crypto_getpadsize(krb5_context context,
2703 krb5_crypto crypto,
2704 size_t *padsize)
2706 *padsize = crypto->et->padsize;
2707 return 0;
2711 * Return the confounder size used by the crypto context
2713 * @param context Kerberos context
2714 * @param crypto crypto context to query
2715 * @param confoundersize the returned confounder size
2717 * @return Return an error code or 0.
2719 * @ingroup krb5_crypto
2722 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2723 krb5_crypto_getconfoundersize(krb5_context context,
2724 krb5_crypto crypto,
2725 size_t *confoundersize)
2727 *confoundersize = crypto->et->confoundersize;
2728 return 0;
2733 * Disable encryption type
2735 * @param context Kerberos 5 context
2736 * @param enctype encryption type to disable
2738 * @return Return an error code or 0.
2740 * @ingroup krb5_crypto
2743 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2744 krb5_enctype_disable(krb5_context context,
2745 krb5_enctype enctype)
2747 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2748 if(et == NULL) {
2749 if (context)
2750 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2751 N_("encryption type %d not supported", ""),
2752 enctype);
2753 return KRB5_PROG_ETYPE_NOSUPP;
2755 et->flags |= F_DISABLED;
2756 return 0;
2760 * Enable encryption type
2762 * @param context Kerberos 5 context
2763 * @param enctype encryption type to enable
2765 * @return Return an error code or 0.
2767 * @ingroup krb5_crypto
2770 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2771 krb5_enctype_enable(krb5_context context,
2772 krb5_enctype enctype)
2774 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2775 if(et == NULL) {
2776 if (context)
2777 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2778 N_("encryption type %d not supported", ""),
2779 enctype);
2780 return KRB5_PROG_ETYPE_NOSUPP;
2782 et->flags &= ~F_DISABLED;
2783 return 0;
2787 * Enable or disable all weak encryption types
2789 * @param context Kerberos 5 context
2790 * @param enable true to enable, false to disable
2792 * @return Return an error code or 0.
2794 * @ingroup krb5_crypto
2797 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2798 krb5_allow_weak_crypto(krb5_context context,
2799 krb5_boolean enable)
2801 int i;
2803 for(i = 0; i < _krb5_num_etypes; i++)
2804 if(_krb5_etypes[i]->flags & F_WEAK) {
2805 if(enable)
2806 _krb5_etypes[i]->flags &= ~F_DISABLED;
2807 else
2808 _krb5_etypes[i]->flags |= F_DISABLED;
2810 return 0;
2814 * Returns is the encryption is strong or weak
2816 * @param context Kerberos 5 context
2817 * @param enctype encryption type to probe
2819 * @return Returns true if encryption type is weak or is not supported.
2821 * @ingroup krb5_crypto
2824 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2825 krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype)
2827 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2828 if(et == NULL || (et->flags & F_WEAK))
2829 return TRUE;
2830 return FALSE;
2834 * Returns whether the encryption type is new or old
2836 * @param context Kerberos 5 context
2837 * @param enctype encryption type to probe
2839 * @return Returns true if encryption type is old or is not supported.
2841 * @ingroup krb5_crypto
2844 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2845 krb5_is_enctype_old(krb5_context context, krb5_enctype enctype)
2847 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2848 if (!et || (et->flags & F_OLD))
2849 return TRUE;
2850 return FALSE;
2854 * Returns whether the encryption type should use randomly generated salts
2856 * @param context Kerberos 5 context
2857 * @param enctype encryption type to probe
2859 * @return Returns true if generated salts should have random component
2861 * @ingroup krb5_crypto
2863 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2864 _krb5_enctype_requires_random_salt(krb5_context context,
2865 krb5_enctype enctype)
2867 struct _krb5_encryption_type *et;
2869 et = _krb5_find_enctype (enctype);
2871 return et && (et->flags & F_SP800_108_HMAC_KDF);
2874 static size_t
2875 wrapped_length (krb5_context context,
2876 krb5_crypto crypto,
2877 size_t data_len)
2879 struct _krb5_encryption_type *et = crypto->et;
2880 size_t padsize = et->padsize;
2881 size_t checksumsize = CHECKSUMSIZE(et->checksum);
2882 size_t res;
2884 res = et->confoundersize + checksumsize + data_len;
2885 res = (res + padsize - 1) / padsize * padsize;
2886 return res;
2889 static size_t
2890 wrapped_length_dervied (krb5_context context,
2891 krb5_crypto crypto,
2892 size_t data_len)
2894 struct _krb5_encryption_type *et = crypto->et;
2895 size_t padsize = et->padsize;
2896 size_t res;
2898 res = et->confoundersize + data_len;
2899 res = (res + padsize - 1) / padsize * padsize;
2900 if (et->keyed_checksum)
2901 res += et->keyed_checksum->checksumsize;
2902 else
2903 res += et->checksum->checksumsize;
2904 return res;
2908 * Return the size of an encrypted packet of length `data_len'
2911 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2912 krb5_get_wrapped_length (krb5_context context,
2913 krb5_crypto crypto,
2914 size_t data_len)
2916 if (derived_crypto (context, crypto))
2917 return wrapped_length_dervied (context, crypto, data_len);
2918 else
2919 return wrapped_length (context, crypto, data_len);
2923 * Return the size of an encrypted packet of length `data_len'
2926 static size_t
2927 crypto_overhead (krb5_context context,
2928 krb5_crypto crypto)
2930 struct _krb5_encryption_type *et = crypto->et;
2931 size_t res;
2933 res = CHECKSUMSIZE(et->checksum);
2934 res += et->confoundersize;
2935 if (et->padsize > 1)
2936 res += et->padsize;
2937 return res;
2940 static size_t
2941 crypto_overhead_dervied (krb5_context context,
2942 krb5_crypto crypto)
2944 struct _krb5_encryption_type *et = crypto->et;
2945 size_t res;
2947 if (et->keyed_checksum)
2948 res = CHECKSUMSIZE(et->keyed_checksum);
2949 else
2950 res = CHECKSUMSIZE(et->checksum);
2951 res += et->confoundersize;
2952 if (et->padsize > 1)
2953 res += et->padsize;
2954 return res;
2957 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2958 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2960 if (derived_crypto (context, crypto))
2961 return crypto_overhead_dervied (context, crypto);
2962 else
2963 return crypto_overhead (context, crypto);
2967 * Converts the random bytestring to a protocol key according to
2968 * Kerberos crypto frame work. It may be assumed that all the bits of
2969 * the input string are equally random, even though the entropy
2970 * present in the random source may be limited.
2972 * @param context Kerberos 5 context
2973 * @param type the enctype resulting key will be of
2974 * @param data input random data to convert to a key
2975 * @param size size of input random data, at least krb5_enctype_keysize() long
2976 * @param key key, output key, free with krb5_free_keyblock_contents()
2978 * @return Return an error code or 0.
2980 * @ingroup krb5_crypto
2983 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2984 krb5_random_to_key(krb5_context context,
2985 krb5_enctype type,
2986 const void *data,
2987 size_t size,
2988 krb5_keyblock *key)
2990 krb5_error_code ret;
2991 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2992 if(et == NULL) {
2993 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2994 N_("encryption type %d not supported", ""),
2995 type);
2996 return KRB5_PROG_ETYPE_NOSUPP;
2998 if ((et->keytype->bits + 7) / 8 > size) {
2999 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3000 N_("encryption key %s needs %d bytes "
3001 "of random to make an encryption key "
3002 "out of it", ""),
3003 et->name, (int)et->keytype->size);
3004 return KRB5_PROG_ETYPE_NOSUPP;
3006 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
3007 if(ret)
3008 return ret;
3009 key->keytype = type;
3010 if (et->keytype->random_to_key)
3011 (*et->keytype->random_to_key)(context, key, data, size);
3012 else
3013 memcpy(key->keyvalue.data, data, et->keytype->size);
3015 return 0;
3020 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3021 krb5_crypto_prf_length(krb5_context context,
3022 krb5_enctype type,
3023 size_t *length)
3025 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
3027 if(et == NULL || et->prf_length == 0) {
3028 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3029 N_("encryption type %d not supported", ""),
3030 type);
3031 return KRB5_PROG_ETYPE_NOSUPP;
3034 *length = et->prf_length;
3035 return 0;
3038 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3039 krb5_crypto_prf(krb5_context context,
3040 const krb5_crypto crypto,
3041 const krb5_data *input,
3042 krb5_data *output)
3044 struct _krb5_encryption_type *et = crypto->et;
3046 krb5_data_zero(output);
3048 if(et->prf == NULL) {
3049 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3050 "kerberos prf for %s not supported",
3051 et->name);
3052 return KRB5_PROG_ETYPE_NOSUPP;
3055 return (*et->prf)(context, crypto, input, output);
3058 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3059 krb5_crypto_prfplus(krb5_context context,
3060 const krb5_crypto crypto,
3061 const krb5_data *input,
3062 size_t length,
3063 krb5_data *output)
3065 krb5_error_code ret;
3066 krb5_data input2;
3067 unsigned char i = 1;
3068 unsigned char *p;
3070 krb5_data_zero(&input2);
3071 krb5_data_zero(output);
3073 krb5_clear_error_message(context);
3075 ret = krb5_data_alloc(output, length);
3076 if (ret) goto out;
3077 ret = krb5_data_alloc(&input2, input->length + 1);
3078 if (ret) goto out;
3080 krb5_clear_error_message(context);
3082 memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
3084 p = output->data;
3086 while (length) {
3087 krb5_data block;
3089 ((unsigned char *)input2.data)[0] = i++;
3091 ret = krb5_crypto_prf(context, crypto, &input2, &block);
3092 if (ret)
3093 goto out;
3095 if (block.length < length) {
3096 memcpy(p, block.data, block.length);
3097 length -= block.length;
3098 } else {
3099 memcpy(p, block.data, length);
3100 length = 0;
3102 p += block.length;
3103 krb5_data_free(&block);
3106 out:
3107 krb5_data_free(&input2);
3108 if (ret)
3109 krb5_data_free(output);
3110 return ret;
3114 * The FX-CF2 key derivation function, used in FAST and preauth framework.
3116 * @param context Kerberos 5 context
3117 * @param crypto1 first key to combine
3118 * @param crypto2 second key to combine
3119 * @param pepper1 factor to combine with first key to garante uniqueness
3120 * @param pepper2 factor to combine with second key to garante uniqueness
3121 * @param enctype the encryption type of the resulting key
3122 * @param res allocated key, free with krb5_free_keyblock_contents()
3124 * @return Return an error code or 0.
3126 * @ingroup krb5_crypto
3129 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3130 krb5_crypto_fx_cf2(krb5_context context,
3131 const krb5_crypto crypto1,
3132 const krb5_crypto crypto2,
3133 krb5_data *pepper1,
3134 krb5_data *pepper2,
3135 krb5_enctype enctype,
3136 krb5_keyblock *res)
3138 krb5_error_code ret;
3139 krb5_data os1, os2;
3140 size_t i, keysize;
3142 memset(res, 0, sizeof(*res));
3143 krb5_data_zero(&os1);
3144 krb5_data_zero(&os2);
3146 ret = krb5_enctype_keybits(context, enctype, &keysize);
3147 if (ret)
3148 return ret;
3149 keysize = (keysize + 7) / 8;
3151 ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
3152 if (ret)
3153 goto out;
3154 ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
3155 if (ret)
3156 goto out;
3158 res->keytype = enctype;
3160 unsigned char *p1 = os1.data, *p2 = os2.data;
3161 for (i = 0; i < keysize; i++)
3162 p1[i] ^= p2[i];
3164 ret = krb5_random_to_key(context, enctype, os1.data, keysize, res);
3165 out:
3166 krb5_data_free(&os1);
3167 krb5_data_free(&os2);
3169 return ret;
3172 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
3173 _krb5_crypto_set_flags(krb5_context context,
3174 krb5_crypto crypto,
3175 krb5_flags flags)
3177 crypto->flags |= flags;
3180 #ifndef HEIMDAL_SMALLER
3183 * Deprecated: keytypes doesn't exists, they are really enctypes.
3185 * @ingroup krb5_deprecated
3188 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3189 krb5_keytype_to_enctypes (krb5_context context,
3190 krb5_keytype keytype,
3191 unsigned *len,
3192 krb5_enctype **val)
3193 KRB5_DEPRECATED_FUNCTION("Use X instead")
3195 int i;
3196 unsigned n = 0;
3197 krb5_enctype *ret;
3199 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3200 if (_krb5_etypes[i]->keytype->type == keytype
3201 && !(_krb5_etypes[i]->flags & F_PSEUDO)
3202 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3203 ++n;
3205 if (n == 0) {
3206 krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
3207 "Keytype have no mapping");
3208 return KRB5_PROG_KEYTYPE_NOSUPP;
3211 ret = malloc(n * sizeof(*ret));
3212 if (ret == NULL && n != 0)
3213 return krb5_enomem(context);
3214 n = 0;
3215 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3216 if (_krb5_etypes[i]->keytype->type == keytype
3217 && !(_krb5_etypes[i]->flags & F_PSEUDO)
3218 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3219 ret[n++] = _krb5_etypes[i]->type;
3221 *len = n;
3222 *val = ret;
3223 return 0;
3227 * Deprecated: keytypes doesn't exists, they are really enctypes.
3229 * @ingroup krb5_deprecated
3232 /* if two enctypes have compatible keys */
3233 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
3234 krb5_enctypes_compatible_keys(krb5_context context,
3235 krb5_enctype etype1,
3236 krb5_enctype etype2)
3237 KRB5_DEPRECATED_FUNCTION("Use X instead")
3239 struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
3240 struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
3241 return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
3244 #endif /* HEIMDAL_SMALLER */