libtommath: Fix possible integer overflow CVE-2023-36328
[heimdal.git] / lib / krb5 / crypto.c
blobaf86f7c457534d30251fac64910c8d7754c476c0
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 *);
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_INAPP_CKSUM,
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 = (krb5_keytype)e->keytype->type;
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 + confounder", ""));
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->data = p;
1279 result->length = l;
1280 return 0;
1283 static krb5_error_code
1284 decrypt_internal_enc_then_cksum(krb5_context context,
1285 krb5_crypto crypto,
1286 unsigned usage,
1287 void *data,
1288 size_t len,
1289 krb5_data *result,
1290 void *ivec)
1292 size_t checksum_sz;
1293 Checksum cksum;
1294 unsigned char *p;
1295 krb5_error_code ret;
1296 struct _krb5_key_data *dkey;
1297 struct _krb5_encryption_type *et = crypto->et;
1298 unsigned long l;
1300 checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1301 if (len < checksum_sz + et->confoundersize) {
1302 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1303 N_("Encrypted data shorter then "
1304 "checksum + confounder", ""));
1305 return KRB5_BAD_MSIZE;
1308 if (((len - checksum_sz) % et->padsize) != 0) {
1309 krb5_clear_error_message(context);
1310 return KRB5_BAD_MSIZE;
1313 len -= checksum_sz;
1315 p = malloc(et->blocksize + len);
1316 if (p == NULL)
1317 return krb5_enomem(context);
1319 if (ivec)
1320 memcpy(p, ivec, et->blocksize);
1321 else
1322 memset(p, 0, et->blocksize);
1323 memcpy(&p[et->blocksize], data, len);
1325 cksum.checksum.data = (unsigned char *)data + len;
1326 cksum.checksum.length = checksum_sz;
1327 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1329 ret = verify_checksum(context,
1330 crypto,
1331 INTEGRITY_USAGE(usage),
1333 et->blocksize + len,
1335 &cksum);
1336 if(ret) {
1337 free(p);
1338 return ret;
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;
1351 ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec);
1352 if (ret) {
1353 free(p);
1354 return ret;
1357 l = len - et->confoundersize;
1358 memmove(p, p + et->blocksize + et->confoundersize, l);
1359 result->data = p;
1360 result->length = l;
1361 return 0;
1364 static krb5_error_code
1365 decrypt_internal(krb5_context context,
1366 krb5_crypto crypto,
1367 void *data,
1368 size_t len,
1369 krb5_data *result,
1370 void *ivec)
1372 krb5_error_code ret;
1373 unsigned char *p;
1374 Checksum cksum;
1375 size_t checksum_sz, l;
1376 struct _krb5_encryption_type *et = crypto->et;
1378 if ((len % et->padsize) != 0) {
1379 krb5_clear_error_message(context);
1380 return KRB5_BAD_MSIZE;
1382 checksum_sz = CHECKSUMSIZE(et->checksum);
1383 if (len < checksum_sz + et->confoundersize) {
1384 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1385 N_("Encrypted data shorter then "
1386 "checksum + confounder", ""));
1387 return KRB5_BAD_MSIZE;
1390 p = malloc(len);
1391 if (len != 0 && p == NULL)
1392 return krb5_enomem(context);
1393 memcpy(p, data, len);
1395 ret = _key_schedule(context, &crypto->key);
1396 if(ret) {
1397 free(p);
1398 return ret;
1400 ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1401 if (ret) {
1402 free(p);
1403 return ret;
1405 ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1406 if(ret) {
1407 free(p);
1408 return ret;
1410 memset(p + et->confoundersize, 0, checksum_sz);
1411 cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1412 ret = verify_checksum(context, NULL, 0, p, len,
1413 KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM, &cksum);
1414 free_Checksum(&cksum);
1415 if(ret) {
1416 free(p);
1417 return ret;
1419 l = len - et->confoundersize - checksum_sz;
1420 memmove(p, p + et->confoundersize + checksum_sz, l);
1421 result->data = p;
1422 result->length = l;
1423 return 0;
1426 static krb5_error_code
1427 decrypt_internal_special(krb5_context context,
1428 krb5_crypto crypto,
1429 int usage,
1430 void *data,
1431 size_t len,
1432 krb5_data *result,
1433 void *ivec)
1435 struct _krb5_encryption_type *et = crypto->et;
1436 size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1437 size_t sz = len - cksum_sz - et->confoundersize;
1438 unsigned char *p;
1439 krb5_error_code ret;
1441 if ((len % et->padsize) != 0) {
1442 krb5_clear_error_message(context);
1443 return KRB5_BAD_MSIZE;
1445 if (len < cksum_sz + et->confoundersize) {
1446 krb5_set_error_message(context, KRB5_BAD_MSIZE,
1447 N_("Encrypted data shorter then "
1448 "checksum + confounder", ""));
1449 return KRB5_BAD_MSIZE;
1452 p = malloc (len);
1453 if (p == NULL)
1454 return krb5_enomem(context);
1455 memcpy(p, data, len);
1457 ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1458 if (ret) {
1459 free(p);
1460 return ret;
1463 memmove (p, p + cksum_sz + et->confoundersize, sz);
1464 result->data = p;
1465 result->length = sz;
1466 return 0;
1469 static krb5_crypto_iov *
1470 iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type)
1472 size_t i;
1473 for (i = 0; i < num_data; i++)
1474 if (data[i].flags == type)
1475 return &data[i];
1476 return NULL;
1479 static size_t
1480 iov_enc_data_len(krb5_crypto_iov *data, int num_data)
1482 size_t i, len;
1484 for (len = 0, i = 0; i < num_data; i++) {
1485 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1486 continue;
1487 len += data[i].data.length;
1490 return len;
1493 static size_t
1494 iov_sign_data_len(krb5_crypto_iov *data, int num_data)
1496 size_t i, len;
1498 for (len = 0, i = 0; i < num_data; i++) {
1499 /* Can't use should_sign, because we must only count data, not
1500 * header/trailer */
1501 if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1502 data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
1503 len += data[i].data.length;
1506 return len;
1509 static krb5_error_code
1510 iov_coalesce(krb5_context context,
1511 krb5_data *prefix,
1512 krb5_crypto_iov *data,
1513 int num_data,
1514 krb5_boolean inc_sign_data,
1515 krb5_data *out)
1517 unsigned char *p, *q;
1518 krb5_crypto_iov *hiv, *piv;
1519 size_t len;
1520 unsigned int i;
1522 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1524 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1526 len = 0;
1527 if (prefix)
1528 len += prefix->length;
1529 len += hiv->data.length;
1530 if (inc_sign_data)
1531 len += iov_sign_data_len(data, num_data);
1532 else
1533 len += iov_enc_data_len(data, num_data);
1534 if (piv)
1535 len += piv->data.length;
1537 p = q = malloc(len);
1538 if (p == NULL)
1539 return krb5_enomem(context);
1541 if (prefix) {
1542 memcpy(q, prefix->data, prefix->length);
1543 q += prefix->length;
1545 memcpy(q, hiv->data.data, hiv->data.length);
1546 q += hiv->data.length;
1547 for (i = 0; i < num_data; i++) {
1548 if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1549 (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) {
1550 memcpy(q, data[i].data.data, data[i].data.length);
1551 q += data[i].data.length;
1554 if (piv)
1555 memset(q, 0, piv->data.length);
1557 out->length = len;
1558 out->data = p;
1560 return 0;
1563 static krb5_error_code
1564 iov_uncoalesce(krb5_context context,
1565 krb5_data *enc_data,
1566 krb5_crypto_iov *data,
1567 int num_data)
1569 unsigned char *q = enc_data->data;
1570 krb5_crypto_iov *hiv, *piv;
1571 unsigned int i;
1573 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1575 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1577 memcpy(hiv->data.data, q, hiv->data.length);
1578 q += hiv->data.length;
1580 for (i = 0; i < num_data; i++) {
1581 if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1582 continue;
1583 memcpy(data[i].data.data, q, data[i].data.length);
1584 q += data[i].data.length;
1586 if (piv)
1587 memcpy(piv->data.data, q, piv->data.length);
1589 return 0;
1592 static krb5_error_code
1593 iov_pad_validate(const struct _krb5_encryption_type *et,
1594 krb5_crypto_iov *data,
1595 int num_data,
1596 krb5_crypto_iov **ppiv)
1598 krb5_crypto_iov *piv;
1599 size_t sz, headersz, block_sz, pad_sz, len;
1601 len = iov_enc_data_len(data, num_data);
1603 headersz = et->confoundersize;
1605 sz = headersz + len;
1606 block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1608 pad_sz = block_sz - sz;
1610 piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1611 /* its ok to have no TYPE_PADDING if there is no padding */
1612 if (piv == NULL && pad_sz != 0)
1613 return KRB5_BAD_MSIZE;
1614 if (piv) {
1615 if (piv->data.length < pad_sz)
1616 return KRB5_BAD_MSIZE;
1617 piv->data.length = pad_sz;
1618 if (pad_sz)
1619 memset(piv->data.data, 0, pad_sz);
1620 else
1621 piv = NULL;
1624 *ppiv = piv;
1625 return 0;
1629 * Inline encrypt a kerberos message
1631 * @param context Kerberos context
1632 * @param crypto Kerberos crypto context
1633 * @param usage Key usage for this buffer
1634 * @param data array of buffers to process
1635 * @param num_data length of array
1636 * @param ivec initial cbc/cts vector
1638 * @return Return an error code or 0.
1639 * @ingroup krb5_crypto
1641 * Kerberos encrypted data look like this:
1643 * 1. KRB5_CRYPTO_TYPE_HEADER
1644 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1645 * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1646 * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1647 * commonly used headers and trailers.
1648 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1649 * 4. KRB5_CRYPTO_TYPE_TRAILER
1652 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1653 krb5_encrypt_iov_ivec(krb5_context context,
1654 krb5_crypto crypto,
1655 unsigned usage,
1656 krb5_crypto_iov *data,
1657 int num_data,
1658 void *ivec)
1660 size_t headersz, trailersz;
1661 Checksum cksum;
1662 krb5_data enc_data, sign_data;
1663 krb5_error_code ret;
1664 struct _krb5_key_data *dkey;
1665 const struct _krb5_encryption_type *et = crypto->et;
1666 krb5_crypto_iov *tiv, *piv, *hiv;
1668 if (num_data < 0) {
1669 krb5_clear_error_message(context);
1670 return KRB5_CRYPTO_INTERNAL;
1673 if(!derived_crypto(context, crypto)) {
1674 krb5_clear_error_message(context);
1675 return KRB5_CRYPTO_INTERNAL;
1678 krb5_data_zero(&enc_data);
1679 krb5_data_zero(&sign_data);
1681 headersz = et->confoundersize;
1682 trailersz = CHECKSUMSIZE(et->keyed_checksum);
1684 /* header */
1685 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1686 if (hiv == NULL || hiv->data.length != headersz)
1687 return KRB5_BAD_MSIZE;
1688 krb5_generate_random_block(hiv->data.data, hiv->data.length);
1690 /* padding */
1691 ret = iov_pad_validate(et, data, num_data, &piv);
1692 if(ret)
1693 goto cleanup;
1695 /* trailer */
1696 tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1697 if (tiv == NULL || tiv->data.length != trailersz) {
1698 ret = KRB5_BAD_MSIZE;
1699 goto cleanup;
1702 if (et->flags & F_ENC_THEN_CKSUM) {
1703 unsigned char old_ivec[EVP_MAX_IV_LENGTH];
1704 krb5_data ivec_data;
1706 heim_assert(et->blocksize <= sizeof(old_ivec),
1707 "blocksize too big for ivec buffer");
1709 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1710 if(ret)
1711 goto cleanup;
1713 ret = _key_schedule(context, dkey);
1714 if(ret)
1715 goto cleanup;
1717 if (ivec)
1718 memcpy(old_ivec, ivec, et->blocksize);
1719 else
1720 memset(old_ivec, 0, et->blocksize);
1722 if (et->encrypt_iov != NULL) {
1723 ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage,
1724 ivec);
1725 if (ret)
1726 goto cleanup;
1727 } else {
1728 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1729 if (ret)
1730 goto cleanup;
1732 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1733 1, usage, ivec);
1734 if (ret)
1735 goto cleanup;
1737 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1738 if (ret)
1739 goto cleanup;
1742 ivec_data.length = et->blocksize;
1743 ivec_data.data = old_ivec;
1745 ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1746 if(ret)
1747 goto cleanup;
1749 ret = create_checksum(context,
1750 et->keyed_checksum,
1751 crypto,
1752 INTEGRITY_USAGE(usage),
1753 sign_data.data,
1754 sign_data.length,
1756 &cksum);
1758 if(ret == 0 && cksum.checksum.length != trailersz) {
1759 free_Checksum (&cksum);
1760 krb5_clear_error_message (context);
1761 ret = KRB5_CRYPTO_INTERNAL;
1763 if (ret)
1764 goto cleanup;
1766 /* save cksum at end */
1767 memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1768 free_Checksum (&cksum);
1770 } else {
1771 cksum.checksum = tiv->data;
1772 ret = create_checksum_iov(context,
1773 et->keyed_checksum,
1774 crypto,
1775 INTEGRITY_USAGE(usage),
1776 data,
1777 num_data,
1779 &cksum);
1780 if (ret)
1781 goto cleanup;
1783 /* create_checksum may realloc the derived key space, so any keys
1784 * obtained before it was called may no longer be valid */
1785 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1786 if(ret)
1787 goto cleanup;
1789 ret = _key_schedule(context, dkey);
1790 if(ret)
1791 goto cleanup;
1793 if (et->encrypt_iov != NULL) {
1794 ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage,
1795 ivec);
1796 if (ret)
1797 goto cleanup;
1798 } else {
1799 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1800 if (ret)
1801 goto cleanup;
1803 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1804 1, usage, ivec);
1805 if (ret)
1806 goto cleanup;
1808 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1809 if (ret)
1810 goto cleanup;
1814 cleanup:
1815 if (enc_data.data) {
1816 memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1817 krb5_data_free(&enc_data);
1819 if (sign_data.data) {
1820 memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1821 krb5_data_free(&sign_data);
1823 return ret;
1827 * Inline decrypt a Kerberos message.
1829 * @param context Kerberos context
1830 * @param crypto Kerberos crypto context
1831 * @param usage Key usage for this buffer
1832 * @param data array of buffers to process
1833 * @param num_data length of array
1834 * @param ivec initial cbc/cts vector
1836 * @return Return an error code or 0.
1837 * @ingroup krb5_crypto
1839 * 1. KRB5_CRYPTO_TYPE_HEADER
1840 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1841 * any order, however the receiver have to aware of the
1842 * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1843 * protocol headers and trailers. The output data will be of same
1844 * size as the input data or shorter.
1847 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1848 krb5_decrypt_iov_ivec(krb5_context context,
1849 krb5_crypto crypto,
1850 unsigned usage,
1851 krb5_crypto_iov *data,
1852 unsigned int num_data,
1853 void *ivec)
1855 Checksum cksum;
1856 krb5_data enc_data, sign_data;
1857 krb5_error_code ret;
1858 struct _krb5_key_data *dkey;
1859 struct _krb5_encryption_type *et = crypto->et;
1860 krb5_crypto_iov *tiv, *hiv;
1862 if(!derived_crypto(context, crypto)) {
1863 krb5_clear_error_message(context);
1864 return KRB5_CRYPTO_INTERNAL;
1867 /* header */
1868 hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1869 if (hiv == NULL || hiv->data.length != et->confoundersize)
1870 return KRB5_BAD_MSIZE;
1872 /* trailer */
1873 tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1874 if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum))
1875 return KRB5_BAD_MSIZE;
1877 /* padding */
1878 if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) {
1879 krb5_clear_error_message(context);
1880 return KRB5_BAD_MSIZE;
1883 krb5_data_zero(&enc_data);
1884 krb5_data_zero(&sign_data);
1886 if (!(et->flags & F_ENC_THEN_CKSUM)) {
1887 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1888 if(ret)
1889 goto cleanup;
1891 ret = _key_schedule(context, dkey);
1892 if(ret)
1893 goto cleanup;
1895 if (et->encrypt_iov != NULL) {
1896 ret = (*et->encrypt_iov)(context, dkey, data, num_data,
1897 0, usage, ivec);
1898 if(ret)
1899 goto cleanup;
1900 } else {
1901 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1902 if(ret)
1903 goto cleanup;
1905 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1906 0, usage, ivec);
1907 if(ret)
1908 goto cleanup;
1910 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1911 if(ret)
1912 goto cleanup;
1915 cksum.checksum.data = tiv->data.data;
1916 cksum.checksum.length = tiv->data.length;
1917 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1919 ret = verify_checksum_iov(context, crypto, INTEGRITY_USAGE(usage),
1920 data, num_data, 0, &cksum);
1921 if(ret)
1922 goto cleanup;
1923 } else {
1924 krb5_data ivec_data;
1925 static const unsigned char zero_ivec[EVP_MAX_IV_LENGTH];
1927 heim_assert(et->blocksize <= sizeof(zero_ivec),
1928 "blocksize too big for ivec buffer");
1930 ivec_data.length = et->blocksize;
1931 ivec_data.data = ivec ? ivec : rk_UNCONST(zero_ivec);
1933 ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1934 if(ret)
1935 goto cleanup;
1937 cksum.checksum.data = tiv->data.data;
1938 cksum.checksum.length = tiv->data.length;
1939 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1941 ret = verify_checksum(context,
1942 crypto,
1943 INTEGRITY_USAGE(usage),
1944 sign_data.data,
1945 sign_data.length,
1947 &cksum);
1948 if(ret)
1949 goto cleanup;
1951 ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1952 if(ret)
1953 goto cleanup;
1955 ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1956 if(ret)
1957 goto cleanup;
1959 ret = _key_schedule(context, dkey);
1960 if(ret)
1961 goto cleanup;
1963 ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1964 0, usage, ivec);
1965 if(ret)
1966 goto cleanup;
1968 ret = iov_uncoalesce(context, &enc_data, data, num_data);
1969 if(ret)
1970 goto cleanup;
1973 cleanup:
1974 if (enc_data.data) {
1975 memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1976 krb5_data_free(&enc_data);
1978 if (sign_data.data) {
1979 memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1980 krb5_data_free(&sign_data);
1982 return ret;
1986 * Create a Kerberos message checksum.
1988 * @param context Kerberos context
1989 * @param crypto Kerberos crypto context
1990 * @param usage Key usage for this buffer
1991 * @param data array of buffers to process
1992 * @param num_data length of array
1993 * @param type output data
1995 * @return Return an error code or 0.
1996 * @ingroup krb5_crypto
1999 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2000 krb5_create_checksum_iov(krb5_context context,
2001 krb5_crypto crypto,
2002 unsigned usage,
2003 krb5_crypto_iov *data,
2004 unsigned int num_data,
2005 krb5_cksumtype *type)
2007 Checksum cksum;
2008 krb5_crypto_iov *civ;
2009 struct _krb5_checksum_type *ct;
2010 unsigned keyusage;
2011 krb5_error_code ret;
2013 civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
2014 if (civ == NULL)
2015 return KRB5_BAD_MSIZE;
2017 ct = crypto->et->keyed_checksum;
2018 if (ct == NULL)
2019 ct = crypto->et->checksum;
2021 if(ct == NULL) {
2022 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2023 N_("checksum type not found", ""));
2024 return KRB5_PROG_SUMTYPE_NOSUPP;
2027 if (arcfour_checksum_p(ct, crypto)) {
2028 keyusage = usage;
2029 _krb5_usage2arcfour(context, &keyusage);
2030 } else
2031 keyusage = CHECKSUM_USAGE(usage);
2033 if (ct->checksumsize > civ->data.length) {
2034 krb5_set_error_message(context, KRB5_BAD_MSIZE,
2035 N_("Checksum larger then input buffer", ""));
2036 return KRB5_BAD_MSIZE;
2039 cksum.checksum = civ->data;
2040 ret = create_checksum_iov(context, ct, crypto, keyusage,
2041 data, num_data, crypto_flags(crypto), &cksum);
2043 if (ret == 0 && type)
2044 *type = cksum.cksumtype;
2046 return ret;
2050 * Verify a Kerberos message checksum.
2052 * @param context Kerberos context
2053 * @param crypto Kerberos crypto context
2054 * @param usage Key usage for this buffer
2055 * @param data array of buffers to process
2056 * @param num_data length of array
2057 * @param type return checksum type if not NULL
2059 * @return Return an error code or 0.
2060 * @ingroup krb5_crypto
2063 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2064 krb5_verify_checksum_iov(krb5_context context,
2065 krb5_crypto crypto,
2066 unsigned usage,
2067 krb5_crypto_iov *data,
2068 unsigned int num_data,
2069 krb5_cksumtype *type)
2071 struct _krb5_encryption_type *et = crypto->et;
2072 struct _krb5_checksum_type *ct;
2073 Checksum cksum;
2074 krb5_crypto_iov *civ;
2075 krb5_error_code ret;
2076 unsigned keyusage;
2078 civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
2079 if (civ == NULL)
2080 return KRB5_BAD_MSIZE;
2082 cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
2083 cksum.checksum.length = civ->data.length;
2084 cksum.checksum.data = civ->data.data;
2086 ct = _krb5_find_checksum(cksum.cksumtype);
2087 if(ct == NULL) {
2088 krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
2089 N_("checksum type %d not supported", ""),
2090 cksum.cksumtype);
2091 return KRB5_PROG_SUMTYPE_NOSUPP;
2094 if (arcfour_checksum_p(ct, crypto)) {
2095 keyusage = usage;
2096 _krb5_usage2arcfour(context, &keyusage);
2097 } else
2098 keyusage = CHECKSUM_USAGE(usage);
2100 ret = verify_checksum_iov(context, crypto, keyusage, data, num_data,
2101 crypto_flags(crypto), &cksum);
2103 if (ret == 0 && type)
2104 *type = cksum.cksumtype;
2106 return ret;
2110 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2111 krb5_crypto_length(krb5_context context,
2112 krb5_crypto crypto,
2113 int type,
2114 size_t *len)
2116 if (!derived_crypto(context, crypto)) {
2117 krb5_set_error_message(context, EINVAL, "not a derived crypto");
2118 return EINVAL;
2121 switch(type) {
2122 case KRB5_CRYPTO_TYPE_EMPTY:
2123 *len = 0;
2124 return 0;
2125 case KRB5_CRYPTO_TYPE_HEADER:
2126 *len = crypto->et->blocksize;
2127 return 0;
2128 case KRB5_CRYPTO_TYPE_DATA:
2129 case KRB5_CRYPTO_TYPE_SIGN_ONLY:
2130 /* len must already been filled in */
2131 return 0;
2132 case KRB5_CRYPTO_TYPE_PADDING:
2133 if (crypto->et->padsize > 1)
2134 *len = crypto->et->padsize;
2135 else
2136 *len = 0;
2137 return 0;
2138 case KRB5_CRYPTO_TYPE_TRAILER:
2139 if (crypto->et->keyed_checksum)
2140 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
2141 else
2142 *len = 0;
2143 return 0;
2144 case KRB5_CRYPTO_TYPE_CHECKSUM:
2145 if (crypto->et->keyed_checksum)
2146 *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
2147 else
2148 *len = CHECKSUMSIZE(crypto->et->checksum);
2149 return 0;
2151 krb5_set_error_message(context, EINVAL,
2152 "%d not a supported type", type);
2153 return EINVAL;
2157 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2158 krb5_crypto_length_iov(krb5_context context,
2159 krb5_crypto crypto,
2160 krb5_crypto_iov *data,
2161 unsigned int num_data)
2163 krb5_error_code ret;
2164 size_t i;
2166 for (i = 0; i < num_data; i++) {
2167 ret = krb5_crypto_length(context, crypto,
2168 data[i].flags,
2169 &data[i].data.length);
2170 if (ret)
2171 return ret;
2173 return 0;
2177 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2178 krb5_encrypt_ivec(krb5_context context,
2179 krb5_crypto crypto,
2180 unsigned usage,
2181 const void *data,
2182 size_t len,
2183 krb5_data *result,
2184 void *ivec)
2186 krb5_error_code ret;
2188 switch (crypto->et->flags & F_CRYPTO_MASK) {
2189 case F_RFC3961_ENC:
2190 ret = encrypt_internal_derived(context, crypto, usage,
2191 data, len, result, ivec);
2192 break;
2193 case F_SPECIAL:
2194 ret = encrypt_internal_special (context, crypto, usage,
2195 data, len, result, ivec);
2196 break;
2197 case F_ENC_THEN_CKSUM:
2198 ret = encrypt_internal_enc_then_cksum(context, crypto, usage,
2199 data, len, result, ivec);
2200 break;
2201 default:
2202 ret = encrypt_internal(context, crypto, data, len, result, ivec);
2203 break;
2206 return ret;
2209 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2210 krb5_encrypt(krb5_context context,
2211 krb5_crypto crypto,
2212 unsigned usage,
2213 const void *data,
2214 size_t len,
2215 krb5_data *result)
2217 return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
2220 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2221 krb5_encrypt_EncryptedData(krb5_context context,
2222 krb5_crypto crypto,
2223 unsigned usage,
2224 void *data,
2225 size_t len,
2226 int kvno,
2227 EncryptedData *result)
2229 result->etype = CRYPTO_ETYPE(crypto);
2230 if(kvno){
2231 ALLOC(result->kvno, 1);
2232 *result->kvno = kvno;
2233 }else
2234 result->kvno = NULL;
2235 return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
2238 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2239 krb5_decrypt_ivec(krb5_context context,
2240 krb5_crypto crypto,
2241 unsigned usage,
2242 void *data,
2243 size_t len,
2244 krb5_data *result,
2245 void *ivec)
2247 krb5_error_code ret;
2249 switch (crypto->et->flags & F_CRYPTO_MASK) {
2250 case F_RFC3961_ENC:
2251 ret = decrypt_internal_derived(context, crypto, usage,
2252 data, len, result, ivec);
2253 break;
2254 case F_SPECIAL:
2255 ret = decrypt_internal_special(context, crypto, usage,
2256 data, len, result, ivec);
2257 break;
2258 case F_ENC_THEN_CKSUM:
2259 ret = decrypt_internal_enc_then_cksum(context, crypto, usage,
2260 data, len, result, ivec);
2261 break;
2262 default:
2263 ret = decrypt_internal(context, crypto, data, len, result, ivec);
2264 break;
2267 return ret;
2270 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2271 krb5_decrypt(krb5_context context,
2272 krb5_crypto crypto,
2273 unsigned usage,
2274 void *data,
2275 size_t len,
2276 krb5_data *result)
2278 return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
2279 NULL);
2282 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2283 krb5_decrypt_EncryptedData(krb5_context context,
2284 krb5_crypto crypto,
2285 unsigned usage,
2286 const EncryptedData *e,
2287 krb5_data *result)
2289 return krb5_decrypt(context, crypto, usage,
2290 e->cipher.data, e->cipher.length, result);
2293 /************************************************************
2295 ************************************************************/
2297 static krb5_error_code
2298 derive_key_rfc3961(krb5_context context,
2299 struct _krb5_encryption_type *et,
2300 struct _krb5_key_data *key,
2301 const void *constant,
2302 size_t len)
2305 unsigned char *k = NULL;
2306 unsigned int nblocks = 0, i;
2307 krb5_error_code ret = 0;
2308 struct _krb5_key_type *kt = et->keytype;
2310 if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
2311 nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
2312 k = malloc(nblocks * et->blocksize);
2313 if(k == NULL) {
2314 ret = krb5_enomem(context);
2315 goto out;
2317 ret = _krb5_n_fold(constant, len, k, et->blocksize);
2318 if (ret) {
2319 krb5_enomem(context);
2320 goto out;
2323 for(i = 0; i < nblocks; i++) {
2324 if(i > 0)
2325 memcpy(k + i * et->blocksize,
2326 k + (i - 1) * et->blocksize,
2327 et->blocksize);
2328 ret = (*et->encrypt)(context, key, k + i * et->blocksize,
2329 et->blocksize, 1, 0, NULL);
2330 if (ret) {
2331 krb5_set_error_message(context, ret, N_("encrypt failed", ""));
2332 goto out;
2335 } else {
2336 /* this case is probably broken, but won't be run anyway */
2337 void *c = malloc(len);
2338 size_t res_len = (kt->bits + 7) / 8;
2340 if(len != 0 && c == NULL) {
2341 ret = krb5_enomem(context);
2342 goto out;
2344 memcpy(c, constant, len);
2345 ret = (*et->encrypt)(context, key, c, len, 1, 0, NULL);
2346 if (ret) {
2347 free(c);
2348 krb5_set_error_message(context, ret, N_("encrypt failed", ""));
2349 goto out;
2351 k = malloc(res_len);
2352 if(res_len != 0 && k == NULL) {
2353 free(c);
2354 ret = krb5_enomem(context);
2355 goto out;
2357 ret = _krb5_n_fold(c, len, k, res_len);
2358 free(c);
2359 if (ret) {
2360 krb5_enomem(context);
2361 goto out;
2365 if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1)
2366 _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
2367 else
2368 memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
2370 out:
2371 if (k) {
2372 memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize);
2373 free(k);
2375 return ret;
2378 static krb5_error_code
2379 derive_key_sp800_hmac(krb5_context context,
2380 struct _krb5_encryption_type *et,
2381 struct _krb5_key_data *key,
2382 const void *constant,
2383 size_t len)
2385 krb5_error_code ret;
2386 struct _krb5_key_type *kt = et->keytype;
2387 krb5_data label;
2388 const EVP_MD *md = NULL;
2389 const unsigned char *c = constant;
2390 size_t key_len;
2391 krb5_data K1;
2393 ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md);
2394 if (ret)
2395 return ret;
2398 * PRF usage: not handled here (output cannot be longer)
2399 * Integrity usage: truncated hash (half length)
2400 * Encryption usage: base key length
2402 if (len == 5 && (c[4] == 0x99 || c[4] == 0x55))
2403 key_len = EVP_MD_size(md) / 2;
2404 else
2405 key_len = kt->size;
2407 ret = krb5_data_alloc(&K1, key_len);
2408 if (ret)
2409 return ret;
2411 label.data = (void *)constant;
2412 label.length = len;
2414 ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue,
2415 &label, NULL, md, &K1);
2416 if (ret == 0) {
2417 if (key->key->keyvalue.length > key_len)
2418 key->key->keyvalue.length = key_len;
2419 memcpy(key->key->keyvalue.data, K1.data, key_len);
2422 memset_s(K1.data, K1.length, 0, K1.length);
2423 krb5_data_free(&K1);
2425 return ret;
2428 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2429 _krb5_derive_key(krb5_context context,
2430 struct _krb5_encryption_type *et,
2431 struct _krb5_key_data *key,
2432 const void *constant,
2433 size_t len)
2435 krb5_error_code ret;
2437 ret = _key_schedule(context, key);
2438 if(ret)
2439 return ret;
2441 switch (et->flags & F_KDF_MASK) {
2442 case F_RFC3961_KDF:
2443 ret = derive_key_rfc3961(context, et, key, constant, len);
2444 break;
2445 case F_SP800_108_HMAC_KDF:
2446 ret = derive_key_sp800_hmac(context, et, key, constant, len);
2447 break;
2448 default:
2449 ret = KRB5_CRYPTO_INTERNAL;
2450 krb5_set_error_message(context, ret,
2451 N_("derive_key() called with unknown keytype (%u)", ""),
2452 et->keytype->type);
2453 break;
2456 if (key->schedule) {
2457 free_key_schedule(context, key, et);
2458 key->schedule = NULL;
2461 return ret;
2464 static struct _krb5_key_data *
2465 _new_derived_key(krb5_crypto crypto, unsigned usage)
2467 struct _krb5_key_usage *d = crypto->key_usage;
2468 d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
2469 if(d == NULL)
2470 return NULL;
2471 crypto->key_usage = d;
2472 d += crypto->num_key_usage++;
2473 memset(d, 0, sizeof(*d));
2474 d->usage = usage;
2475 return &d->key;
2478 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2479 krb5_derive_key(krb5_context context,
2480 const krb5_keyblock *key,
2481 krb5_enctype etype,
2482 const void *constant,
2483 size_t constant_len,
2484 krb5_keyblock **derived_key)
2486 krb5_error_code ret;
2487 struct _krb5_encryption_type *et;
2488 struct _krb5_key_data d;
2490 *derived_key = NULL;
2492 et = _krb5_find_enctype (etype);
2493 if (et == NULL) {
2494 return unsupported_enctype (context, etype);
2497 ret = krb5_copy_keyblock(context, key, &d.key);
2498 if (ret)
2499 return ret;
2501 d.schedule = NULL;
2502 ret = _krb5_derive_key(context, et, &d, constant, constant_len);
2503 if (ret == 0)
2504 ret = krb5_copy_keyblock(context, d.key, derived_key);
2505 _krb5_free_key_data(context, &d, et);
2506 return ret;
2509 static krb5_error_code
2510 _get_derived_key(krb5_context context,
2511 krb5_crypto crypto,
2512 unsigned usage,
2513 struct _krb5_key_data **key)
2515 int i;
2516 struct _krb5_key_data *d;
2517 unsigned char constant[5];
2519 *key = NULL;
2520 for(i = 0; i < crypto->num_key_usage; i++)
2521 if(crypto->key_usage[i].usage == usage) {
2522 *key = &crypto->key_usage[i].key;
2523 return 0;
2525 d = _new_derived_key(crypto, usage);
2526 if (d == NULL)
2527 return krb5_enomem(context);
2528 *key = d;
2529 krb5_copy_keyblock(context, crypto->key.key, &d->key);
2530 _krb5_put_int(constant, usage, sizeof(constant));
2531 return _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2535 * Create a crypto context used for all encryption and signature
2536 * operation. The encryption type to use is taken from the key, but
2537 * can be overridden with the enctype parameter. This can be useful
2538 * for encryptions types which is compatiable (DES for example).
2540 * To free the crypto context, use krb5_crypto_destroy().
2542 * @param context Kerberos context
2543 * @param key the key block information with all key data
2544 * @param etype the encryption type
2545 * @param crypto the resulting crypto context
2547 * @return Return an error code or 0.
2549 * @ingroup krb5_crypto
2552 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2553 krb5_crypto_init(krb5_context context,
2554 const krb5_keyblock *key,
2555 krb5_enctype etype,
2556 krb5_crypto *crypto)
2558 krb5_error_code ret;
2559 ALLOC(*crypto, 1);
2560 if (*crypto == NULL)
2561 return krb5_enomem(context);
2562 if(etype == ETYPE_NULL)
2563 etype = key->keytype;
2564 (*crypto)->et = _krb5_find_enctype(etype);
2565 if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2566 free(*crypto);
2567 *crypto = NULL;
2568 return unsupported_enctype(context, etype);
2570 if((*crypto)->et->keytype->size != key->keyvalue.length) {
2571 free(*crypto);
2572 *crypto = NULL;
2573 krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2574 "encryption key has bad length");
2575 return KRB5_BAD_KEYSIZE;
2577 ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2578 if(ret) {
2579 free(*crypto);
2580 *crypto = NULL;
2581 return ret;
2583 (*crypto)->key.schedule = NULL;
2584 (*crypto)->num_key_usage = 0;
2585 (*crypto)->key_usage = NULL;
2586 (*crypto)->flags = 0;
2587 return 0;
2590 static void
2591 free_key_schedule(krb5_context context,
2592 struct _krb5_key_data *key,
2593 struct _krb5_encryption_type *et)
2595 if (et->keytype->cleanup)
2596 (*et->keytype->cleanup)(context, key);
2597 memset(key->schedule->data, 0, key->schedule->length);
2598 krb5_free_data(context, key->schedule);
2601 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2602 _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2603 struct _krb5_encryption_type *et)
2605 krb5_free_keyblock(context, key->key);
2606 if(key->schedule) {
2607 free_key_schedule(context, key, et);
2608 key->schedule = NULL;
2612 static void
2613 free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2614 struct _krb5_encryption_type *et)
2616 _krb5_free_key_data(context, &ku->key, et);
2620 * Free a crypto context created by krb5_crypto_init().
2622 * @param context Kerberos context
2623 * @param crypto crypto context to free
2625 * @return Return an error code or 0.
2627 * @ingroup krb5_crypto
2630 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2631 krb5_crypto_destroy(krb5_context context,
2632 krb5_crypto crypto)
2634 int i;
2636 for(i = 0; i < crypto->num_key_usage; i++)
2637 free_key_usage(context, &crypto->key_usage[i], crypto->et);
2638 free(crypto->key_usage);
2639 _krb5_free_key_data(context, &crypto->key, crypto->et);
2641 if (crypto->mdctx)
2642 EVP_MD_CTX_destroy(crypto->mdctx);
2644 if (crypto->hmacctx)
2645 HMAC_CTX_free(crypto->hmacctx);
2647 free (crypto);
2648 return 0;
2652 * Return the blocksize used algorithm referenced by the crypto context
2654 * @param context Kerberos context
2655 * @param crypto crypto context to query
2656 * @param blocksize the resulting blocksize
2658 * @return Return an error code or 0.
2660 * @ingroup krb5_crypto
2663 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2664 krb5_crypto_getblocksize(krb5_context context,
2665 krb5_crypto crypto,
2666 size_t *blocksize)
2668 *blocksize = crypto->et->blocksize;
2669 return 0;
2673 * Return the encryption type used by the crypto context
2675 * @param context Kerberos context
2676 * @param crypto crypto context to query
2677 * @param enctype the resulting encryption type
2679 * @return Return an error code or 0.
2681 * @ingroup krb5_crypto
2684 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2685 krb5_crypto_getenctype(krb5_context context,
2686 krb5_crypto crypto,
2687 krb5_enctype *enctype)
2689 *enctype = crypto->et->type;
2690 return 0;
2694 * Return the padding size used by the crypto context
2696 * @param context Kerberos context
2697 * @param crypto crypto context to query
2698 * @param padsize the return padding size
2700 * @return Return an error code or 0.
2702 * @ingroup krb5_crypto
2705 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2706 krb5_crypto_getpadsize(krb5_context context,
2707 krb5_crypto crypto,
2708 size_t *padsize)
2710 *padsize = crypto->et->padsize;
2711 return 0;
2715 * Return the confounder size used by the crypto context
2717 * @param context Kerberos context
2718 * @param crypto crypto context to query
2719 * @param confoundersize the returned confounder size
2721 * @return Return an error code or 0.
2723 * @ingroup krb5_crypto
2726 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2727 krb5_crypto_getconfoundersize(krb5_context context,
2728 krb5_crypto crypto,
2729 size_t *confoundersize)
2731 *confoundersize = crypto->et->confoundersize;
2732 return 0;
2737 * Disable encryption type
2739 * @param context Kerberos 5 context
2740 * @param enctype encryption type to disable
2742 * @return Return an error code or 0.
2744 * @ingroup krb5_crypto
2747 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2748 krb5_enctype_disable(krb5_context context,
2749 krb5_enctype enctype)
2751 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2752 if(et == NULL) {
2753 if (context)
2754 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2755 N_("encryption type %d not supported", ""),
2756 enctype);
2757 return KRB5_PROG_ETYPE_NOSUPP;
2759 et->flags |= F_DISABLED;
2760 return 0;
2764 * Enable encryption type
2766 * @param context Kerberos 5 context
2767 * @param enctype encryption type to enable
2769 * @return Return an error code or 0.
2771 * @ingroup krb5_crypto
2774 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2775 krb5_enctype_enable(krb5_context context,
2776 krb5_enctype enctype)
2778 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2779 if(et == NULL) {
2780 if (context)
2781 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2782 N_("encryption type %d not supported", ""),
2783 enctype);
2784 return KRB5_PROG_ETYPE_NOSUPP;
2786 et->flags &= ~F_DISABLED;
2787 return 0;
2791 * Enable or disable all weak encryption types
2793 * @param context Kerberos 5 context
2794 * @param enable true to enable, false to disable
2796 * @return Return an error code or 0.
2798 * @ingroup krb5_crypto
2801 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2802 krb5_allow_weak_crypto(krb5_context context,
2803 krb5_boolean enable)
2805 int i;
2807 for(i = 0; i < _krb5_num_etypes; i++)
2808 if(_krb5_etypes[i]->flags & F_WEAK) {
2809 if(enable)
2810 _krb5_etypes[i]->flags &= ~F_DISABLED;
2811 else
2812 _krb5_etypes[i]->flags |= F_DISABLED;
2814 return 0;
2818 * Returns is the encryption is strong or weak
2820 * @param context Kerberos 5 context
2821 * @param enctype encryption type to probe
2823 * @return Returns true if encryption type is weak or is not supported.
2825 * @ingroup krb5_crypto
2828 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2829 krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype)
2831 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2832 if(et == NULL || (et->flags & F_WEAK))
2833 return TRUE;
2834 return FALSE;
2838 * Returns whether the encryption type is new or old
2840 * @param context Kerberos 5 context
2841 * @param enctype encryption type to probe
2843 * @return Returns true if encryption type is old or is not supported.
2845 * @ingroup krb5_crypto
2848 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2849 krb5_is_enctype_old(krb5_context context, krb5_enctype enctype)
2851 struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2852 if (!et || (et->flags & F_OLD))
2853 return TRUE;
2854 return FALSE;
2858 * Returns whether the encryption type should use randomly generated salts
2860 * @param context Kerberos 5 context
2861 * @param enctype encryption type to probe
2863 * @return Returns true if generated salts should have random component
2865 * @ingroup krb5_crypto
2867 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2868 _krb5_enctype_requires_random_salt(krb5_context context,
2869 krb5_enctype enctype)
2871 struct _krb5_encryption_type *et;
2873 et = _krb5_find_enctype (enctype);
2875 return et && (et->flags & F_SP800_108_HMAC_KDF);
2878 static size_t
2879 wrapped_length (krb5_context context,
2880 krb5_crypto crypto,
2881 size_t data_len)
2883 struct _krb5_encryption_type *et = crypto->et;
2884 size_t padsize = et->padsize;
2885 size_t checksumsize = CHECKSUMSIZE(et->checksum);
2886 size_t res;
2888 res = et->confoundersize + checksumsize + data_len;
2889 res = (res + padsize - 1) / padsize * padsize;
2890 return res;
2893 static size_t
2894 wrapped_length_dervied (krb5_context context,
2895 krb5_crypto crypto,
2896 size_t data_len)
2898 struct _krb5_encryption_type *et = crypto->et;
2899 size_t padsize = et->padsize;
2900 size_t res;
2902 res = et->confoundersize + data_len;
2903 res = (res + padsize - 1) / padsize * padsize;
2904 if (et->keyed_checksum)
2905 res += et->keyed_checksum->checksumsize;
2906 else
2907 res += et->checksum->checksumsize;
2908 return res;
2912 * Return the size of an encrypted packet of length `data_len'
2915 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2916 krb5_get_wrapped_length (krb5_context context,
2917 krb5_crypto crypto,
2918 size_t data_len)
2920 if (derived_crypto (context, crypto))
2921 return wrapped_length_dervied (context, crypto, data_len);
2922 else
2923 return wrapped_length (context, crypto, data_len);
2927 * Return the size of an encrypted packet of length `data_len'
2930 static size_t
2931 crypto_overhead (krb5_context context,
2932 krb5_crypto crypto)
2934 struct _krb5_encryption_type *et = crypto->et;
2935 size_t res;
2937 res = CHECKSUMSIZE(et->checksum);
2938 res += et->confoundersize;
2939 if (et->padsize > 1)
2940 res += et->padsize;
2941 return res;
2944 static size_t
2945 crypto_overhead_dervied (krb5_context context,
2946 krb5_crypto crypto)
2948 struct _krb5_encryption_type *et = crypto->et;
2949 size_t res;
2951 if (et->keyed_checksum)
2952 res = CHECKSUMSIZE(et->keyed_checksum);
2953 else
2954 res = CHECKSUMSIZE(et->checksum);
2955 res += et->confoundersize;
2956 if (et->padsize > 1)
2957 res += et->padsize;
2958 return res;
2961 KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2962 krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2964 if (derived_crypto (context, crypto))
2965 return crypto_overhead_dervied (context, crypto);
2966 else
2967 return crypto_overhead (context, crypto);
2971 * Converts the random bytestring to a protocol key according to
2972 * Kerberos crypto frame work. It may be assumed that all the bits of
2973 * the input string are equally random, even though the entropy
2974 * present in the random source may be limited.
2976 * @param context Kerberos 5 context
2977 * @param type the enctype resulting key will be of
2978 * @param data input random data to convert to a key
2979 * @param size size of input random data, at least krb5_enctype_keysize() long
2980 * @param key key, output key, free with krb5_free_keyblock_contents()
2982 * @return Return an error code or 0.
2984 * @ingroup krb5_crypto
2987 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2988 krb5_random_to_key(krb5_context context,
2989 krb5_enctype type,
2990 const void *data,
2991 size_t size,
2992 krb5_keyblock *key)
2994 krb5_error_code ret;
2995 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2996 if(et == NULL) {
2997 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2998 N_("encryption type %d not supported", ""),
2999 type);
3000 return KRB5_PROG_ETYPE_NOSUPP;
3002 if ((et->keytype->bits + 7) / 8 > size) {
3003 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3004 N_("encryption key %s needs %d bytes "
3005 "of random to make an encryption key "
3006 "out of it", ""),
3007 et->name, (int)et->keytype->size);
3008 return KRB5_PROG_ETYPE_NOSUPP;
3010 ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
3011 if(ret)
3012 return ret;
3013 key->keytype = type;
3014 if (et->keytype->random_to_key)
3015 (*et->keytype->random_to_key)(context, key, data, size);
3016 else
3017 memcpy(key->keyvalue.data, data, et->keytype->size);
3019 return 0;
3024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3025 krb5_crypto_prf_length(krb5_context context,
3026 krb5_enctype type,
3027 size_t *length)
3029 struct _krb5_encryption_type *et = _krb5_find_enctype(type);
3031 if(et == NULL || et->prf_length == 0) {
3032 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3033 N_("encryption type %d not supported", ""),
3034 type);
3035 return KRB5_PROG_ETYPE_NOSUPP;
3038 *length = et->prf_length;
3039 return 0;
3042 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3043 krb5_crypto_prf(krb5_context context,
3044 const krb5_crypto crypto,
3045 const krb5_data *input,
3046 krb5_data *output)
3048 struct _krb5_encryption_type *et = crypto->et;
3050 krb5_data_zero(output);
3052 if(et->prf == NULL) {
3053 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
3054 "kerberos prf for %s not supported",
3055 et->name);
3056 return KRB5_PROG_ETYPE_NOSUPP;
3059 return (*et->prf)(context, crypto, input, output);
3062 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3063 krb5_crypto_prfplus(krb5_context context,
3064 const krb5_crypto crypto,
3065 const krb5_data *input,
3066 size_t length,
3067 krb5_data *output)
3069 krb5_error_code ret;
3070 krb5_data input2;
3071 unsigned char i = 1;
3072 unsigned char *p;
3074 krb5_data_zero(&input2);
3075 krb5_data_zero(output);
3077 krb5_clear_error_message(context);
3079 ret = krb5_data_alloc(output, length);
3080 if (ret) goto out;
3081 ret = krb5_data_alloc(&input2, input->length + 1);
3082 if (ret) goto out;
3084 krb5_clear_error_message(context);
3086 memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
3088 p = output->data;
3090 while (length) {
3091 krb5_data block;
3093 ((unsigned char *)input2.data)[0] = i++;
3095 ret = krb5_crypto_prf(context, crypto, &input2, &block);
3096 if (ret)
3097 goto out;
3099 if (block.length < length) {
3100 memcpy(p, block.data, block.length);
3101 length -= block.length;
3102 } else {
3103 memcpy(p, block.data, length);
3104 length = 0;
3106 p += block.length;
3107 krb5_data_free(&block);
3110 out:
3111 krb5_data_free(&input2);
3112 if (ret)
3113 krb5_data_free(output);
3114 return ret;
3118 * The FX-CF2 key derivation function, used in FAST and preauth framework.
3120 * @param context Kerberos 5 context
3121 * @param crypto1 first key to combine
3122 * @param crypto2 second key to combine
3123 * @param pepper1 factor to combine with first key to guarantee uniqueness
3124 * @param pepper2 factor to combine with second key to guarantee uniqueness
3125 * @param enctype the encryption type of the resulting key
3126 * @param res allocated key, free with krb5_free_keyblock_contents()
3128 * @return Return an error code or 0.
3130 * @ingroup krb5_crypto
3133 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3134 krb5_crypto_fx_cf2(krb5_context context,
3135 const krb5_crypto crypto1,
3136 const krb5_crypto crypto2,
3137 krb5_data *pepper1,
3138 krb5_data *pepper2,
3139 krb5_enctype enctype,
3140 krb5_keyblock *res)
3142 krb5_error_code ret;
3143 krb5_data os1, os2;
3144 size_t i, keysize;
3146 memset(res, 0, sizeof(*res));
3147 krb5_data_zero(&os1);
3148 krb5_data_zero(&os2);
3150 ret = krb5_enctype_keybits(context, enctype, &keysize);
3151 if (ret)
3152 return ret;
3153 keysize = (keysize + 7) / 8;
3155 ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
3156 if (ret)
3157 goto out;
3158 ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
3159 if (ret)
3160 goto out;
3162 res->keytype = enctype;
3164 unsigned char *p1 = os1.data, *p2 = os2.data;
3165 for (i = 0; i < keysize; i++)
3166 p1[i] ^= p2[i];
3168 ret = krb5_random_to_key(context, enctype, os1.data, keysize, res);
3169 out:
3170 krb5_data_free(&os1);
3171 krb5_data_free(&os2);
3173 return ret;
3176 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
3177 _krb5_crypto_set_flags(krb5_context context,
3178 krb5_crypto crypto,
3179 krb5_flags flags)
3181 crypto->flags |= flags;
3184 #ifndef HEIMDAL_SMALLER
3187 * Deprecated: keytypes don't exist, they are really enctypes.
3189 * @ingroup krb5_deprecated
3192 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3193 krb5_keytype_to_enctypes (krb5_context context,
3194 krb5_keytype keytype,
3195 unsigned *len,
3196 krb5_enctype **val)
3197 KRB5_DEPRECATED_FUNCTION("Use X instead")
3199 int i;
3200 unsigned n = 0;
3201 krb5_enctype *ret;
3203 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3204 if (_krb5_etypes[i]->keytype->type == keytype
3205 && !(_krb5_etypes[i]->flags & F_PSEUDO)
3206 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3207 ++n;
3209 if (n == 0) {
3210 krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
3211 "Keytype has no mapping");
3212 return KRB5_PROG_KEYTYPE_NOSUPP;
3215 ret = malloc(n * sizeof(*ret));
3216 if (ret == NULL && n != 0)
3217 return krb5_enomem(context);
3218 n = 0;
3219 for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3220 if (_krb5_etypes[i]->keytype->type == keytype
3221 && !(_krb5_etypes[i]->flags & F_PSEUDO)
3222 && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3223 ret[n++] = _krb5_etypes[i]->type;
3225 *len = n;
3226 *val = ret;
3227 return 0;
3231 * Deprecated: keytypes don't exist, they are really enctypes.
3233 * @ingroup krb5_deprecated
3236 /* if two enctypes have compatible keys */
3237 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
3238 krb5_enctypes_compatible_keys(krb5_context context,
3239 krb5_enctype etype1,
3240 krb5_enctype etype2)
3241 KRB5_DEPRECATED_FUNCTION("Use X instead")
3243 struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
3244 struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
3245 return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
3248 #endif /* HEIMDAL_SMALLER */