2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "krb5_locl.h"
36 struct _krb5_key_usage
{
38 struct _krb5_key_data key
;
42 #ifndef HEIMDAL_SMALLER
43 #define DES3_OLD_ENCTYPE 1
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
)
67 ret
= krb5_enctype_to_string(context
, etype
, &name
);
71 krb5_set_error_message(context
, KRB5_PROG_ETYPE_NOSUPP
,
72 N_("Encryption type %s not supported", ""),
75 return KRB5_PROG_ETYPE_NOSUPP
;
82 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83 krb5_enctype_keysize(krb5_context context
,
87 struct _krb5_encryption_type
*et
= _krb5_find_enctype(type
);
89 return unsupported_enctype (context
, type
);
91 *keysize
= et
->keytype
->size
;
95 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
96 krb5_enctype_keybits(krb5_context context
,
100 struct _krb5_encryption_type
*et
= _krb5_find_enctype(type
);
102 return unsupported_enctype (context
, type
);
104 *keybits
= et
->keytype
->bits
;
108 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
109 krb5_generate_random_keyblock(krb5_context context
,
114 struct _krb5_encryption_type
*et
= _krb5_find_enctype(type
);
116 return unsupported_enctype (context
, type
);
118 ret
= krb5_data_alloc(&key
->keyvalue
, et
->keytype
->size
);
122 if(et
->keytype
->random_key
)
123 (*et
->keytype
->random_key
)(context
, key
);
125 krb5_generate_random_block(key
->keyvalue
.data
,
126 key
->keyvalue
.length
);
130 static krb5_error_code
131 _key_schedule(krb5_context context
,
132 struct _krb5_key_data
*key
)
135 struct _krb5_encryption_type
*et
;
136 struct _krb5_key_type
*kt
;
138 if (key
->schedule
!= NULL
)
141 et
= _krb5_find_enctype(key
->key
->keytype
);
144 return unsupported_enctype (context
,
150 if(kt
->schedule
== NULL
)
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
);
158 key
->schedule
= NULL
;
161 (*kt
->schedule
)(context
, kt
, key
);
165 /************************************************************
167 ************************************************************/
169 static krb5_error_code
170 EVP_unkeyed_checksum(krb5_context context
,
172 struct _krb5_key_data
*key
,
174 const struct krb5_crypto_iov
*iov
,
179 if (_krb5_evp_digest_iov(crypto
,
181 C
->checksum
.data
, NULL
,
183 krb5_abortx(context
, "unkeyed checksum failed");
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, \
195 const struct krb5_crypto_iov *iov, \
199 return EVP_unkeyed_checksum(context, crypto, key, \
201 C, EVP_sha##name()); \
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
,
213 struct _krb5_checksum_type
*cm
,
215 const struct krb5_crypto_iov
*iov
,
217 struct _krb5_key_data
*keyblock
,
220 unsigned char *ipad
, *opad
;
222 struct krb5_crypto_iov
*working
;
226 ipad
= malloc(cm
->blocksize
);
230 opad
= malloc(cm
->blocksize
+ cm
->checksumsize
);
236 working
= calloc(niov
+ 1, sizeof(struct krb5_crypto_iov
));
237 if (working
== NULL
) {
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
,
256 key
= result
->checksum
.data
;
257 key_len
= result
->checksum
.length
;
259 key
= keyblock
->key
->keyvalue
.data
;
260 key_len
= keyblock
->key
->keyvalue
.length
;
262 for(i
= 0; i
< key_len
; 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
);
283 memset(opad
, 0, cm
->blocksize
+ cm
->checksumsize
);
290 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
291 _krb5_internal_hmac(krb5_context context
,
293 struct _krb5_checksum_type
*cm
,
297 struct _krb5_key_data
*keyblock
,
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,
309 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
310 krb5_hmac(krb5_context context
,
311 krb5_cksumtype cktype
,
318 struct _krb5_checksum_type
*c
= _krb5_find_checksum(cktype
);
319 struct _krb5_key_data kd
;
324 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
325 N_("checksum type %d not supported", ""),
327 return KRB5_PROG_SUMTYPE_NOSUPP
;
333 ret
= _krb5_internal_hmac(context
, NULL
, c
, data
, len
, usage
, &kd
, result
);
336 krb5_free_data(context
, kd
.schedule
);
342 _krb5_SP_HMAC_SHA1_checksum(krb5_context context
,
344 struct _krb5_key_data
*key
,
346 const struct krb5_crypto_iov
*iov
,
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
,
359 heim_assert(result
->checksum
.length
<= hmaclen
,
360 "SHA1 checksum too short");
361 memcpy(result
->checksum
.data
, hmac
, result
->checksum
.length
);
367 _krb5_SP_HMAC_SHA1_verify(krb5_context context
,
369 struct _krb5_key_data
*key
,
371 const struct krb5_crypto_iov
*iov
,
376 unsigned char hmac
[EVP_MAX_MD_SIZE
];
377 unsigned int hmaclen
= sizeof(hmac
);
380 ret
= _krb5_evp_hmac_iov(context
, crypto
, key
, iov
, niov
, hmac
, &hmaclen
,
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
;
394 #define SHA_CHECKSUM(name, blocksize, outputsize) \
395 struct _krb5_checksum_type _krb5_checksum_sha##name = { \
396 CKSUMTYPE_SHA##name, \
401 SHA##name##_checksum, \
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
)
414 for(i
= 0; i
< _krb5_num_checksums
; i
++)
415 if(_krb5_checksum_types
[i
]->type
== type
)
416 return _krb5_checksum_types
[i
];
420 static krb5_error_code
421 get_checksum_key(krb5_context context
,
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", ""),
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
) {
452 *key
= _new_derived_key(crypto
, 0xff/* KRB5_KU_RFC1510_VARIANT */);
454 return krb5_enomem(context
);
455 ret
= krb5_copy_keyblock(context
, crypto
->key
.key
, &(*key
)->key
);
458 for(i
= 0; i
< (*key
)->key
->keyvalue
.length
; i
++)
459 ((unsigned char*)(*key
)->key
->keyvalue
.data
)[i
] ^= 0xF0;
464 ret
= _key_schedule(context
, *key
);
468 static krb5_error_code
469 create_checksum_iov(krb5_context context
,
470 struct _krb5_checksum_type
*ct
,
473 struct krb5_crypto_iov
*iov
,
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
);
489 } else if ((flags
& KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
) == 0) {
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
,
510 struct krb5_crypto_iov iov
[1];
512 ret
= krb5_data_alloc(&result
->checksum
, ct
->checksumsize
);
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
);
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 */
535 return KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
;
537 return crypto
->flags
;
540 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
541 krb5_create_checksum(krb5_context context
,
543 krb5_key_usage usage
,
549 struct _krb5_checksum_type
*ct
= NULL
;
552 /* type 0 -> pick from crypto */
554 ct
= _krb5_find_checksum(type
);
556 ct
= crypto
->et
->keyed_checksum
;
558 ct
= crypto
->et
->checksum
;
562 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
563 N_("checksum type %d not supported", ""),
565 return KRB5_PROG_SUMTYPE_NOSUPP
;
568 if (arcfour_checksum_p(ct
, crypto
)) {
570 _krb5_usage2arcfour(context
, &keyusage
);
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
,
581 unsigned usage
, /* not krb5_key_usage */
582 struct krb5_crypto_iov
*iov
,
588 struct _krb5_key_data
*dkey
;
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", ""),
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
);
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
;
624 * If checksum have a verify function, lets use that instead of
625 * calling ->checksum and then compare result.
629 ret
= (*ct
->verify
)(context
, crypto
, dkey
, usage
, iov
, niov
, cksum
);
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)");
638 ret
= krb5_data_alloc (&c
.checksum
, ct
->checksumsize
);
642 ret
= (*ct
->checksum
)(context
, crypto
, dkey
, usage
, iov
, niov
, &c
);
644 krb5_data_free(&c
.checksum
);
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)");
657 krb5_data_free (&c
.checksum
);
661 static krb5_error_code
662 verify_checksum(krb5_context context
,
664 unsigned usage
, /* not krb5_key_usage */
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
,
682 krb5_key_usage usage
,
687 struct _krb5_checksum_type
*ct
;
690 ct
= _krb5_find_checksum(cksum
->cksumtype
);
692 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
693 N_("checksum type %d not supported", ""),
695 return KRB5_PROG_SUMTYPE_NOSUPP
;
698 if (arcfour_checksum_p(ct
, crypto
)) {
700 _krb5_usage2arcfour(context
, &keyusage
);
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
,
711 krb5_cksumtype
*type
)
713 struct _krb5_checksum_type
*ct
= NULL
;
715 if (crypto
!= NULL
) {
716 ct
= crypto
->et
->keyed_checksum
;
718 ct
= crypto
->et
->checksum
;
722 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
723 N_("checksum type not found", ""));
724 return KRB5_PROG_SUMTYPE_NOSUPP
;
733 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
734 krb5_checksumsize(krb5_context context
,
738 struct _krb5_checksum_type
*ct
= _krb5_find_checksum(type
);
740 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
741 N_("checksum type %d not supported", ""),
743 return KRB5_PROG_SUMTYPE_NOSUPP
;
745 *size
= ct
->checksumsize
;
749 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
750 krb5_checksum_is_keyed(krb5_context context
,
753 struct _krb5_checksum_type
*ct
= _krb5_find_checksum(type
);
756 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
757 N_("checksum type %d not supported", ""),
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
,
768 struct _krb5_checksum_type
*ct
= _krb5_find_checksum(type
);
771 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
772 N_("checksum type %d not supported", ""),
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
,
783 struct _krb5_checksum_type
*ct
= _krb5_find_checksum(type
);
786 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
787 N_("checksum type %d not supported", ""),
789 return KRB5_PROG_SUMTYPE_NOSUPP
;
791 ct
->flags
|= F_DISABLED
;
795 /************************************************************
797 ************************************************************/
799 KRB5_LIB_FUNCTION
struct _krb5_encryption_type
* KRB5_LIB_CALL
800 _krb5_find_enctype(krb5_enctype type
)
803 for(i
= 0; i
< _krb5_num_etypes
; i
++)
804 if(_krb5_etypes
[i
]->type
== type
)
805 return _krb5_etypes
[i
];
810 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
811 krb5_enctype_to_string(krb5_context context
,
815 struct _krb5_encryption_type
*e
;
816 e
= _krb5_find_enctype(etype
);
818 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
819 N_("encryption type %d not supported", ""),
822 return KRB5_PROG_ETYPE_NOSUPP
;
824 *string
= strdup(e
->name
);
826 return krb5_enomem(context
);
830 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
831 krb5_string_to_enctype(krb5_context context
,
836 for(i
= 0; i
< _krb5_num_etypes
; i
++) {
837 if(strcasecmp(_krb5_etypes
[i
]->name
, string
) == 0){
838 *etype
= _krb5_etypes
[i
]->type
;
841 if(_krb5_etypes
[i
]->alias
!= NULL
&&
842 strcasecmp(_krb5_etypes
[i
]->alias
, string
) == 0){
843 *etype
= _krb5_etypes
[i
]->type
;
847 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
848 N_("encryption type %s not supported", ""),
850 return KRB5_PROG_ETYPE_NOSUPP
;
853 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
854 krb5_enctype_to_keytype(krb5_context context
,
856 krb5_keytype
*keytype
)
858 struct _krb5_encryption_type
*e
= _krb5_find_enctype(etype
);
860 return unsupported_enctype (context
, etype
);
862 *keytype
= e
->keytype
->type
; /* XXX */
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
,
880 struct _krb5_encryption_type
*e
= _krb5_find_enctype(etype
);
881 if(e
&& (e
->flags
& F_DISABLED
) == 0)
884 return KRB5_PROG_ETYPE_NOSUPP
;
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", ""),
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
,
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
;
926 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
927 N_("checksum type %d not supported", ""),
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
);
939 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
940 N_("checksum type %d not supported", ""),
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", ""),
948 return KRB5_PROG_SUMTYPE_NOSUPP
;
954 derived_crypto(krb5_context context
,
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
,
972 size_t sz
, block_sz
, checksum_sz
, total_sz
;
974 unsigned char *p
, *q
;
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
);
986 return krb5_enomem(context
);
989 krb5_generate_random_block(q
, et
->confoundersize
); /* XXX */
990 q
+= et
->confoundersize
;
991 memcpy(q
, data
, len
);
993 ret
= create_checksum(context
,
996 INTEGRITY_USAGE(usage
),
1001 if(ret
== 0 && cksum
.checksum
.length
!= checksum_sz
) {
1002 free_Checksum (&cksum
);
1003 krb5_clear_error_message (context
);
1004 ret
= KRB5_CRYPTO_INTERNAL
;
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
);
1013 ret
= _key_schedule(context
, dkey
);
1016 ret
= (*et
->encrypt
)(context
, dkey
, p
, block_sz
, 1, usage
, ivec
);
1020 result
->length
= total_sz
;
1023 memset(p
, 0, total_sz
);
1028 static krb5_error_code
1029 encrypt_internal_enc_then_cksum(krb5_context context
,
1037 size_t sz
, block_sz
, checksum_sz
, total_sz
;
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
);
1051 return krb5_enomem(context
);
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
);
1061 ret
= _key_schedule(context
, dkey
);
1065 /* XXX EVP style update API would avoid needing to allocate here */
1066 ivc
= malloc(et
->blocksize
+ block_sz
);
1068 ret
= krb5_enomem(context
);
1072 memcpy(ivc
, ivec
, et
->blocksize
);
1074 memset(ivc
, 0, et
->blocksize
);
1076 ret
= (*et
->encrypt
)(context
, dkey
, p
, block_sz
, 1, usage
, ivec
);
1079 memcpy(&ivc
[et
->blocksize
], p
, block_sz
);
1081 ret
= create_checksum(context
,
1084 INTEGRITY_USAGE(usage
),
1086 et
->blocksize
+ block_sz
,
1089 if(ret
== 0 && cksum
.checksum
.length
!= checksum_sz
) {
1090 free_Checksum (&cksum
);
1091 krb5_clear_error_message (context
);
1092 ret
= KRB5_CRYPTO_INTERNAL
;
1096 memcpy(p
+ block_sz
, cksum
.checksum
.data
, cksum
.checksum
.length
);
1097 free_Checksum (&cksum
);
1099 result
->length
= total_sz
;
1103 memset_s(p
, total_sz
, 0, total_sz
);
1109 static krb5_error_code
1110 encrypt_internal(krb5_context context
,
1117 size_t sz
, block_sz
, checksum_sz
;
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
);
1129 return krb5_enomem(context
);
1132 krb5_generate_random_block(q
, et
->confoundersize
); /* XXX */
1133 q
+= et
->confoundersize
;
1134 memset(q
, 0, checksum_sz
);
1136 memcpy(q
, data
, len
);
1138 ret
= create_checksum(context
,
1144 KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
,
1146 if(ret
== 0 && cksum
.checksum
.length
!= checksum_sz
) {
1147 krb5_clear_error_message (context
);
1148 free_Checksum(&cksum
);
1149 ret
= KRB5_CRYPTO_INTERNAL
;
1153 memcpy(p
+ et
->confoundersize
, cksum
.checksum
.data
, cksum
.checksum
.length
);
1154 free_Checksum(&cksum
);
1155 ret
= _key_schedule(context
, &crypto
->key
);
1158 ret
= (*et
->encrypt
)(context
, &crypto
->key
, p
, block_sz
, 1, 0, ivec
);
1160 memset(p
, 0, block_sz
);
1165 result
->length
= block_sz
;
1168 memset(p
, 0, block_sz
);
1173 static krb5_error_code
1174 encrypt_internal_special(krb5_context context
,
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
;
1186 krb5_error_code ret
;
1190 return krb5_enomem(context
);
1192 memset (p
, 0, 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
);
1204 result
->length
= sz
;
1208 static krb5_error_code
1209 decrypt_internal_derived(krb5_context context
,
1220 krb5_error_code ret
;
1221 struct _krb5_key_data
*dkey
;
1222 struct _krb5_encryption_type
*et
= crypto
->et
;
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
;
1239 if (len
!= 0 && p
== NULL
)
1240 return krb5_enomem(context
);
1241 memcpy(p
, data
, len
);
1245 ret
= _get_derived_key(context
, crypto
, ENCRYPTION_USAGE(usage
), &dkey
);
1250 ret
= _key_schedule(context
, dkey
);
1255 ret
= (*et
->encrypt
)(context
, dkey
, p
, len
, 0, usage
, ivec
);
1261 cksum
.checksum
.data
= p
+ len
;
1262 cksum
.checksum
.length
= checksum_sz
;
1263 cksum
.cksumtype
= CHECKSUMTYPE(et
->keyed_checksum
);
1265 ret
= verify_checksum(context
,
1267 INTEGRITY_USAGE(usage
),
1276 l
= len
- et
->confoundersize
;
1277 memmove(p
, p
+ et
->confoundersize
, l
);
1282 static krb5_error_code
1283 decrypt_internal_enc_then_cksum(krb5_context context
,
1294 krb5_error_code ret
;
1295 struct _krb5_key_data
*dkey
;
1296 struct _krb5_encryption_type
*et
= crypto
->et
;
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
;
1314 p
= malloc(et
->blocksize
+ len
);
1316 return krb5_enomem(context
);
1319 memcpy(p
, ivec
, et
->blocksize
);
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
,
1330 INTEGRITY_USAGE(usage
),
1332 et
->blocksize
+ len
,
1340 ret
= _get_derived_key(context
, crypto
, ENCRYPTION_USAGE(usage
), &dkey
);
1345 ret
= _key_schedule(context
, dkey
);
1350 ret
= (*et
->encrypt
)(context
, dkey
, &p
[et
->blocksize
], len
, 0, usage
, ivec
);
1356 l
= len
- et
->confoundersize
;
1357 memmove(p
, p
+ et
->blocksize
+ et
->confoundersize
, l
);
1362 static krb5_error_code
1363 decrypt_internal(krb5_context context
,
1370 krb5_error_code ret
;
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
;
1389 if (len
!= 0 && p
== NULL
)
1390 return krb5_enomem(context
);
1391 memcpy(p
, data
, len
);
1393 ret
= _key_schedule(context
, &crypto
->key
);
1398 ret
= (*et
->encrypt
)(context
, &crypto
->key
, p
, len
, 0, 0, ivec
);
1403 ret
= krb5_data_copy(&cksum
.checksum
, p
+ et
->confoundersize
, checksum_sz
);
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
);
1417 l
= len
- et
->confoundersize
- checksum_sz
;
1418 memmove(p
, p
+ et
->confoundersize
+ checksum_sz
, l
);
1423 static krb5_error_code
1424 decrypt_internal_special(krb5_context context
,
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
;
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
;
1451 return krb5_enomem(context
);
1452 memcpy(p
, data
, len
);
1454 ret
= (*et
->encrypt
)(context
, &crypto
->key
, p
, len
, FALSE
, usage
, ivec
);
1460 memmove (p
, p
+ cksum_sz
+ et
->confoundersize
, sz
);
1461 result
->length
= sz
;
1465 static krb5_crypto_iov
*
1466 iov_find(krb5_crypto_iov
*data
, size_t num_data
, unsigned type
)
1469 for (i
= 0; i
< num_data
; i
++)
1470 if (data
[i
].flags
== type
)
1476 iov_enc_data_len(krb5_crypto_iov
*data
, int num_data
)
1480 for (len
= 0, i
= 0; i
< num_data
; i
++) {
1481 if (data
[i
].flags
!= KRB5_CRYPTO_TYPE_DATA
)
1483 len
+= data
[i
].data
.length
;
1490 iov_sign_data_len(krb5_crypto_iov
*data
, int num_data
)
1494 for (len
= 0, i
= 0; i
< num_data
; i
++) {
1495 /* Can't use should_sign, because we must only count data, not
1497 if (data
[i
].flags
== KRB5_CRYPTO_TYPE_DATA
||
1498 data
[i
].flags
== KRB5_CRYPTO_TYPE_SIGN_ONLY
)
1499 len
+= data
[i
].data
.length
;
1505 static krb5_error_code
1506 iov_coalesce(krb5_context context
,
1508 krb5_crypto_iov
*data
,
1510 krb5_boolean inc_sign_data
,
1513 unsigned char *p
, *q
;
1514 krb5_crypto_iov
*hiv
, *piv
;
1518 hiv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_HEADER
);
1520 piv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_PADDING
);
1524 len
+= prefix
->length
;
1525 len
+= hiv
->data
.length
;
1527 len
+= iov_sign_data_len(data
, num_data
);
1529 len
+= iov_enc_data_len(data
, num_data
);
1531 len
+= piv
->data
.length
;
1533 p
= q
= malloc(len
);
1535 return krb5_enomem(context
);
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
;
1551 memset(q
, 0, piv
->data
.length
);
1559 static krb5_error_code
1560 iov_uncoalesce(krb5_context context
,
1561 krb5_data
*enc_data
,
1562 krb5_crypto_iov
*data
,
1565 unsigned char *q
= enc_data
->data
;
1566 krb5_crypto_iov
*hiv
, *piv
;
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
)
1579 memcpy(data
[i
].data
.data
, q
, data
[i
].data
.length
);
1580 q
+= data
[i
].data
.length
;
1583 memcpy(piv
->data
.data
, q
, piv
->data
.length
);
1588 static krb5_error_code
1589 iov_pad_validate(const struct _krb5_encryption_type
*et
,
1590 krb5_crypto_iov
*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
;
1611 if (piv
->data
.length
< pad_sz
)
1612 return KRB5_BAD_MSIZE
;
1613 piv
->data
.length
= pad_sz
;
1615 memset(piv
->data
.data
, 0, pad_sz
);
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
,
1652 krb5_crypto_iov
*data
,
1656 size_t headersz
, trailersz
;
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
;
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
);
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
);
1687 ret
= iov_pad_validate(et
, data
, num_data
, &piv
);
1692 tiv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_TRAILER
);
1693 if (tiv
== NULL
|| tiv
->data
.length
!= trailersz
) {
1694 ret
= KRB5_BAD_MSIZE
;
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
);
1709 ret
= _key_schedule(context
, dkey
);
1714 memcpy(old_ivec
, ivec
, et
->blocksize
);
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
,
1724 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1728 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1733 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
1745 ret
= create_checksum(context
,
1748 INTEGRITY_USAGE(usage
),
1754 if(ret
== 0 && cksum
.checksum
.length
!= trailersz
) {
1755 free_Checksum (&cksum
);
1756 krb5_clear_error_message (context
);
1757 ret
= KRB5_CRYPTO_INTERNAL
;
1762 /* save cksum at end */
1763 memcpy(tiv
->data
.data
, cksum
.checksum
.data
, cksum
.checksum
.length
);
1764 free_Checksum (&cksum
);
1767 cksum
.checksum
= tiv
->data
;
1768 ret
= create_checksum_iov(context
,
1771 INTEGRITY_USAGE(usage
),
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
);
1785 ret
= _key_schedule(context
, dkey
);
1789 if (et
->encrypt_iov
!= NULL
) {
1790 ret
= (*et
->encrypt_iov
)(context
, dkey
, data
, num_data
, 1, usage
,
1795 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1799 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1804 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
,
1847 krb5_crypto_iov
*data
,
1848 unsigned int num_data
,
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
;
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
;
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
;
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
);
1887 ret
= _key_schedule(context
, dkey
);
1891 if (et
->encrypt_iov
!= NULL
) {
1892 ret
= (*et
->encrypt_iov
)(context
, dkey
, data
, num_data
,
1897 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1901 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1906 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
);
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
,
1939 INTEGRITY_USAGE(usage
),
1947 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1951 ret
= _get_derived_key(context
, crypto
, ENCRYPTION_USAGE(usage
), &dkey
);
1955 ret
= _key_schedule(context
, dkey
);
1959 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1964 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
,
1999 krb5_crypto_iov
*data
,
2000 unsigned int num_data
,
2001 krb5_cksumtype
*type
)
2004 krb5_crypto_iov
*civ
;
2005 struct _krb5_checksum_type
*ct
;
2007 krb5_error_code ret
;
2009 civ
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_CHECKSUM
);
2011 return KRB5_BAD_MSIZE
;
2013 ct
= crypto
->et
->keyed_checksum
;
2015 ct
= crypto
->et
->checksum
;
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
)) {
2025 _krb5_usage2arcfour(context
, &keyusage
);
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
;
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
,
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
;
2070 krb5_crypto_iov
*civ
;
2071 krb5_error_code ret
;
2074 civ
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_CHECKSUM
);
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
);
2084 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
2085 N_("checksum type %d not supported", ""),
2087 return KRB5_PROG_SUMTYPE_NOSUPP
;
2090 if (arcfour_checksum_p(ct
, crypto
)) {
2092 _krb5_usage2arcfour(context
, &keyusage
);
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
;
2106 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2107 krb5_crypto_length(krb5_context context
,
2112 if (!derived_crypto(context
, crypto
)) {
2113 krb5_set_error_message(context
, EINVAL
, "not a derived crypto");
2118 case KRB5_CRYPTO_TYPE_EMPTY
:
2121 case KRB5_CRYPTO_TYPE_HEADER
:
2122 *len
= crypto
->et
->blocksize
;
2124 case KRB5_CRYPTO_TYPE_DATA
:
2125 case KRB5_CRYPTO_TYPE_SIGN_ONLY
:
2126 /* len must already been filled in */
2128 case KRB5_CRYPTO_TYPE_PADDING
:
2129 if (crypto
->et
->padsize
> 1)
2130 *len
= crypto
->et
->padsize
;
2134 case KRB5_CRYPTO_TYPE_TRAILER
:
2135 if (crypto
->et
->keyed_checksum
)
2136 *len
= CHECKSUMSIZE(crypto
->et
->keyed_checksum
);
2140 case KRB5_CRYPTO_TYPE_CHECKSUM
:
2141 if (crypto
->et
->keyed_checksum
)
2142 *len
= CHECKSUMSIZE(crypto
->et
->keyed_checksum
);
2144 *len
= CHECKSUMSIZE(crypto
->et
->checksum
);
2147 krb5_set_error_message(context
, EINVAL
,
2148 "%d not a supported type", type
);
2153 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2154 krb5_crypto_length_iov(krb5_context context
,
2156 krb5_crypto_iov
*data
,
2157 unsigned int num_data
)
2159 krb5_error_code ret
;
2162 for (i
= 0; i
< num_data
; i
++) {
2163 ret
= krb5_crypto_length(context
, crypto
,
2165 &data
[i
].data
.length
);
2173 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2174 krb5_encrypt_ivec(krb5_context context
,
2182 krb5_error_code ret
;
2184 switch (crypto
->et
->flags
& F_CRYPTO_MASK
) {
2186 ret
= encrypt_internal_derived(context
, crypto
, usage
,
2187 data
, len
, result
, ivec
);
2190 ret
= encrypt_internal_special (context
, crypto
, usage
,
2191 data
, len
, result
, ivec
);
2193 case F_ENC_THEN_CKSUM
:
2194 ret
= encrypt_internal_enc_then_cksum(context
, crypto
, usage
,
2195 data
, len
, result
, ivec
);
2198 ret
= encrypt_internal(context
, crypto
, data
, len
, result
, ivec
);
2205 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2206 krb5_encrypt(krb5_context context
,
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
,
2223 EncryptedData
*result
)
2225 result
->etype
= CRYPTO_ETYPE(crypto
);
2227 ALLOC(result
->kvno
, 1);
2228 *result
->kvno
= kvno
;
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
,
2243 krb5_error_code ret
;
2245 switch (crypto
->et
->flags
& F_CRYPTO_MASK
) {
2247 ret
= decrypt_internal_derived(context
, crypto
, usage
,
2248 data
, len
, result
, ivec
);
2251 ret
= decrypt_internal_special(context
, crypto
, usage
,
2252 data
, len
, result
, ivec
);
2254 case F_ENC_THEN_CKSUM
:
2255 ret
= decrypt_internal_enc_then_cksum(context
, crypto
, usage
,
2256 data
, len
, result
, ivec
);
2259 ret
= decrypt_internal(context
, crypto
, data
, len
, result
, ivec
);
2266 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2267 krb5_decrypt(krb5_context context
,
2274 return krb5_decrypt_ivec (context
, crypto
, usage
, data
, len
, result
,
2278 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2279 krb5_decrypt_EncryptedData(krb5_context context
,
2282 const EncryptedData
*e
,
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
,
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
);
2310 ret
= krb5_enomem(context
);
2313 ret
= _krb5_n_fold(constant
, len
, k
, et
->blocksize
);
2315 krb5_enomem(context
);
2319 for(i
= 0; i
< nblocks
; i
++) {
2321 memcpy(k
+ i
* et
->blocksize
,
2322 k
+ (i
- 1) * et
->blocksize
,
2324 ret
= (*et
->encrypt
)(context
, key
, k
+ i
* et
->blocksize
,
2325 et
->blocksize
, 1, 0, NULL
);
2327 krb5_set_error_message(context
, ret
, N_("encrypt failed", ""));
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
);
2340 memcpy(c
, constant
, len
);
2341 ret
= (*et
->encrypt
)(context
, key
, c
, len
, 1, 0, NULL
);
2344 krb5_set_error_message(context
, ret
, N_("encrypt failed", ""));
2347 k
= malloc(res_len
);
2348 if(res_len
!= 0 && k
== NULL
) {
2350 ret
= krb5_enomem(context
);
2353 ret
= _krb5_n_fold(c
, len
, k
, res_len
);
2356 krb5_enomem(context
);
2361 if (kt
->type
== KRB5_ENCTYPE_OLD_DES3_CBC_SHA1
)
2362 _krb5_DES3_random_to_key(context
, key
->key
, k
, nblocks
* et
->blocksize
);
2364 memcpy(key
->key
->keyvalue
.data
, k
, key
->key
->keyvalue
.length
);
2368 memset_s(k
, nblocks
* et
->blocksize
, 0, nblocks
* et
->blocksize
);
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
,
2381 krb5_error_code ret
;
2382 struct _krb5_key_type
*kt
= et
->keytype
;
2384 const EVP_MD
*md
= NULL
;
2385 const unsigned char *c
= constant
;
2389 ret
= _krb5_aes_sha2_md_for_enctype(context
, kt
->type
, &md
);
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;
2403 ret
= krb5_data_alloc(&K1
, key_len
);
2407 label
.data
= (void *)constant
;
2410 ret
= _krb5_SP800_108_HMAC_KDF(context
, &key
->key
->keyvalue
,
2411 &label
, NULL
, md
, &K1
);
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
);
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
,
2431 krb5_error_code ret
;
2433 ret
= _key_schedule(context
, key
);
2437 switch (et
->flags
& F_KDF_MASK
) {
2439 ret
= derive_key_rfc3961(context
, et
, key
, constant
, len
);
2441 case F_SP800_108_HMAC_KDF
:
2442 ret
= derive_key_sp800_hmac(context
, et
, key
, constant
, len
);
2445 ret
= KRB5_CRYPTO_INTERNAL
;
2446 krb5_set_error_message(context
, ret
,
2447 N_("derive_key() called with unknown keytype (%u)", ""),
2452 if (key
->schedule
) {
2453 free_key_schedule(context
, key
, et
);
2454 key
->schedule
= NULL
;
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
));
2467 crypto
->key_usage
= d
;
2468 d
+= crypto
->num_key_usage
++;
2469 memset(d
, 0, sizeof(*d
));
2474 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2475 krb5_derive_key(krb5_context context
,
2476 const krb5_keyblock
*key
,
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
);
2490 return unsupported_enctype (context
, etype
);
2493 ret
= krb5_copy_keyblock(context
, key
, &d
.key
);
2498 ret
= _krb5_derive_key(context
, et
, &d
, constant
, constant_len
);
2500 ret
= krb5_copy_keyblock(context
, d
.key
, derived_key
);
2501 _krb5_free_key_data(context
, &d
, et
);
2505 static krb5_error_code
2506 _get_derived_key(krb5_context context
,
2509 struct _krb5_key_data
**key
)
2512 struct _krb5_key_data
*d
;
2513 unsigned char constant
[5];
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
;
2521 d
= _new_derived_key(crypto
, usage
);
2523 return krb5_enomem(context
);
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
,
2552 krb5_crypto
*crypto
)
2554 krb5_error_code ret
;
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
)) {
2564 return unsupported_enctype(context
, etype
);
2566 if((*crypto
)->et
->keytype
->size
!= key
->keyvalue
.length
) {
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
);
2579 (*crypto
)->key
.schedule
= NULL
;
2580 (*crypto
)->num_key_usage
= 0;
2581 (*crypto
)->key_usage
= NULL
;
2582 (*crypto
)->flags
= 0;
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
);
2603 free_key_schedule(context
, key
, et
);
2604 key
->schedule
= NULL
;
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
,
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
);
2638 EVP_MD_CTX_destroy(crypto
->mdctx
);
2640 if (crypto
->hmacctx
)
2641 HMAC_CTX_free(crypto
->hmacctx
);
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
,
2664 *blocksize
= crypto
->et
->blocksize
;
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
,
2683 krb5_enctype
*enctype
)
2685 *enctype
= crypto
->et
->type
;
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
,
2706 *padsize
= crypto
->et
->padsize
;
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
,
2725 size_t *confoundersize
)
2727 *confoundersize
= crypto
->et
->confoundersize
;
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
);
2750 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
2751 N_("encryption type %d not supported", ""),
2753 return KRB5_PROG_ETYPE_NOSUPP
;
2755 et
->flags
|= F_DISABLED
;
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
);
2777 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
2778 N_("encryption type %d not supported", ""),
2780 return KRB5_PROG_ETYPE_NOSUPP
;
2782 et
->flags
&= ~F_DISABLED
;
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
)
2803 for(i
= 0; i
< _krb5_num_etypes
; i
++)
2804 if(_krb5_etypes
[i
]->flags
& F_WEAK
) {
2806 _krb5_etypes
[i
]->flags
&= ~F_DISABLED
;
2808 _krb5_etypes
[i
]->flags
|= F_DISABLED
;
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
))
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
))
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
);
2875 wrapped_length (krb5_context context
,
2879 struct _krb5_encryption_type
*et
= crypto
->et
;
2880 size_t padsize
= et
->padsize
;
2881 size_t checksumsize
= CHECKSUMSIZE(et
->checksum
);
2884 res
= et
->confoundersize
+ checksumsize
+ data_len
;
2885 res
= (res
+ padsize
- 1) / padsize
* padsize
;
2890 wrapped_length_dervied (krb5_context context
,
2894 struct _krb5_encryption_type
*et
= crypto
->et
;
2895 size_t padsize
= et
->padsize
;
2898 res
= et
->confoundersize
+ data_len
;
2899 res
= (res
+ padsize
- 1) / padsize
* padsize
;
2900 if (et
->keyed_checksum
)
2901 res
+= et
->keyed_checksum
->checksumsize
;
2903 res
+= et
->checksum
->checksumsize
;
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
,
2916 if (derived_crypto (context
, crypto
))
2917 return wrapped_length_dervied (context
, crypto
, data_len
);
2919 return wrapped_length (context
, crypto
, data_len
);
2923 * Return the size of an encrypted packet of length `data_len'
2927 crypto_overhead (krb5_context context
,
2930 struct _krb5_encryption_type
*et
= crypto
->et
;
2933 res
= CHECKSUMSIZE(et
->checksum
);
2934 res
+= et
->confoundersize
;
2935 if (et
->padsize
> 1)
2941 crypto_overhead_dervied (krb5_context context
,
2944 struct _krb5_encryption_type
*et
= crypto
->et
;
2947 if (et
->keyed_checksum
)
2948 res
= CHECKSUMSIZE(et
->keyed_checksum
);
2950 res
= CHECKSUMSIZE(et
->checksum
);
2951 res
+= et
->confoundersize
;
2952 if (et
->padsize
> 1)
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
);
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
,
2990 krb5_error_code ret
;
2991 struct _krb5_encryption_type
*et
= _krb5_find_enctype(type
);
2993 krb5_set_error_message(context
, KRB5_PROG_ETYPE_NOSUPP
,
2994 N_("encryption type %d not supported", ""),
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 "
3003 et
->name
, (int)et
->keytype
->size
);
3004 return KRB5_PROG_ETYPE_NOSUPP
;
3006 ret
= krb5_data_alloc(&key
->keyvalue
, et
->keytype
->size
);
3009 key
->keytype
= type
;
3010 if (et
->keytype
->random_to_key
)
3011 (*et
->keytype
->random_to_key
)(context
, key
, data
, size
);
3013 memcpy(key
->keyvalue
.data
, data
, et
->keytype
->size
);
3020 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3021 krb5_crypto_prf_length(krb5_context context
,
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", ""),
3031 return KRB5_PROG_ETYPE_NOSUPP
;
3034 *length
= et
->prf_length
;
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
,
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",
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
,
3065 krb5_error_code ret
;
3067 unsigned char i
= 1;
3070 krb5_data_zero(&input2
);
3071 krb5_data_zero(output
);
3073 krb5_clear_error_message(context
);
3075 ret
= krb5_data_alloc(output
, length
);
3077 ret
= krb5_data_alloc(&input2
, input
->length
+ 1);
3080 krb5_clear_error_message(context
);
3082 memcpy(((unsigned char *)input2
.data
) + 1, input
->data
, input
->length
);
3089 ((unsigned char *)input2
.data
)[0] = i
++;
3091 ret
= krb5_crypto_prf(context
, crypto
, &input2
, &block
);
3095 if (block
.length
< length
) {
3096 memcpy(p
, block
.data
, block
.length
);
3097 length
-= block
.length
;
3099 memcpy(p
, block
.data
, length
);
3103 krb5_data_free(&block
);
3107 krb5_data_free(&input2
);
3109 krb5_data_free(output
);
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
,
3135 krb5_enctype enctype
,
3138 krb5_error_code ret
;
3142 memset(res
, 0, sizeof(*res
));
3143 krb5_data_zero(&os1
);
3144 krb5_data_zero(&os2
);
3146 ret
= krb5_enctype_keybits(context
, enctype
, &keysize
);
3149 keysize
= (keysize
+ 7) / 8;
3151 ret
= krb5_crypto_prfplus(context
, crypto1
, pepper1
, keysize
, &os1
);
3154 ret
= krb5_crypto_prfplus(context
, crypto2
, pepper2
, keysize
, &os2
);
3158 res
->keytype
= enctype
;
3160 unsigned char *p1
= os1
.data
, *p2
= os2
.data
;
3161 for (i
= 0; i
< keysize
; i
++)
3164 ret
= krb5_random_to_key(context
, enctype
, os1
.data
, keysize
, res
);
3166 krb5_data_free(&os1
);
3167 krb5_data_free(&os2
);
3172 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
3173 _krb5_crypto_set_flags(krb5_context context
,
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
,
3193 KRB5_DEPRECATED_FUNCTION("Use X instead")
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)
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
);
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
;
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 */