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_INAPP_CKSUM
,
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
= (krb5_keytype
)e
->keytype
->type
;
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 + 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
;
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
);
1283 static krb5_error_code
1284 decrypt_internal_enc_then_cksum(krb5_context context
,
1295 krb5_error_code ret
;
1296 struct _krb5_key_data
*dkey
;
1297 struct _krb5_encryption_type
*et
= crypto
->et
;
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
;
1315 p
= malloc(et
->blocksize
+ len
);
1317 return krb5_enomem(context
);
1320 memcpy(p
, ivec
, et
->blocksize
);
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
,
1331 INTEGRITY_USAGE(usage
),
1333 et
->blocksize
+ len
,
1341 ret
= _get_derived_key(context
, crypto
, ENCRYPTION_USAGE(usage
), &dkey
);
1346 ret
= _key_schedule(context
, dkey
);
1351 ret
= (*et
->encrypt
)(context
, dkey
, &p
[et
->blocksize
], len
, 0, usage
, ivec
);
1357 l
= len
- et
->confoundersize
;
1358 memmove(p
, p
+ et
->blocksize
+ et
->confoundersize
, l
);
1364 static krb5_error_code
1365 decrypt_internal(krb5_context context
,
1372 krb5_error_code ret
;
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
;
1391 if (len
!= 0 && p
== NULL
)
1392 return krb5_enomem(context
);
1393 memcpy(p
, data
, len
);
1395 ret
= _key_schedule(context
, &crypto
->key
);
1400 ret
= (*et
->encrypt
)(context
, &crypto
->key
, p
, len
, 0, 0, ivec
);
1405 ret
= krb5_data_copy(&cksum
.checksum
, p
+ et
->confoundersize
, checksum_sz
);
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
);
1419 l
= len
- et
->confoundersize
- checksum_sz
;
1420 memmove(p
, p
+ et
->confoundersize
+ checksum_sz
, l
);
1426 static krb5_error_code
1427 decrypt_internal_special(krb5_context context
,
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
;
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
;
1454 return krb5_enomem(context
);
1455 memcpy(p
, data
, len
);
1457 ret
= (*et
->encrypt
)(context
, &crypto
->key
, p
, len
, FALSE
, usage
, ivec
);
1463 memmove (p
, p
+ cksum_sz
+ et
->confoundersize
, sz
);
1465 result
->length
= sz
;
1469 static krb5_crypto_iov
*
1470 iov_find(krb5_crypto_iov
*data
, size_t num_data
, unsigned type
)
1473 for (i
= 0; i
< num_data
; i
++)
1474 if (data
[i
].flags
== type
)
1480 iov_enc_data_len(krb5_crypto_iov
*data
, int num_data
)
1484 for (len
= 0, i
= 0; i
< num_data
; i
++) {
1485 if (data
[i
].flags
!= KRB5_CRYPTO_TYPE_DATA
)
1487 len
+= data
[i
].data
.length
;
1494 iov_sign_data_len(krb5_crypto_iov
*data
, int num_data
)
1498 for (len
= 0, i
= 0; i
< num_data
; i
++) {
1499 /* Can't use should_sign, because we must only count data, not
1501 if (data
[i
].flags
== KRB5_CRYPTO_TYPE_DATA
||
1502 data
[i
].flags
== KRB5_CRYPTO_TYPE_SIGN_ONLY
)
1503 len
+= data
[i
].data
.length
;
1509 static krb5_error_code
1510 iov_coalesce(krb5_context context
,
1512 krb5_crypto_iov
*data
,
1514 krb5_boolean inc_sign_data
,
1517 unsigned char *p
, *q
;
1518 krb5_crypto_iov
*hiv
, *piv
;
1522 hiv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_HEADER
);
1524 piv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_PADDING
);
1528 len
+= prefix
->length
;
1529 len
+= hiv
->data
.length
;
1531 len
+= iov_sign_data_len(data
, num_data
);
1533 len
+= iov_enc_data_len(data
, num_data
);
1535 len
+= piv
->data
.length
;
1537 p
= q
= malloc(len
);
1539 return krb5_enomem(context
);
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
;
1555 memset(q
, 0, piv
->data
.length
);
1563 static krb5_error_code
1564 iov_uncoalesce(krb5_context context
,
1565 krb5_data
*enc_data
,
1566 krb5_crypto_iov
*data
,
1569 unsigned char *q
= enc_data
->data
;
1570 krb5_crypto_iov
*hiv
, *piv
;
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
)
1583 memcpy(data
[i
].data
.data
, q
, data
[i
].data
.length
);
1584 q
+= data
[i
].data
.length
;
1587 memcpy(piv
->data
.data
, q
, piv
->data
.length
);
1592 static krb5_error_code
1593 iov_pad_validate(const struct _krb5_encryption_type
*et
,
1594 krb5_crypto_iov
*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
;
1615 if (piv
->data
.length
< pad_sz
)
1616 return KRB5_BAD_MSIZE
;
1617 piv
->data
.length
= pad_sz
;
1619 memset(piv
->data
.data
, 0, pad_sz
);
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
,
1656 krb5_crypto_iov
*data
,
1660 size_t headersz
, trailersz
;
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
;
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
);
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
);
1691 ret
= iov_pad_validate(et
, data
, num_data
, &piv
);
1696 tiv
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_TRAILER
);
1697 if (tiv
== NULL
|| tiv
->data
.length
!= trailersz
) {
1698 ret
= KRB5_BAD_MSIZE
;
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
);
1713 ret
= _key_schedule(context
, dkey
);
1718 memcpy(old_ivec
, ivec
, et
->blocksize
);
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
,
1728 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1732 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1737 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
1749 ret
= create_checksum(context
,
1752 INTEGRITY_USAGE(usage
),
1758 if(ret
== 0 && cksum
.checksum
.length
!= trailersz
) {
1759 free_Checksum (&cksum
);
1760 krb5_clear_error_message (context
);
1761 ret
= KRB5_CRYPTO_INTERNAL
;
1766 /* save cksum at end */
1767 memcpy(tiv
->data
.data
, cksum
.checksum
.data
, cksum
.checksum
.length
);
1768 free_Checksum (&cksum
);
1771 cksum
.checksum
= tiv
->data
;
1772 ret
= create_checksum_iov(context
,
1775 INTEGRITY_USAGE(usage
),
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
);
1789 ret
= _key_schedule(context
, dkey
);
1793 if (et
->encrypt_iov
!= NULL
) {
1794 ret
= (*et
->encrypt_iov
)(context
, dkey
, data
, num_data
, 1, usage
,
1799 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1803 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1808 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
,
1851 krb5_crypto_iov
*data
,
1852 unsigned int num_data
,
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
;
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
;
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
;
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
);
1891 ret
= _key_schedule(context
, dkey
);
1895 if (et
->encrypt_iov
!= NULL
) {
1896 ret
= (*et
->encrypt_iov
)(context
, dkey
, data
, num_data
,
1901 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1905 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1910 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
);
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
,
1943 INTEGRITY_USAGE(usage
),
1951 ret
= iov_coalesce(context
, NULL
, data
, num_data
, FALSE
, &enc_data
);
1955 ret
= _get_derived_key(context
, crypto
, ENCRYPTION_USAGE(usage
), &dkey
);
1959 ret
= _key_schedule(context
, dkey
);
1963 ret
= (*et
->encrypt
)(context
, dkey
, enc_data
.data
, enc_data
.length
,
1968 ret
= iov_uncoalesce(context
, &enc_data
, data
, num_data
);
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
);
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
,
2003 krb5_crypto_iov
*data
,
2004 unsigned int num_data
,
2005 krb5_cksumtype
*type
)
2008 krb5_crypto_iov
*civ
;
2009 struct _krb5_checksum_type
*ct
;
2011 krb5_error_code ret
;
2013 civ
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_CHECKSUM
);
2015 return KRB5_BAD_MSIZE
;
2017 ct
= crypto
->et
->keyed_checksum
;
2019 ct
= crypto
->et
->checksum
;
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
)) {
2029 _krb5_usage2arcfour(context
, &keyusage
);
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
;
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
,
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
;
2074 krb5_crypto_iov
*civ
;
2075 krb5_error_code ret
;
2078 civ
= iov_find(data
, num_data
, KRB5_CRYPTO_TYPE_CHECKSUM
);
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
);
2088 krb5_set_error_message (context
, KRB5_PROG_SUMTYPE_NOSUPP
,
2089 N_("checksum type %d not supported", ""),
2091 return KRB5_PROG_SUMTYPE_NOSUPP
;
2094 if (arcfour_checksum_p(ct
, crypto
)) {
2096 _krb5_usage2arcfour(context
, &keyusage
);
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
;
2110 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2111 krb5_crypto_length(krb5_context context
,
2116 if (!derived_crypto(context
, crypto
)) {
2117 krb5_set_error_message(context
, EINVAL
, "not a derived crypto");
2122 case KRB5_CRYPTO_TYPE_EMPTY
:
2125 case KRB5_CRYPTO_TYPE_HEADER
:
2126 *len
= crypto
->et
->blocksize
;
2128 case KRB5_CRYPTO_TYPE_DATA
:
2129 case KRB5_CRYPTO_TYPE_SIGN_ONLY
:
2130 /* len must already been filled in */
2132 case KRB5_CRYPTO_TYPE_PADDING
:
2133 if (crypto
->et
->padsize
> 1)
2134 *len
= crypto
->et
->padsize
;
2138 case KRB5_CRYPTO_TYPE_TRAILER
:
2139 if (crypto
->et
->keyed_checksum
)
2140 *len
= CHECKSUMSIZE(crypto
->et
->keyed_checksum
);
2144 case KRB5_CRYPTO_TYPE_CHECKSUM
:
2145 if (crypto
->et
->keyed_checksum
)
2146 *len
= CHECKSUMSIZE(crypto
->et
->keyed_checksum
);
2148 *len
= CHECKSUMSIZE(crypto
->et
->checksum
);
2151 krb5_set_error_message(context
, EINVAL
,
2152 "%d not a supported type", type
);
2157 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2158 krb5_crypto_length_iov(krb5_context context
,
2160 krb5_crypto_iov
*data
,
2161 unsigned int num_data
)
2163 krb5_error_code ret
;
2166 for (i
= 0; i
< num_data
; i
++) {
2167 ret
= krb5_crypto_length(context
, crypto
,
2169 &data
[i
].data
.length
);
2177 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2178 krb5_encrypt_ivec(krb5_context context
,
2186 krb5_error_code ret
;
2188 switch (crypto
->et
->flags
& F_CRYPTO_MASK
) {
2190 ret
= encrypt_internal_derived(context
, crypto
, usage
,
2191 data
, len
, result
, ivec
);
2194 ret
= encrypt_internal_special (context
, crypto
, usage
,
2195 data
, len
, result
, ivec
);
2197 case F_ENC_THEN_CKSUM
:
2198 ret
= encrypt_internal_enc_then_cksum(context
, crypto
, usage
,
2199 data
, len
, result
, ivec
);
2202 ret
= encrypt_internal(context
, crypto
, data
, len
, result
, ivec
);
2209 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2210 krb5_encrypt(krb5_context context
,
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
,
2227 EncryptedData
*result
)
2229 result
->etype
= CRYPTO_ETYPE(crypto
);
2231 ALLOC(result
->kvno
, 1);
2232 *result
->kvno
= kvno
;
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
,
2247 krb5_error_code ret
;
2249 switch (crypto
->et
->flags
& F_CRYPTO_MASK
) {
2251 ret
= decrypt_internal_derived(context
, crypto
, usage
,
2252 data
, len
, result
, ivec
);
2255 ret
= decrypt_internal_special(context
, crypto
, usage
,
2256 data
, len
, result
, ivec
);
2258 case F_ENC_THEN_CKSUM
:
2259 ret
= decrypt_internal_enc_then_cksum(context
, crypto
, usage
,
2260 data
, len
, result
, ivec
);
2263 ret
= decrypt_internal(context
, crypto
, data
, len
, result
, ivec
);
2270 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2271 krb5_decrypt(krb5_context context
,
2278 return krb5_decrypt_ivec (context
, crypto
, usage
, data
, len
, result
,
2282 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2283 krb5_decrypt_EncryptedData(krb5_context context
,
2286 const EncryptedData
*e
,
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
,
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
);
2314 ret
= krb5_enomem(context
);
2317 ret
= _krb5_n_fold(constant
, len
, k
, et
->blocksize
);
2319 krb5_enomem(context
);
2323 for(i
= 0; i
< nblocks
; i
++) {
2325 memcpy(k
+ i
* et
->blocksize
,
2326 k
+ (i
- 1) * et
->blocksize
,
2328 ret
= (*et
->encrypt
)(context
, key
, k
+ i
* et
->blocksize
,
2329 et
->blocksize
, 1, 0, NULL
);
2331 krb5_set_error_message(context
, ret
, N_("encrypt failed", ""));
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
);
2344 memcpy(c
, constant
, len
);
2345 ret
= (*et
->encrypt
)(context
, key
, c
, len
, 1, 0, NULL
);
2348 krb5_set_error_message(context
, ret
, N_("encrypt failed", ""));
2351 k
= malloc(res_len
);
2352 if(res_len
!= 0 && k
== NULL
) {
2354 ret
= krb5_enomem(context
);
2357 ret
= _krb5_n_fold(c
, len
, k
, res_len
);
2360 krb5_enomem(context
);
2365 if (kt
->type
== KRB5_ENCTYPE_OLD_DES3_CBC_SHA1
)
2366 _krb5_DES3_random_to_key(context
, key
->key
, k
, nblocks
* et
->blocksize
);
2368 memcpy(key
->key
->keyvalue
.data
, k
, key
->key
->keyvalue
.length
);
2372 memset_s(k
, nblocks
* et
->blocksize
, 0, nblocks
* et
->blocksize
);
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
,
2385 krb5_error_code ret
;
2386 struct _krb5_key_type
*kt
= et
->keytype
;
2388 const EVP_MD
*md
= NULL
;
2389 const unsigned char *c
= constant
;
2393 ret
= _krb5_aes_sha2_md_for_enctype(context
, kt
->type
, &md
);
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;
2407 ret
= krb5_data_alloc(&K1
, key_len
);
2411 label
.data
= (void *)constant
;
2414 ret
= _krb5_SP800_108_HMAC_KDF(context
, &key
->key
->keyvalue
,
2415 &label
, NULL
, md
, &K1
);
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
);
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
,
2435 krb5_error_code ret
;
2437 ret
= _key_schedule(context
, key
);
2441 switch (et
->flags
& F_KDF_MASK
) {
2443 ret
= derive_key_rfc3961(context
, et
, key
, constant
, len
);
2445 case F_SP800_108_HMAC_KDF
:
2446 ret
= derive_key_sp800_hmac(context
, et
, key
, constant
, len
);
2449 ret
= KRB5_CRYPTO_INTERNAL
;
2450 krb5_set_error_message(context
, ret
,
2451 N_("derive_key() called with unknown keytype (%u)", ""),
2456 if (key
->schedule
) {
2457 free_key_schedule(context
, key
, et
);
2458 key
->schedule
= NULL
;
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
));
2471 crypto
->key_usage
= d
;
2472 d
+= crypto
->num_key_usage
++;
2473 memset(d
, 0, sizeof(*d
));
2478 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2479 krb5_derive_key(krb5_context context
,
2480 const krb5_keyblock
*key
,
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
);
2494 return unsupported_enctype (context
, etype
);
2497 ret
= krb5_copy_keyblock(context
, key
, &d
.key
);
2502 ret
= _krb5_derive_key(context
, et
, &d
, constant
, constant_len
);
2504 ret
= krb5_copy_keyblock(context
, d
.key
, derived_key
);
2505 _krb5_free_key_data(context
, &d
, et
);
2509 static krb5_error_code
2510 _get_derived_key(krb5_context context
,
2513 struct _krb5_key_data
**key
)
2516 struct _krb5_key_data
*d
;
2517 unsigned char constant
[5];
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
;
2525 d
= _new_derived_key(crypto
, usage
);
2527 return krb5_enomem(context
);
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
,
2556 krb5_crypto
*crypto
)
2558 krb5_error_code ret
;
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
)) {
2568 return unsupported_enctype(context
, etype
);
2570 if((*crypto
)->et
->keytype
->size
!= key
->keyvalue
.length
) {
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
);
2583 (*crypto
)->key
.schedule
= NULL
;
2584 (*crypto
)->num_key_usage
= 0;
2585 (*crypto
)->key_usage
= NULL
;
2586 (*crypto
)->flags
= 0;
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
);
2607 free_key_schedule(context
, key
, et
);
2608 key
->schedule
= NULL
;
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
,
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
);
2642 EVP_MD_CTX_destroy(crypto
->mdctx
);
2644 if (crypto
->hmacctx
)
2645 HMAC_CTX_free(crypto
->hmacctx
);
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
,
2668 *blocksize
= crypto
->et
->blocksize
;
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
,
2687 krb5_enctype
*enctype
)
2689 *enctype
= crypto
->et
->type
;
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
,
2710 *padsize
= crypto
->et
->padsize
;
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
,
2729 size_t *confoundersize
)
2731 *confoundersize
= crypto
->et
->confoundersize
;
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
);
2754 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
2755 N_("encryption type %d not supported", ""),
2757 return KRB5_PROG_ETYPE_NOSUPP
;
2759 et
->flags
|= F_DISABLED
;
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
);
2781 krb5_set_error_message (context
, KRB5_PROG_ETYPE_NOSUPP
,
2782 N_("encryption type %d not supported", ""),
2784 return KRB5_PROG_ETYPE_NOSUPP
;
2786 et
->flags
&= ~F_DISABLED
;
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
)
2807 for(i
= 0; i
< _krb5_num_etypes
; i
++)
2808 if(_krb5_etypes
[i
]->flags
& F_WEAK
) {
2810 _krb5_etypes
[i
]->flags
&= ~F_DISABLED
;
2812 _krb5_etypes
[i
]->flags
|= F_DISABLED
;
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
))
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
))
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
);
2879 wrapped_length (krb5_context context
,
2883 struct _krb5_encryption_type
*et
= crypto
->et
;
2884 size_t padsize
= et
->padsize
;
2885 size_t checksumsize
= CHECKSUMSIZE(et
->checksum
);
2888 res
= et
->confoundersize
+ checksumsize
+ data_len
;
2889 res
= (res
+ padsize
- 1) / padsize
* padsize
;
2894 wrapped_length_dervied (krb5_context context
,
2898 struct _krb5_encryption_type
*et
= crypto
->et
;
2899 size_t padsize
= et
->padsize
;
2902 res
= et
->confoundersize
+ data_len
;
2903 res
= (res
+ padsize
- 1) / padsize
* padsize
;
2904 if (et
->keyed_checksum
)
2905 res
+= et
->keyed_checksum
->checksumsize
;
2907 res
+= et
->checksum
->checksumsize
;
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
,
2920 if (derived_crypto (context
, crypto
))
2921 return wrapped_length_dervied (context
, crypto
, data_len
);
2923 return wrapped_length (context
, crypto
, data_len
);
2927 * Return the size of an encrypted packet of length `data_len'
2931 crypto_overhead (krb5_context context
,
2934 struct _krb5_encryption_type
*et
= crypto
->et
;
2937 res
= CHECKSUMSIZE(et
->checksum
);
2938 res
+= et
->confoundersize
;
2939 if (et
->padsize
> 1)
2945 crypto_overhead_dervied (krb5_context context
,
2948 struct _krb5_encryption_type
*et
= crypto
->et
;
2951 if (et
->keyed_checksum
)
2952 res
= CHECKSUMSIZE(et
->keyed_checksum
);
2954 res
= CHECKSUMSIZE(et
->checksum
);
2955 res
+= et
->confoundersize
;
2956 if (et
->padsize
> 1)
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
);
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
,
2994 krb5_error_code ret
;
2995 struct _krb5_encryption_type
*et
= _krb5_find_enctype(type
);
2997 krb5_set_error_message(context
, KRB5_PROG_ETYPE_NOSUPP
,
2998 N_("encryption type %d not supported", ""),
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 "
3007 et
->name
, (int)et
->keytype
->size
);
3008 return KRB5_PROG_ETYPE_NOSUPP
;
3010 ret
= krb5_data_alloc(&key
->keyvalue
, et
->keytype
->size
);
3013 key
->keytype
= type
;
3014 if (et
->keytype
->random_to_key
)
3015 (*et
->keytype
->random_to_key
)(context
, key
, data
, size
);
3017 memcpy(key
->keyvalue
.data
, data
, et
->keytype
->size
);
3024 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3025 krb5_crypto_prf_length(krb5_context context
,
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", ""),
3035 return KRB5_PROG_ETYPE_NOSUPP
;
3038 *length
= et
->prf_length
;
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
,
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",
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
,
3069 krb5_error_code ret
;
3071 unsigned char i
= 1;
3074 krb5_data_zero(&input2
);
3075 krb5_data_zero(output
);
3077 krb5_clear_error_message(context
);
3079 ret
= krb5_data_alloc(output
, length
);
3081 ret
= krb5_data_alloc(&input2
, input
->length
+ 1);
3084 krb5_clear_error_message(context
);
3086 memcpy(((unsigned char *)input2
.data
) + 1, input
->data
, input
->length
);
3093 ((unsigned char *)input2
.data
)[0] = i
++;
3095 ret
= krb5_crypto_prf(context
, crypto
, &input2
, &block
);
3099 if (block
.length
< length
) {
3100 memcpy(p
, block
.data
, block
.length
);
3101 length
-= block
.length
;
3103 memcpy(p
, block
.data
, length
);
3107 krb5_data_free(&block
);
3111 krb5_data_free(&input2
);
3113 krb5_data_free(output
);
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
,
3139 krb5_enctype enctype
,
3142 krb5_error_code ret
;
3146 memset(res
, 0, sizeof(*res
));
3147 krb5_data_zero(&os1
);
3148 krb5_data_zero(&os2
);
3150 ret
= krb5_enctype_keybits(context
, enctype
, &keysize
);
3153 keysize
= (keysize
+ 7) / 8;
3155 ret
= krb5_crypto_prfplus(context
, crypto1
, pepper1
, keysize
, &os1
);
3158 ret
= krb5_crypto_prfplus(context
, crypto2
, pepper2
, keysize
, &os2
);
3162 res
->keytype
= enctype
;
3164 unsigned char *p1
= os1
.data
, *p2
= os2
.data
;
3165 for (i
= 0; i
< keysize
; i
++)
3168 ret
= krb5_random_to_key(context
, enctype
, os1
.data
, keysize
, res
);
3170 krb5_data_free(&os1
);
3171 krb5_data_free(&os2
);
3176 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
3177 _krb5_crypto_set_flags(krb5_context context
,
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
,
3197 KRB5_DEPRECATED_FUNCTION("Use X instead")
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)
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
);
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
;
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 */