155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682Smarkm
36233294Sstasstruct _krb5_key_usage {
3755682Smarkm    unsigned usage;
38233294Sstas    struct _krb5_key_data key;
3955682Smarkm};
4055682Smarkm
4155682Smarkm
42233294Sstas#ifndef HEIMDAL_SMALLER
43233294Sstas#define DES3_OLD_ENCTYPE 1
4455682Smarkm#endif
4555682Smarkm
46233294Sstasstatic krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
47233294Sstas					unsigned, struct _krb5_key_data**);
48233294Sstasstatic struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
4955682Smarkm
50233294Sstasstatic void free_key_schedule(krb5_context,
51233294Sstas			      struct _krb5_key_data *,
52233294Sstas			      struct _krb5_encryption_type *);
5355682Smarkm
54233294Sstas/*
55233294Sstas * Converts etype to a user readable string and sets as a side effect
56233294Sstas * the krb5_error_message containing this string. Returns
57233294Sstas * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
58233294Sstas * which case the error code of the etype convesion is returned.
5955682Smarkm */
6055682Smarkm
6155682Smarkmstatic krb5_error_code
62233294Sstasunsupported_enctype(krb5_context context, krb5_enctype etype)
6355682Smarkm{
64178828Sdfr    krb5_error_code ret;
65233294Sstas    char *name;
6655682Smarkm
67233294Sstas    ret = krb5_enctype_to_string(context, etype, &name);
68233294Sstas    if (ret)
69120948Snectar	return ret;
70120948Snectar
71233294Sstas    krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
72233294Sstas			   N_("Encryption type %s not supported", ""),
73233294Sstas			   name);
74233294Sstas    free(name);
75233294Sstas    return KRB5_PROG_ETYPE_NOSUPP;
76120948Snectar}
77120948Snectar
78120948Snectar/*
79120948Snectar *
80120948Snectar */
81120948Snectar
82233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83120948Snectarkrb5_enctype_keysize(krb5_context context,
84120948Snectar		     krb5_enctype type,
85120948Snectar		     size_t *keysize)
86120948Snectar{
87233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
88120948Snectar    if(et == NULL) {
89233294Sstas        return unsupported_enctype (context, type);
90120948Snectar    }
91120948Snectar    *keysize = et->keytype->size;
92120948Snectar    return 0;
93120948Snectar}
94120948Snectar
95233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
96178828Sdfrkrb5_enctype_keybits(krb5_context context,
97178828Sdfr		     krb5_enctype type,
98178828Sdfr		     size_t *keybits)
99178828Sdfr{
100233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
101178828Sdfr    if(et == NULL) {
102233294Sstas        return unsupported_enctype (context, type);
103178828Sdfr    }
104178828Sdfr    *keybits = et->keytype->bits;
105178828Sdfr    return 0;
106178828Sdfr}
107178828Sdfr
108233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
10955682Smarkmkrb5_generate_random_keyblock(krb5_context context,
11055682Smarkm			      krb5_enctype type,
11155682Smarkm			      krb5_keyblock *key)
11255682Smarkm{
11355682Smarkm    krb5_error_code ret;
114233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
11578536Sassar    if(et == NULL) {
116233294Sstas        return unsupported_enctype (context, type);
11778536Sassar    }
11855682Smarkm    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
119233294Sstas    if(ret)
12055682Smarkm	return ret;
12155682Smarkm    key->keytype = type;
12255682Smarkm    if(et->keytype->random_key)
12355682Smarkm	(*et->keytype->random_key)(context, key);
12455682Smarkm    else
125233294Sstas	krb5_generate_random_block(key->keyvalue.data,
12655682Smarkm				   key->keyvalue.length);
12755682Smarkm    return 0;
12855682Smarkm}
12955682Smarkm
13055682Smarkmstatic krb5_error_code
13155682Smarkm_key_schedule(krb5_context context,
132233294Sstas	      struct _krb5_key_data *key)
13355682Smarkm{
13455682Smarkm    krb5_error_code ret;
135233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
136233294Sstas    struct _krb5_key_type *kt;
13755682Smarkm
138233294Sstas    if (et == NULL) {
139233294Sstas        return unsupported_enctype (context,
140233294Sstas                               key->key->keytype);
141233294Sstas    }
142233294Sstas
143233294Sstas    kt = et->keytype;
144233294Sstas
14555682Smarkm    if(kt->schedule == NULL)
14655682Smarkm	return 0;
14772448Sassar    if (key->schedule != NULL)
14872448Sassar	return 0;
14955682Smarkm    ALLOC(key->schedule, 1);
15078536Sassar    if(key->schedule == NULL) {
151233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
15255682Smarkm	return ENOMEM;
15378536Sassar    }
15455682Smarkm    ret = krb5_data_alloc(key->schedule, kt->schedule_size);
15555682Smarkm    if(ret) {
15655682Smarkm	free(key->schedule);
15755682Smarkm	key->schedule = NULL;
15855682Smarkm	return ret;
15955682Smarkm    }
160233294Sstas    (*kt->schedule)(context, kt, key);
16155682Smarkm    return 0;
16255682Smarkm}
16355682Smarkm
16455682Smarkm/************************************************************
16555682Smarkm *                                                          *
16655682Smarkm ************************************************************/
16755682Smarkm
168233294Sstasstatic krb5_error_code
169233294SstasSHA1_checksum(krb5_context context,
170233294Sstas	      struct _krb5_key_data *key,
17172448Sassar	      const void *data,
17255682Smarkm	      size_t len,
17372448Sassar	      unsigned usage,
17455682Smarkm	      Checksum *C)
17555682Smarkm{
176233294Sstas    if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
177233294Sstas	krb5_abortx(context, "sha1 checksum failed");
178233294Sstas    return 0;
17955682Smarkm}
18055682Smarkm
181233294Sstas/* HMAC according to RFC2104 */
182233294Sstaskrb5_error_code
183233294Sstas_krb5_internal_hmac(krb5_context context,
184233294Sstas		    struct _krb5_checksum_type *cm,
18572448Sassar		    const void *data,
18655682Smarkm		    size_t len,
18772448Sassar		    unsigned usage,
188233294Sstas		    struct _krb5_key_data *keyblock,
189233294Sstas		    Checksum *result)
19055682Smarkm{
19155682Smarkm    unsigned char *ipad, *opad;
19255682Smarkm    unsigned char *key;
19355682Smarkm    size_t key_len;
194233294Sstas    size_t i;
195233294Sstas
196127811Snectar    ipad = malloc(cm->blocksize + len);
197127811Snectar    if (ipad == NULL)
198127811Snectar	return ENOMEM;
199127811Snectar    opad = malloc(cm->blocksize + cm->checksumsize);
200127811Snectar    if (opad == NULL) {
201127811Snectar	free(ipad);
202127811Snectar	return ENOMEM;
203127811Snectar    }
204127811Snectar    memset(ipad, 0x36, cm->blocksize);
205127811Snectar    memset(opad, 0x5c, cm->blocksize);
206127811Snectar
20755682Smarkm    if(keyblock->key->keyvalue.length > cm->blocksize){
208233294Sstas	(*cm->checksum)(context,
209233294Sstas			keyblock,
210233294Sstas			keyblock->key->keyvalue.data,
211233294Sstas			keyblock->key->keyvalue.length,
21272448Sassar			usage,
21355682Smarkm			result);
21455682Smarkm	key = result->checksum.data;
21555682Smarkm	key_len = result->checksum.length;
21655682Smarkm    } else {
21755682Smarkm	key = keyblock->key->keyvalue.data;
21855682Smarkm	key_len = keyblock->key->keyvalue.length;
21955682Smarkm    }
22055682Smarkm    for(i = 0; i < key_len; i++){
22155682Smarkm	ipad[i] ^= key[i];
22255682Smarkm	opad[i] ^= key[i];
22355682Smarkm    }
22455682Smarkm    memcpy(ipad + cm->blocksize, data, len);
22572448Sassar    (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
22672448Sassar		    usage, result);
227233294Sstas    memcpy(opad + cm->blocksize, result->checksum.data,
22855682Smarkm	   result->checksum.length);
229233294Sstas    (*cm->checksum)(context, keyblock, opad,
23072448Sassar		    cm->blocksize + cm->checksumsize, usage, result);
23155682Smarkm    memset(ipad, 0, cm->blocksize + len);
23255682Smarkm    free(ipad);
23355682Smarkm    memset(opad, 0, cm->blocksize + cm->checksumsize);
23455682Smarkm    free(opad);
235127811Snectar
236127811Snectar    return 0;
23755682Smarkm}
23855682Smarkm
239233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240127811Snectarkrb5_hmac(krb5_context context,
241127811Snectar	  krb5_cksumtype cktype,
242127811Snectar	  const void *data,
243127811Snectar	  size_t len,
244233294Sstas	  unsigned usage,
245127811Snectar	  krb5_keyblock *key,
246127811Snectar	  Checksum *result)
247127811Snectar{
248233294Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
249233294Sstas    struct _krb5_key_data kd;
250127811Snectar    krb5_error_code ret;
251127811Snectar
252127811Snectar    if (c == NULL) {
253233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
254233294Sstas				N_("checksum type %d not supported", ""),
255233294Sstas				cktype);
256127811Snectar	return KRB5_PROG_SUMTYPE_NOSUPP;
257127811Snectar    }
258127811Snectar
259127811Snectar    kd.key = key;
260127811Snectar    kd.schedule = NULL;
261127811Snectar
262233294Sstas    ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result);
263127811Snectar
264127811Snectar    if (kd.schedule)
265127811Snectar	krb5_free_data(context, kd.schedule);
266127811Snectar
267127811Snectar    return ret;
268233294Sstas}
269127811Snectar
270233294Sstaskrb5_error_code
271233294Sstas_krb5_SP_HMAC_SHA1_checksum(krb5_context context,
272233294Sstas			    struct _krb5_key_data *key,
273233294Sstas			    const void *data,
274233294Sstas			    size_t len,
275233294Sstas			    unsigned usage,
276233294Sstas			    Checksum *result)
27755682Smarkm{
278233294Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
279120948Snectar    Checksum res;
280120948Snectar    char sha1_data[20];
281127811Snectar    krb5_error_code ret;
28255682Smarkm
283120948Snectar    res.checksum.data = sha1_data;
284120948Snectar    res.checksum.length = sizeof(sha1_data);
285120948Snectar
286233294Sstas    ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res);
287127811Snectar    if (ret)
288127811Snectar	krb5_abortx(context, "hmac failed");
289120948Snectar    memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
290233294Sstas    return 0;
29155682Smarkm}
29255682Smarkm
293233294Sstasstruct _krb5_checksum_type _krb5_checksum_sha1 = {
29455682Smarkm    CKSUMTYPE_SHA1,
29555682Smarkm    "sha1",
29655682Smarkm    64,
29755682Smarkm    20,
29855682Smarkm    F_CPROOF,
29955682Smarkm    SHA1_checksum,
30055682Smarkm    NULL
30155682Smarkm};
30255682Smarkm
303233294Sstasstruct _krb5_checksum_type *
304233294Sstas_krb5_find_checksum(krb5_cksumtype type)
30555682Smarkm{
30655682Smarkm    int i;
307233294Sstas    for(i = 0; i < _krb5_num_checksums; i++)
308233294Sstas	if(_krb5_checksum_types[i]->type == type)
309233294Sstas	    return _krb5_checksum_types[i];
31055682Smarkm    return NULL;
31155682Smarkm}
31255682Smarkm
31355682Smarkmstatic krb5_error_code
314233294Sstasget_checksum_key(krb5_context context,
31555682Smarkm		 krb5_crypto crypto,
31655682Smarkm		 unsigned usage,  /* not krb5_key_usage */
317233294Sstas		 struct _krb5_checksum_type *ct,
318233294Sstas		 struct _krb5_key_data **key)
31955682Smarkm{
32055682Smarkm    krb5_error_code ret = 0;
32155682Smarkm
32255682Smarkm    if(ct->flags & F_DERIVED)
32355682Smarkm	ret = _get_derived_key(context, crypto, usage, key);
32455682Smarkm    else if(ct->flags & F_VARIANT) {
325233294Sstas	size_t i;
32655682Smarkm
32755682Smarkm	*key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
32878536Sassar	if(*key == NULL) {
329233294Sstas	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
33055682Smarkm	    return ENOMEM;
33178536Sassar	}
33255682Smarkm	ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
333233294Sstas	if(ret)
33455682Smarkm	    return ret;
33555682Smarkm	for(i = 0; i < (*key)->key->keyvalue.length; i++)
33655682Smarkm	    ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
33755682Smarkm    } else {
338233294Sstas	*key = &crypto->key;
33955682Smarkm    }
34055682Smarkm    if(ret == 0)
34155682Smarkm	ret = _key_schedule(context, *key);
34255682Smarkm    return ret;
34355682Smarkm}
34455682Smarkm
34555682Smarkmstatic krb5_error_code
346127811Snectarcreate_checksum (krb5_context context,
347233294Sstas		 struct _krb5_checksum_type *ct,
348127811Snectar		 krb5_crypto crypto,
349127811Snectar		 unsigned usage,
350127811Snectar		 void *data,
351127811Snectar		 size_t len,
352127811Snectar		 Checksum *result)
35355682Smarkm{
35455682Smarkm    krb5_error_code ret;
355233294Sstas    struct _krb5_key_data *dkey;
35655682Smarkm    int keyed_checksum;
357233294Sstas
358178828Sdfr    if (ct->flags & F_DISABLED) {
359233294Sstas	krb5_clear_error_message (context);
360178828Sdfr	return KRB5_PROG_SUMTYPE_NOSUPP;
361178828Sdfr    }
36255682Smarkm    keyed_checksum = (ct->flags & F_KEYED) != 0;
36378536Sassar    if(keyed_checksum && crypto == NULL) {
364233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
365233294Sstas				N_("Checksum type %s is keyed but no "
366233294Sstas				   "crypto context (key) was passed in", ""),
367233294Sstas				ct->name);
36855682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
36978536Sassar    }
37072448Sassar    if(keyed_checksum) {
37155682Smarkm	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
37272448Sassar	if (ret)
37372448Sassar	    return ret;
37472448Sassar    } else
37555682Smarkm	dkey = NULL;
37655682Smarkm    result->cksumtype = ct->type;
377178828Sdfr    ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
378178828Sdfr    if (ret)
379178828Sdfr	return (ret);
380233294Sstas    return (*ct->checksum)(context, dkey, data, len, usage, result);
38155682Smarkm}
38255682Smarkm
383127811Snectarstatic int
384233294Sstasarcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
38555682Smarkm{
386127811Snectar    return (ct->type == CKSUMTYPE_HMAC_MD5) &&
387127811Snectar	(crypto->key.key->keytype == KEYTYPE_ARCFOUR);
388127811Snectar}
389127811Snectar
390233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
391127811Snectarkrb5_create_checksum(krb5_context context,
392127811Snectar		     krb5_crypto crypto,
393127811Snectar		     krb5_key_usage usage,
394127811Snectar		     int type,
395127811Snectar		     void *data,
396127811Snectar		     size_t len,
397127811Snectar		     Checksum *result)
398127811Snectar{
399233294Sstas    struct _krb5_checksum_type *ct = NULL;
400127811Snectar    unsigned keyusage;
40155682Smarkm
402127811Snectar    /* type 0 -> pick from crypto */
40378536Sassar    if (type) {
404233294Sstas	ct = _krb5_find_checksum(type);
40578536Sassar    } else if (crypto) {
40655682Smarkm	ct = crypto->et->keyed_checksum;
40778536Sassar	if (ct == NULL)
40878536Sassar	    ct = crypto->et->checksum;
40978536Sassar    }
41078536Sassar
41178536Sassar    if(ct == NULL) {
412233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
413233294Sstas				N_("checksum type %d not supported", ""),
414233294Sstas				type);
41555682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
41678536Sassar    }
41755682Smarkm
418127811Snectar    if (arcfour_checksum_p(ct, crypto)) {
419127811Snectar	keyusage = usage;
420233294Sstas	_krb5_usage2arcfour(context, &keyusage);
421127811Snectar    } else
422127811Snectar	keyusage = CHECKSUM_USAGE(usage);
423127811Snectar
424127811Snectar    return create_checksum(context, ct, crypto, keyusage,
425127811Snectar			   data, len, result);
42655682Smarkm}
42755682Smarkm
42855682Smarkmstatic krb5_error_code
42955682Smarkmverify_checksum(krb5_context context,
43055682Smarkm		krb5_crypto crypto,
43155682Smarkm		unsigned usage, /* not krb5_key_usage */
43255682Smarkm		void *data,
43355682Smarkm		size_t len,
43455682Smarkm		Checksum *cksum)
43555682Smarkm{
43655682Smarkm    krb5_error_code ret;
437233294Sstas    struct _krb5_key_data *dkey;
43855682Smarkm    int keyed_checksum;
43955682Smarkm    Checksum c;
440233294Sstas    struct _krb5_checksum_type *ct;
44155682Smarkm
442233294Sstas    ct = _krb5_find_checksum(cksum->cksumtype);
443178828Sdfr    if (ct == NULL || (ct->flags & F_DISABLED)) {
444233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
445233294Sstas				N_("checksum type %d not supported", ""),
446233294Sstas				cksum->cksumtype);
44755682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
44878536Sassar    }
44978536Sassar    if(ct->checksumsize != cksum->checksum.length) {
450233294Sstas	krb5_clear_error_message (context);
451233294Sstas	krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
452233294Sstas			       N_("Decrypt integrity check failed for checksum type %s, "
453233294Sstas				  "length was %u, expected %u", ""),
454233294Sstas			       ct->name, (unsigned)cksum->checksum.length,
455233294Sstas			       (unsigned)ct->checksumsize);
456233294Sstas
45755682Smarkm	return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
45878536Sassar    }
45955682Smarkm    keyed_checksum = (ct->flags & F_KEYED) != 0;
460233294Sstas    if(keyed_checksum) {
461233294Sstas	struct _krb5_checksum_type *kct;
462233294Sstas	if (crypto == NULL) {
463233294Sstas	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
464233294Sstas				   N_("Checksum type %s is keyed but no "
465233294Sstas				      "crypto context (key) was passed in", ""),
466233294Sstas				   ct->name);
467233294Sstas	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
468233294Sstas	}
469233294Sstas	kct = crypto->et->keyed_checksum;
470234027Sstas	if (kct == NULL || kct->type != ct->type) {
471233294Sstas	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
472233294Sstas				   N_("Checksum type %s is keyed, but "
473233294Sstas				      "the key type %s passed didnt have that checksum "
474233294Sstas				      "type as the keyed type", ""),
475233294Sstas				    ct->name, crypto->et->name);
476233294Sstas	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
477233294Sstas	}
478233294Sstas
47955682Smarkm	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
480233294Sstas	if (ret)
481233294Sstas	    return ret;
482233294Sstas    } else
48355682Smarkm	dkey = NULL;
48455682Smarkm
485233294Sstas    /*
486233294Sstas     * If checksum have a verify function, lets use that instead of
487233294Sstas     * calling ->checksum and then compare result.
488233294Sstas     */
489233294Sstas
490233294Sstas    if(ct->verify) {
491233294Sstas	ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
492233294Sstas	if (ret)
493233294Sstas	    krb5_set_error_message(context, ret,
494233294Sstas				   N_("Decrypt integrity check failed for checksum "
495233294Sstas				      "type %s, key type %s", ""),
496233294Sstas				   ct->name, (crypto != NULL)? crypto->et->name : "(none)");
497233294Sstas	return ret;
498233294Sstas    }
499233294Sstas
50055682Smarkm    ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
50155682Smarkm    if (ret)
50255682Smarkm	return ret;
50355682Smarkm
504233294Sstas    ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
505233294Sstas    if (ret) {
506233294Sstas	krb5_data_free(&c.checksum);
507233294Sstas	return ret;
508233294Sstas    }
50955682Smarkm
510233294Sstas    if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
51155682Smarkm	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
512233294Sstas	krb5_set_error_message(context, ret,
513233294Sstas			       N_("Decrypt integrity check failed for checksum "
514233294Sstas				  "type %s, key type %s", ""),
515233294Sstas			       ct->name, crypto ? crypto->et->name : "(unkeyed)");
51678536Sassar    } else {
51755682Smarkm	ret = 0;
51878536Sassar    }
51955682Smarkm    krb5_data_free (&c.checksum);
52055682Smarkm    return ret;
52155682Smarkm}
52255682Smarkm
523233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
52455682Smarkmkrb5_verify_checksum(krb5_context context,
52555682Smarkm		     krb5_crypto crypto,
526233294Sstas		     krb5_key_usage usage,
52755682Smarkm		     void *data,
52855682Smarkm		     size_t len,
52955682Smarkm		     Checksum *cksum)
53055682Smarkm{
531233294Sstas    struct _krb5_checksum_type *ct;
532127811Snectar    unsigned keyusage;
533127811Snectar
534233294Sstas    ct = _krb5_find_checksum(cksum->cksumtype);
535127811Snectar    if(ct == NULL) {
536233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
537233294Sstas				N_("checksum type %d not supported", ""),
538233294Sstas				cksum->cksumtype);
539127811Snectar	return KRB5_PROG_SUMTYPE_NOSUPP;
540127811Snectar    }
541127811Snectar
542127811Snectar    if (arcfour_checksum_p(ct, crypto)) {
543127811Snectar	keyusage = usage;
544233294Sstas	_krb5_usage2arcfour(context, &keyusage);
545127811Snectar    } else
546127811Snectar	keyusage = CHECKSUM_USAGE(usage);
547127811Snectar
548127811Snectar    return verify_checksum(context, crypto, keyusage,
549127811Snectar			   data, len, cksum);
55055682Smarkm}
55155682Smarkm
552233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
553178828Sdfrkrb5_crypto_get_checksum_type(krb5_context context,
554178828Sdfr                              krb5_crypto crypto,
555178828Sdfr			      krb5_cksumtype *type)
556178828Sdfr{
557233294Sstas    struct _krb5_checksum_type *ct = NULL;
558233294Sstas
559178828Sdfr    if (crypto != NULL) {
560178828Sdfr        ct = crypto->et->keyed_checksum;
561178828Sdfr        if (ct == NULL)
562178828Sdfr            ct = crypto->et->checksum;
563178828Sdfr    }
564233294Sstas
565178828Sdfr    if (ct == NULL) {
566233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
567233294Sstas				N_("checksum type not found", ""));
568178828Sdfr        return KRB5_PROG_SUMTYPE_NOSUPP;
569233294Sstas    }
570178828Sdfr
571178828Sdfr    *type = ct->type;
572233294Sstas
573233294Sstas    return 0;
574178828Sdfr}
575178828Sdfr
576178828Sdfr
577233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
57855682Smarkmkrb5_checksumsize(krb5_context context,
57955682Smarkm		  krb5_cksumtype type,
58055682Smarkm		  size_t *size)
58155682Smarkm{
582233294Sstas    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
58378536Sassar    if(ct == NULL) {
584233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
585233294Sstas				N_("checksum type %d not supported", ""),
586233294Sstas				type);
58755682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
58878536Sassar    }
58955682Smarkm    *size = ct->checksumsize;
59055682Smarkm    return 0;
59155682Smarkm}
59255682Smarkm
593233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
59455682Smarkmkrb5_checksum_is_keyed(krb5_context context,
59555682Smarkm		       krb5_cksumtype type)
59655682Smarkm{
597233294Sstas    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
59878536Sassar    if(ct == NULL) {
599178828Sdfr	if (context)
600233294Sstas	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
601233294Sstas				    N_("checksum type %d not supported", ""),
602233294Sstas				    type);
60355682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
60478536Sassar    }
60555682Smarkm    return ct->flags & F_KEYED;
60655682Smarkm}
60755682Smarkm
608233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
60955682Smarkmkrb5_checksum_is_collision_proof(krb5_context context,
61055682Smarkm				 krb5_cksumtype type)
61155682Smarkm{
612233294Sstas    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
61378536Sassar    if(ct == NULL) {
614178828Sdfr	if (context)
615233294Sstas	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
616233294Sstas				    N_("checksum type %d not supported", ""),
617233294Sstas				    type);
61855682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
61978536Sassar    }
62055682Smarkm    return ct->flags & F_CPROOF;
62155682Smarkm}
62255682Smarkm
623233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
624178828Sdfrkrb5_checksum_disable(krb5_context context,
625178828Sdfr		      krb5_cksumtype type)
626178828Sdfr{
627233294Sstas    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
628178828Sdfr    if(ct == NULL) {
629178828Sdfr	if (context)
630233294Sstas	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
631233294Sstas				    N_("checksum type %d not supported", ""),
632233294Sstas				    type);
633178828Sdfr	return KRB5_PROG_SUMTYPE_NOSUPP;
634178828Sdfr    }
635178828Sdfr    ct->flags |= F_DISABLED;
636178828Sdfr    return 0;
637178828Sdfr}
638178828Sdfr
63955682Smarkm/************************************************************
64055682Smarkm *                                                          *
64155682Smarkm ************************************************************/
64255682Smarkm
643233294Sstasstruct _krb5_encryption_type *
644233294Sstas_krb5_find_enctype(krb5_enctype type)
64555682Smarkm{
646120948Snectar    int i;
647233294Sstas    for(i = 0; i < _krb5_num_etypes; i++)
648233294Sstas	if(_krb5_etypes[i]->type == type)
649233294Sstas	    return _krb5_etypes[i];
65055682Smarkm    return NULL;
65155682Smarkm}
65255682Smarkm
65355682Smarkm
654233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
65555682Smarkmkrb5_enctype_to_string(krb5_context context,
65655682Smarkm		       krb5_enctype etype,
65755682Smarkm		       char **string)
65855682Smarkm{
659233294Sstas    struct _krb5_encryption_type *e;
660233294Sstas    e = _krb5_find_enctype(etype);
66178536Sassar    if(e == NULL) {
662233294Sstas	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
663233294Sstas				N_("encryption type %d not supported", ""),
664233294Sstas				etype);
665178828Sdfr	*string = NULL;
66655682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
66778536Sassar    }
66855682Smarkm    *string = strdup(e->name);
66978536Sassar    if(*string == NULL) {
670233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
67155682Smarkm	return ENOMEM;
67278536Sassar    }
67355682Smarkm    return 0;
67455682Smarkm}
67555682Smarkm
676233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
67755682Smarkmkrb5_string_to_enctype(krb5_context context,
67855682Smarkm		       const char *string,
67955682Smarkm		       krb5_enctype *etype)
68055682Smarkm{
68155682Smarkm    int i;
682233294Sstas    for(i = 0; i < _krb5_num_etypes; i++)
683233294Sstas	if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
684233294Sstas	    *etype = _krb5_etypes[i]->type;
68555682Smarkm	    return 0;
68655682Smarkm	}
687233294Sstas    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
688233294Sstas			    N_("encryption type %s not supported", ""),
689233294Sstas			    string);
69055682Smarkm    return KRB5_PROG_ETYPE_NOSUPP;
69155682Smarkm}
69255682Smarkm
693233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
69455682Smarkmkrb5_enctype_to_keytype(krb5_context context,
69555682Smarkm			krb5_enctype etype,
69655682Smarkm			krb5_keytype *keytype)
69755682Smarkm{
698233294Sstas    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
69978536Sassar    if(e == NULL) {
700233294Sstas        return unsupported_enctype (context, etype);
70178536Sassar    }
70255682Smarkm    *keytype = e->keytype->type; /* XXX */
70355682Smarkm    return 0;
70455682Smarkm}
70555682Smarkm
706233294Sstas/**
707233294Sstas * Check if a enctype is valid, return 0 if it is.
708233294Sstas *
709233294Sstas * @param context Kerberos context
710233294Sstas * @param etype enctype to check if its valid or not
711233294Sstas *
712233294Sstas * @return Return an error code for an failure or 0 on success (enctype valid).
713233294Sstas * @ingroup krb5_crypto
714233294Sstas */
715233294Sstas
716233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
717233294Sstaskrb5_enctype_valid(krb5_context context,
718233294Sstas		   krb5_enctype etype)
71955682Smarkm{
720233294Sstas    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
721233294Sstas    if(e && (e->flags & F_DISABLED) == 0)
722233294Sstas	return 0;
723233294Sstas    if (context == NULL)
724233294Sstas	return KRB5_PROG_ETYPE_NOSUPP;
725233294Sstas    if(e == NULL) {
726233294Sstas        return unsupported_enctype (context, etype);
72755682Smarkm    }
728233294Sstas    /* Must be (e->flags & F_DISABLED) */
729233294Sstas    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
730233294Sstas			    N_("encryption type %s is disabled", ""),
731233294Sstas			    e->name);
732233294Sstas    return KRB5_PROG_ETYPE_NOSUPP;
73355682Smarkm}
73455682Smarkm
735233294Sstas/**
736233294Sstas * Return the coresponding encryption type for a checksum type.
737233294Sstas *
738233294Sstas * @param context Kerberos context
739233294Sstas * @param ctype The checksum type to get the result enctype for
740233294Sstas * @param etype The returned encryption, when the matching etype is
741233294Sstas * not found, etype is set to ETYPE_NULL.
742233294Sstas *
743233294Sstas * @return Return an error code for an failure or 0 on success.
744233294Sstas * @ingroup krb5_crypto
74555682Smarkm */
74655682Smarkm
747233294Sstas
748233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
749233294Sstaskrb5_cksumtype_to_enctype(krb5_context context,
750233294Sstas			  krb5_cksumtype ctype,
751233294Sstas			  krb5_enctype *etype)
75255682Smarkm{
753233294Sstas    int i;
75455682Smarkm
755233294Sstas    *etype = ETYPE_NULL;
75655682Smarkm
757233294Sstas    for(i = 0; i < _krb5_num_etypes; i++) {
758233294Sstas	if(_krb5_etypes[i]->keyed_checksum &&
759233294Sstas	   _krb5_etypes[i]->keyed_checksum->type == ctype)
760233294Sstas	    {
761233294Sstas		*etype = _krb5_etypes[i]->type;
762233294Sstas		return 0;
763233294Sstas	    }
76478536Sassar    }
76555682Smarkm
766233294Sstas    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
767233294Sstas			    N_("checksum type %d not supported", ""),
768233294Sstas			    (int)ctype);
769233294Sstas    return KRB5_PROG_SUMTYPE_NOSUPP;
77055682Smarkm}
77155682Smarkm
772233294Sstas
773233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
774233294Sstaskrb5_cksumtype_valid(krb5_context context,
775178828Sdfr		     krb5_cksumtype ctype)
776178828Sdfr{
777233294Sstas    struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
778178828Sdfr    if (c == NULL) {
779233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
780233294Sstas				N_("checksum type %d not supported", ""),
781233294Sstas				ctype);
782178828Sdfr	return KRB5_PROG_SUMTYPE_NOSUPP;
783178828Sdfr    }
784178828Sdfr    if (c->flags & F_DISABLED) {
785233294Sstas	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
786233294Sstas				N_("checksum type %s is disabled", ""),
787233294Sstas				c->name);
788178828Sdfr	return KRB5_PROG_SUMTYPE_NOSUPP;
789178828Sdfr    }
790178828Sdfr    return 0;
791178828Sdfr}
792178828Sdfr
793178828Sdfr
79455682Smarkmstatic krb5_boolean
79555682Smarkmderived_crypto(krb5_context context,
79655682Smarkm	       krb5_crypto crypto)
79755682Smarkm{
79855682Smarkm    return (crypto->et->flags & F_DERIVED) != 0;
79955682Smarkm}
80055682Smarkm
80172448Sassarstatic krb5_boolean
80272448Sassarspecial_crypto(krb5_context context,
80372448Sassar	       krb5_crypto crypto)
80472448Sassar{
80572448Sassar    return (crypto->et->flags & F_SPECIAL) != 0;
80672448Sassar}
80755682Smarkm
80855682Smarkm#define CHECKSUMSIZE(C) ((C)->checksumsize)
80955682Smarkm#define CHECKSUMTYPE(C) ((C)->type)
81055682Smarkm
81155682Smarkmstatic krb5_error_code
81255682Smarkmencrypt_internal_derived(krb5_context context,
81355682Smarkm			 krb5_crypto crypto,
81455682Smarkm			 unsigned usage,
815178828Sdfr			 const void *data,
81655682Smarkm			 size_t len,
81772448Sassar			 krb5_data *result,
81872448Sassar			 void *ivec)
81955682Smarkm{
82090929Snectar    size_t sz, block_sz, checksum_sz, total_sz;
82155682Smarkm    Checksum cksum;
82255682Smarkm    unsigned char *p, *q;
82355682Smarkm    krb5_error_code ret;
824233294Sstas    struct _krb5_key_data *dkey;
825233294Sstas    const struct _krb5_encryption_type *et = crypto->et;
826233294Sstas
82755682Smarkm    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
82855682Smarkm
82990929Snectar    sz = et->confoundersize + len;
830120948Snectar    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
83190929Snectar    total_sz = block_sz + checksum_sz;
83290929Snectar    p = calloc(1, total_sz);
83390929Snectar    if(p == NULL) {
834233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
83555682Smarkm	return ENOMEM;
83690929Snectar    }
837233294Sstas
83855682Smarkm    q = p;
83955682Smarkm    krb5_generate_random_block(q, et->confoundersize); /* XXX */
84055682Smarkm    q += et->confoundersize;
84155682Smarkm    memcpy(q, data, len);
842233294Sstas
843233294Sstas    ret = create_checksum(context,
844127811Snectar			  et->keyed_checksum,
845233294Sstas			  crypto,
84655682Smarkm			  INTEGRITY_USAGE(usage),
847233294Sstas			  p,
84855682Smarkm			  block_sz,
84955682Smarkm			  &cksum);
85072448Sassar    if(ret == 0 && cksum.checksum.length != checksum_sz) {
85172448Sassar	free_Checksum (&cksum);
852233294Sstas	krb5_clear_error_message (context);
85372448Sassar	ret = KRB5_CRYPTO_INTERNAL;
85472448Sassar    }
85590929Snectar    if(ret)
85690929Snectar	goto fail;
85755682Smarkm    memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
85872448Sassar    free_Checksum (&cksum);
85955682Smarkm    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
86090929Snectar    if(ret)
86190929Snectar	goto fail;
86255682Smarkm    ret = _key_schedule(context, dkey);
86390929Snectar    if(ret)
86490929Snectar	goto fail;
86590929Snectar    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
86690929Snectar    if (ret)
86790929Snectar	goto fail;
86855682Smarkm    result->data = p;
86990929Snectar    result->length = total_sz;
87055682Smarkm    return 0;
87190929Snectar fail:
87290929Snectar    memset(p, 0, total_sz);
87390929Snectar    free(p);
87490929Snectar    return ret;
87555682Smarkm}
87655682Smarkm
87790929Snectar
87855682Smarkmstatic krb5_error_code
87955682Smarkmencrypt_internal(krb5_context context,
88055682Smarkm		 krb5_crypto crypto,
881178828Sdfr		 const void *data,
88255682Smarkm		 size_t len,
88372448Sassar		 krb5_data *result,
88472448Sassar		 void *ivec)
88555682Smarkm{
88655682Smarkm    size_t sz, block_sz, checksum_sz;
88755682Smarkm    Checksum cksum;
88855682Smarkm    unsigned char *p, *q;
88955682Smarkm    krb5_error_code ret;
890233294Sstas    const struct _krb5_encryption_type *et = crypto->et;
891233294Sstas
89278536Sassar    checksum_sz = CHECKSUMSIZE(et->checksum);
893233294Sstas
89455682Smarkm    sz = et->confoundersize + checksum_sz + len;
895120948Snectar    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
89655682Smarkm    p = calloc(1, block_sz);
89778536Sassar    if(p == NULL) {
898233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
89955682Smarkm	return ENOMEM;
90078536Sassar    }
901233294Sstas
90255682Smarkm    q = p;
90355682Smarkm    krb5_generate_random_block(q, et->confoundersize); /* XXX */
90455682Smarkm    q += et->confoundersize;
90555682Smarkm    memset(q, 0, checksum_sz);
90655682Smarkm    q += checksum_sz;
90755682Smarkm    memcpy(q, data, len);
90855682Smarkm
909233294Sstas    ret = create_checksum(context,
910127811Snectar			  et->checksum,
91178536Sassar			  crypto,
91255682Smarkm			  0,
913233294Sstas			  p,
91455682Smarkm			  block_sz,
91555682Smarkm			  &cksum);
91655682Smarkm    if(ret == 0 && cksum.checksum.length != checksum_sz) {
917233294Sstas	krb5_clear_error_message (context);
91890929Snectar	free_Checksum(&cksum);
91955682Smarkm	ret = KRB5_CRYPTO_INTERNAL;
92055682Smarkm    }
92190929Snectar    if(ret)
92290929Snectar	goto fail;
92355682Smarkm    memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
92455682Smarkm    free_Checksum(&cksum);
92555682Smarkm    ret = _key_schedule(context, &crypto->key);
92690929Snectar    if(ret)
92790929Snectar	goto fail;
92890929Snectar    ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
92990929Snectar    if (ret) {
93055682Smarkm	memset(p, 0, block_sz);
93155682Smarkm	free(p);
93255682Smarkm	return ret;
93355682Smarkm    }
93455682Smarkm    result->data = p;
93555682Smarkm    result->length = block_sz;
93655682Smarkm    return 0;
93790929Snectar fail:
93890929Snectar    memset(p, 0, block_sz);
93990929Snectar    free(p);
94090929Snectar    return ret;
94155682Smarkm}
94255682Smarkm
94355682Smarkmstatic krb5_error_code
94472448Sassarencrypt_internal_special(krb5_context context,
94572448Sassar			 krb5_crypto crypto,
94672448Sassar			 int usage,
947178828Sdfr			 const void *data,
94872448Sassar			 size_t len,
94972448Sassar			 krb5_data *result,
95072448Sassar			 void *ivec)
95172448Sassar{
952233294Sstas    struct _krb5_encryption_type *et = crypto->et;
95378536Sassar    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
95472448Sassar    size_t sz = len + cksum_sz + et->confoundersize;
95572448Sassar    char *tmp, *p;
95690929Snectar    krb5_error_code ret;
95772448Sassar
95872448Sassar    tmp = malloc (sz);
95978536Sassar    if (tmp == NULL) {
960233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
96172448Sassar	return ENOMEM;
96278536Sassar    }
96372448Sassar    p = tmp;
96472448Sassar    memset (p, 0, cksum_sz);
96572448Sassar    p += cksum_sz;
96672448Sassar    krb5_generate_random_block(p, et->confoundersize);
96772448Sassar    p += et->confoundersize;
96872448Sassar    memcpy (p, data, len);
96990929Snectar    ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
97090929Snectar    if (ret) {
97190929Snectar	memset(tmp, 0, sz);
97290929Snectar	free(tmp);
97390929Snectar	return ret;
97490929Snectar    }
97572448Sassar    result->data   = tmp;
97672448Sassar    result->length = sz;
97772448Sassar    return 0;
97872448Sassar}
97972448Sassar
98072448Sassarstatic krb5_error_code
98155682Smarkmdecrypt_internal_derived(krb5_context context,
98255682Smarkm			 krb5_crypto crypto,
98355682Smarkm			 unsigned usage,
98455682Smarkm			 void *data,
98555682Smarkm			 size_t len,
98672448Sassar			 krb5_data *result,
98772448Sassar			 void *ivec)
98855682Smarkm{
98955682Smarkm    size_t checksum_sz;
99055682Smarkm    Checksum cksum;
99155682Smarkm    unsigned char *p;
99255682Smarkm    krb5_error_code ret;
993233294Sstas    struct _krb5_key_data *dkey;
994233294Sstas    struct _krb5_encryption_type *et = crypto->et;
99555682Smarkm    unsigned long l;
996233294Sstas
99772448Sassar    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
998178828Sdfr    if (len < checksum_sz + et->confoundersize) {
999233294Sstas	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1000233294Sstas			       N_("Encrypted data shorter then "
1001233294Sstas				  "checksum + confunder", ""));
1002178828Sdfr	return KRB5_BAD_MSIZE;
100378536Sassar    }
100472448Sassar
1005127811Snectar    if (((len - checksum_sz) % et->padsize) != 0) {
1006233294Sstas	krb5_clear_error_message(context);
1007127811Snectar	return KRB5_BAD_MSIZE;
1008127811Snectar    }
1009127811Snectar
101055682Smarkm    p = malloc(len);
101178536Sassar    if(len != 0 && p == NULL) {
1012233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
101355682Smarkm	return ENOMEM;
101478536Sassar    }
101555682Smarkm    memcpy(p, data, len);
101655682Smarkm
101755682Smarkm    len -= checksum_sz;
101855682Smarkm
101955682Smarkm    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
102055682Smarkm    if(ret) {
102155682Smarkm	free(p);
102255682Smarkm	return ret;
102355682Smarkm    }
102455682Smarkm    ret = _key_schedule(context, dkey);
102555682Smarkm    if(ret) {
102655682Smarkm	free(p);
102755682Smarkm	return ret;
102855682Smarkm    }
102990929Snectar    ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
103090929Snectar    if (ret) {
103190929Snectar	free(p);
103290929Snectar	return ret;
103390929Snectar    }
103455682Smarkm
103555682Smarkm    cksum.checksum.data   = p + len;
103655682Smarkm    cksum.checksum.length = checksum_sz;
103755682Smarkm    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
103855682Smarkm
103955682Smarkm    ret = verify_checksum(context,
104055682Smarkm			  crypto,
104155682Smarkm			  INTEGRITY_USAGE(usage),
104255682Smarkm			  p,
104355682Smarkm			  len,
104455682Smarkm			  &cksum);
104555682Smarkm    if(ret) {
104655682Smarkm	free(p);
104755682Smarkm	return ret;
104855682Smarkm    }
104955682Smarkm    l = len - et->confoundersize;
105055682Smarkm    memmove(p, p + et->confoundersize, l);
105155682Smarkm    result->data = realloc(p, l);
1052178828Sdfr    if(result->data == NULL && l != 0) {
105355682Smarkm	free(p);
1054233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
105555682Smarkm	return ENOMEM;
105655682Smarkm    }
105755682Smarkm    result->length = l;
105855682Smarkm    return 0;
105955682Smarkm}
106055682Smarkm
106155682Smarkmstatic krb5_error_code
106255682Smarkmdecrypt_internal(krb5_context context,
106355682Smarkm		 krb5_crypto crypto,
106455682Smarkm		 void *data,
106555682Smarkm		 size_t len,
106672448Sassar		 krb5_data *result,
106772448Sassar		 void *ivec)
106855682Smarkm{
106955682Smarkm    krb5_error_code ret;
107055682Smarkm    unsigned char *p;
107155682Smarkm    Checksum cksum;
107255682Smarkm    size_t checksum_sz, l;
1073233294Sstas    struct _krb5_encryption_type *et = crypto->et;
1074233294Sstas
1075127811Snectar    if ((len % et->padsize) != 0) {
1076233294Sstas	krb5_clear_error_message(context);
1077127811Snectar	return KRB5_BAD_MSIZE;
1078127811Snectar    }
1079233294Sstas    checksum_sz = CHECKSUMSIZE(et->checksum);
1080233294Sstas    if (len < checksum_sz + et->confoundersize) {
1081233294Sstas	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1082233294Sstas			       N_("Encrypted data shorter then "
1083233294Sstas				  "checksum + confunder", ""));
1084233294Sstas	return KRB5_BAD_MSIZE;
1085233294Sstas    }
1086127811Snectar
108755682Smarkm    p = malloc(len);
108878536Sassar    if(len != 0 && p == NULL) {
1089233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
109055682Smarkm	return ENOMEM;
109178536Sassar    }
109255682Smarkm    memcpy(p, data, len);
1093233294Sstas
109455682Smarkm    ret = _key_schedule(context, &crypto->key);
109555682Smarkm    if(ret) {
109655682Smarkm	free(p);
109755682Smarkm	return ret;
109855682Smarkm    }
109990929Snectar    ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
110090929Snectar    if (ret) {
110190929Snectar	free(p);
110290929Snectar	return ret;
110390929Snectar    }
110455682Smarkm    ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
110555682Smarkm    if(ret) {
110672448Sassar 	free(p);
110772448Sassar 	return ret;
110855682Smarkm    }
110955682Smarkm    memset(p + et->confoundersize, 0, checksum_sz);
111078536Sassar    cksum.cksumtype = CHECKSUMTYPE(et->checksum);
111155682Smarkm    ret = verify_checksum(context, NULL, 0, p, len, &cksum);
111255682Smarkm    free_Checksum(&cksum);
111355682Smarkm    if(ret) {
111455682Smarkm	free(p);
111555682Smarkm	return ret;
111655682Smarkm    }
111755682Smarkm    l = len - et->confoundersize - checksum_sz;
111855682Smarkm    memmove(p, p + et->confoundersize + checksum_sz, l);
111955682Smarkm    result->data = realloc(p, l);
1120178828Sdfr    if(result->data == NULL && l != 0) {
112155682Smarkm	free(p);
1122233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
112355682Smarkm	return ENOMEM;
112455682Smarkm    }
112555682Smarkm    result->length = l;
112655682Smarkm    return 0;
112755682Smarkm}
112855682Smarkm
112972448Sassarstatic krb5_error_code
113072448Sassardecrypt_internal_special(krb5_context context,
113172448Sassar			 krb5_crypto crypto,
113272448Sassar			 int usage,
113372448Sassar			 void *data,
113472448Sassar			 size_t len,
113572448Sassar			 krb5_data *result,
113672448Sassar			 void *ivec)
113772448Sassar{
1138233294Sstas    struct _krb5_encryption_type *et = crypto->et;
113978536Sassar    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
114072448Sassar    size_t sz = len - cksum_sz - et->confoundersize;
1141127811Snectar    unsigned char *p;
114290929Snectar    krb5_error_code ret;
114372448Sassar
1144127811Snectar    if ((len % et->padsize) != 0) {
1145233294Sstas	krb5_clear_error_message(context);
1146127811Snectar	return KRB5_BAD_MSIZE;
1147127811Snectar    }
1148233294Sstas    if (len < cksum_sz + et->confoundersize) {
1149233294Sstas	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1150233294Sstas			       N_("Encrypted data shorter then "
1151233294Sstas				  "checksum + confunder", ""));
1152233294Sstas	return KRB5_BAD_MSIZE;
1153233294Sstas    }
1154127811Snectar
1155127811Snectar    p = malloc (len);
1156127811Snectar    if (p == NULL) {
1157233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
115872448Sassar	return ENOMEM;
115978536Sassar    }
1160127811Snectar    memcpy(p, data, len);
1161233294Sstas
1162127811Snectar    ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
116390929Snectar    if (ret) {
1164127811Snectar	free(p);
116590929Snectar	return ret;
116690929Snectar    }
116772448Sassar
1168127811Snectar    memmove (p, p + cksum_sz + et->confoundersize, sz);
1169127811Snectar    result->data = realloc(p, sz);
1170178828Sdfr    if(result->data == NULL && sz != 0) {
1171127811Snectar	free(p);
1172233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1173127811Snectar	return ENOMEM;
1174127811Snectar    }
117572448Sassar    result->length = sz;
117672448Sassar    return 0;
117772448Sassar}
117872448Sassar
1179233294Sstasstatic krb5_crypto_iov *
1180233294Sstasfind_iv(krb5_crypto_iov *data, size_t num_data, unsigned type)
1181233294Sstas{
1182233294Sstas    size_t i;
1183233294Sstas    for (i = 0; i < num_data; i++)
1184233294Sstas	if (data[i].flags == type)
1185233294Sstas	    return &data[i];
1186233294Sstas    return NULL;
1187233294Sstas}
118872448Sassar
1189233294Sstas/**
1190233294Sstas * Inline encrypt a kerberos message
1191233294Sstas *
1192233294Sstas * @param context Kerberos context
1193233294Sstas * @param crypto Kerberos crypto context
1194233294Sstas * @param usage Key usage for this buffer
1195233294Sstas * @param data array of buffers to process
1196233294Sstas * @param num_data length of array
1197233294Sstas * @param ivec initial cbc/cts vector
1198233294Sstas *
1199233294Sstas * @return Return an error code or 0.
1200233294Sstas * @ingroup krb5_crypto
1201233294Sstas *
1202233294Sstas * Kerberos encrypted data look like this:
1203233294Sstas *
1204233294Sstas * 1. KRB5_CRYPTO_TYPE_HEADER
1205233294Sstas * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1206233294Sstas *    KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1207233294Sstas *    have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1208233294Sstas *    commonly used headers and trailers.
1209233294Sstas * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1210233294Sstas * 4. KRB5_CRYPTO_TYPE_TRAILER
1211233294Sstas */
1212233294Sstas
1213233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1214233294Sstaskrb5_encrypt_iov_ivec(krb5_context context,
1215233294Sstas		      krb5_crypto crypto,
1216233294Sstas		      unsigned usage,
1217233294Sstas		      krb5_crypto_iov *data,
1218233294Sstas		      int num_data,
1219233294Sstas		      void *ivec)
1220233294Sstas{
1221233294Sstas    size_t headersz, trailersz, len;
1222233294Sstas    int i;
1223233294Sstas    size_t sz, block_sz, pad_sz;
1224233294Sstas    Checksum cksum;
1225233294Sstas    unsigned char *p, *q;
1226233294Sstas    krb5_error_code ret;
1227233294Sstas    struct _krb5_key_data *dkey;
1228233294Sstas    const struct _krb5_encryption_type *et = crypto->et;
1229233294Sstas    krb5_crypto_iov *tiv, *piv, *hiv;
1230233294Sstas
1231233294Sstas    if (num_data < 0) {
1232233294Sstas        krb5_clear_error_message(context);
1233233294Sstas	return KRB5_CRYPTO_INTERNAL;
1234233294Sstas    }
1235233294Sstas
1236233294Sstas    if(!derived_crypto(context, crypto)) {
1237233294Sstas	krb5_clear_error_message(context);
1238233294Sstas	return KRB5_CRYPTO_INTERNAL;
1239233294Sstas    }
1240233294Sstas
1241233294Sstas    headersz = et->confoundersize;
1242233294Sstas    trailersz = CHECKSUMSIZE(et->keyed_checksum);
1243233294Sstas
1244233294Sstas    for (len = 0, i = 0; i < num_data; i++) {
1245233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1246233294Sstas	    continue;
1247233294Sstas	len += data[i].data.length;
1248233294Sstas    }
1249233294Sstas
1250233294Sstas    sz = headersz + len;
1251233294Sstas    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1252233294Sstas
1253233294Sstas    pad_sz = block_sz - sz;
1254233294Sstas
1255233294Sstas    /* header */
1256233294Sstas
1257233294Sstas    hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1258233294Sstas    if (hiv == NULL || hiv->data.length != headersz)
1259233294Sstas	return KRB5_BAD_MSIZE;
1260233294Sstas
1261233294Sstas    krb5_generate_random_block(hiv->data.data, hiv->data.length);
1262233294Sstas
1263233294Sstas    /* padding */
1264233294Sstas    piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1265233294Sstas    /* its ok to have no TYPE_PADDING if there is no padding */
1266233294Sstas    if (piv == NULL && pad_sz != 0)
1267233294Sstas	return KRB5_BAD_MSIZE;
1268233294Sstas    if (piv) {
1269233294Sstas	if (piv->data.length < pad_sz)
1270233294Sstas	    return KRB5_BAD_MSIZE;
1271233294Sstas	piv->data.length = pad_sz;
1272233294Sstas	if (pad_sz)
1273233294Sstas	    memset(piv->data.data, pad_sz, pad_sz);
1274233294Sstas	else
1275233294Sstas	    piv = NULL;
1276233294Sstas    }
1277233294Sstas
1278233294Sstas    /* trailer */
1279233294Sstas    tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1280233294Sstas    if (tiv == NULL || tiv->data.length != trailersz)
1281233294Sstas	return KRB5_BAD_MSIZE;
1282233294Sstas
1283233294Sstas    /*
1284233294Sstas     * XXX replace with EVP_Sign? at least make create_checksum an iov
1285233294Sstas     * function.
1286233294Sstas     * XXX CTS EVP is broken, can't handle multi buffers :(
1287233294Sstas     */
1288233294Sstas
1289233294Sstas    len = block_sz;
1290233294Sstas    for (i = 0; i < num_data; i++) {
1291233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1292233294Sstas	    continue;
1293233294Sstas	len += data[i].data.length;
1294233294Sstas    }
1295233294Sstas
1296233294Sstas    p = q = malloc(len);
1297233294Sstas
1298233294Sstas    memcpy(q, hiv->data.data, hiv->data.length);
1299233294Sstas    q += hiv->data.length;
1300233294Sstas    for (i = 0; i < num_data; i++) {
1301233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1302233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1303233294Sstas	    continue;
1304233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1305233294Sstas	q += data[i].data.length;
1306233294Sstas    }
1307233294Sstas    if (piv)
1308233294Sstas	memset(q, 0, piv->data.length);
1309233294Sstas
1310233294Sstas    ret = create_checksum(context,
1311233294Sstas			  et->keyed_checksum,
1312233294Sstas			  crypto,
1313233294Sstas			  INTEGRITY_USAGE(usage),
1314233294Sstas			  p,
1315233294Sstas			  len,
1316233294Sstas			  &cksum);
1317233294Sstas    free(p);
1318233294Sstas    if(ret == 0 && cksum.checksum.length != trailersz) {
1319233294Sstas	free_Checksum (&cksum);
1320233294Sstas	krb5_clear_error_message (context);
1321233294Sstas	ret = KRB5_CRYPTO_INTERNAL;
1322233294Sstas    }
1323233294Sstas    if(ret)
1324233294Sstas	return ret;
1325233294Sstas
1326233294Sstas    /* save cksum at end */
1327233294Sstas    memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1328233294Sstas    free_Checksum (&cksum);
1329233294Sstas
1330233294Sstas    /* XXX replace with EVP_Cipher */
1331233294Sstas    p = q = malloc(block_sz);
1332233294Sstas    if(p == NULL)
1333233294Sstas	return ENOMEM;
1334233294Sstas
1335233294Sstas    memcpy(q, hiv->data.data, hiv->data.length);
1336233294Sstas    q += hiv->data.length;
1337233294Sstas
1338233294Sstas    for (i = 0; i < num_data; i++) {
1339233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1340233294Sstas	    continue;
1341233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1342233294Sstas	q += data[i].data.length;
1343233294Sstas    }
1344233294Sstas    if (piv)
1345233294Sstas	memset(q, 0, piv->data.length);
1346233294Sstas
1347233294Sstas
1348233294Sstas    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1349233294Sstas    if(ret) {
1350233294Sstas	free(p);
1351233294Sstas	return ret;
1352233294Sstas    }
1353233294Sstas    ret = _key_schedule(context, dkey);
1354233294Sstas    if(ret) {
1355233294Sstas	free(p);
1356233294Sstas	return ret;
1357233294Sstas    }
1358233294Sstas
1359233294Sstas    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1360233294Sstas    if (ret) {
1361233294Sstas	free(p);
1362233294Sstas	return ret;
1363233294Sstas    }
1364233294Sstas
1365233294Sstas    /* now copy data back to buffers */
1366233294Sstas    q = p;
1367233294Sstas
1368233294Sstas    memcpy(hiv->data.data, q, hiv->data.length);
1369233294Sstas    q += hiv->data.length;
1370233294Sstas
1371233294Sstas    for (i = 0; i < num_data; i++) {
1372233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1373233294Sstas	    continue;
1374233294Sstas	memcpy(data[i].data.data, q, data[i].data.length);
1375233294Sstas	q += data[i].data.length;
1376233294Sstas    }
1377233294Sstas    if (piv)
1378233294Sstas	memcpy(piv->data.data, q, pad_sz);
1379233294Sstas
1380233294Sstas    free(p);
1381233294Sstas
1382233294Sstas    return ret;
1383233294Sstas}
1384233294Sstas
1385233294Sstas/**
1386233294Sstas * Inline decrypt a Kerberos message.
1387233294Sstas *
1388233294Sstas * @param context Kerberos context
1389233294Sstas * @param crypto Kerberos crypto context
1390233294Sstas * @param usage Key usage for this buffer
1391233294Sstas * @param data array of buffers to process
1392233294Sstas * @param num_data length of array
1393233294Sstas * @param ivec initial cbc/cts vector
1394233294Sstas *
1395233294Sstas * @return Return an error code or 0.
1396233294Sstas * @ingroup krb5_crypto
1397233294Sstas *
1398233294Sstas * 1. KRB5_CRYPTO_TYPE_HEADER
1399233294Sstas * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1400233294Sstas *  any order, however the receiver have to aware of the
1401233294Sstas *  order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1402233294Sstas *  protocol headers and trailers. The output data will be of same
1403233294Sstas *  size as the input data or shorter.
1404233294Sstas */
1405233294Sstas
1406233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1407233294Sstaskrb5_decrypt_iov_ivec(krb5_context context,
1408233294Sstas		      krb5_crypto crypto,
1409233294Sstas		      unsigned usage,
1410233294Sstas		      krb5_crypto_iov *data,
1411233294Sstas		      unsigned int num_data,
1412233294Sstas		      void *ivec)
1413233294Sstas{
1414233294Sstas    unsigned int i;
1415233294Sstas    size_t headersz, trailersz, len;
1416233294Sstas    Checksum cksum;
1417233294Sstas    unsigned char *p, *q;
1418233294Sstas    krb5_error_code ret;
1419233294Sstas    struct _krb5_key_data *dkey;
1420233294Sstas    struct _krb5_encryption_type *et = crypto->et;
1421233294Sstas    krb5_crypto_iov *tiv, *hiv;
1422233294Sstas
1423233294Sstas    if(!derived_crypto(context, crypto)) {
1424233294Sstas	krb5_clear_error_message(context);
1425233294Sstas	return KRB5_CRYPTO_INTERNAL;
1426233294Sstas    }
1427233294Sstas
1428233294Sstas    headersz = et->confoundersize;
1429233294Sstas
1430233294Sstas    hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1431233294Sstas    if (hiv == NULL || hiv->data.length != headersz)
1432233294Sstas	return KRB5_BAD_MSIZE;
1433233294Sstas
1434233294Sstas    /* trailer */
1435233294Sstas    trailersz = CHECKSUMSIZE(et->keyed_checksum);
1436233294Sstas
1437233294Sstas    tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1438233294Sstas    if (tiv->data.length != trailersz)
1439233294Sstas	return KRB5_BAD_MSIZE;
1440233294Sstas
1441233294Sstas    /* Find length of data we will decrypt */
1442233294Sstas
1443233294Sstas    len = headersz;
1444233294Sstas    for (i = 0; i < num_data; i++) {
1445233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1446233294Sstas	    continue;
1447233294Sstas	len += data[i].data.length;
1448233294Sstas    }
1449233294Sstas
1450233294Sstas    if ((len % et->padsize) != 0) {
1451233294Sstas	krb5_clear_error_message(context);
1452233294Sstas	return KRB5_BAD_MSIZE;
1453233294Sstas    }
1454233294Sstas
1455233294Sstas    /* XXX replace with EVP_Cipher */
1456233294Sstas
1457233294Sstas    p = q = malloc(len);
1458233294Sstas    if (p == NULL)
1459233294Sstas	return ENOMEM;
1460233294Sstas
1461233294Sstas    memcpy(q, hiv->data.data, hiv->data.length);
1462233294Sstas    q += hiv->data.length;
1463233294Sstas
1464233294Sstas    for (i = 0; i < num_data; i++) {
1465233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1466233294Sstas	    continue;
1467233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1468233294Sstas	q += data[i].data.length;
1469233294Sstas    }
1470233294Sstas
1471233294Sstas    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1472233294Sstas    if(ret) {
1473233294Sstas	free(p);
1474233294Sstas	return ret;
1475233294Sstas    }
1476233294Sstas    ret = _key_schedule(context, dkey);
1477233294Sstas    if(ret) {
1478233294Sstas	free(p);
1479233294Sstas	return ret;
1480233294Sstas    }
1481233294Sstas
1482233294Sstas    ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1483233294Sstas    if (ret) {
1484233294Sstas	free(p);
1485233294Sstas	return ret;
1486233294Sstas    }
1487233294Sstas
1488233294Sstas    /* copy data back to buffers */
1489233294Sstas    memcpy(hiv->data.data, p, hiv->data.length);
1490233294Sstas    q = p + hiv->data.length;
1491233294Sstas    for (i = 0; i < num_data; i++) {
1492233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1493233294Sstas	    continue;
1494233294Sstas	memcpy(data[i].data.data, q, data[i].data.length);
1495233294Sstas	q += data[i].data.length;
1496233294Sstas    }
1497233294Sstas
1498233294Sstas    free(p);
1499233294Sstas
1500233294Sstas    /* check signature */
1501233294Sstas    for (i = 0; i < num_data; i++) {
1502233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1503233294Sstas	    continue;
1504233294Sstas	len += data[i].data.length;
1505233294Sstas    }
1506233294Sstas
1507233294Sstas    p = q = malloc(len);
1508233294Sstas    if (p == NULL)
1509233294Sstas	return ENOMEM;
1510233294Sstas
1511233294Sstas    memcpy(q, hiv->data.data, hiv->data.length);
1512233294Sstas    q += hiv->data.length;
1513233294Sstas    for (i = 0; i < num_data; i++) {
1514233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1515233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1516233294Sstas	    continue;
1517233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1518233294Sstas	q += data[i].data.length;
1519233294Sstas    }
1520233294Sstas
1521233294Sstas    cksum.checksum.data   = tiv->data.data;
1522233294Sstas    cksum.checksum.length = tiv->data.length;
1523233294Sstas    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1524233294Sstas
1525233294Sstas    ret = verify_checksum(context,
1526233294Sstas			  crypto,
1527233294Sstas			  INTEGRITY_USAGE(usage),
1528233294Sstas			  p,
1529233294Sstas			  len,
1530233294Sstas			  &cksum);
1531233294Sstas    free(p);
1532233294Sstas    return ret;
1533233294Sstas}
1534233294Sstas
1535233294Sstas/**
1536233294Sstas * Create a Kerberos message checksum.
1537233294Sstas *
1538233294Sstas * @param context Kerberos context
1539233294Sstas * @param crypto Kerberos crypto context
1540233294Sstas * @param usage Key usage for this buffer
1541233294Sstas * @param data array of buffers to process
1542233294Sstas * @param num_data length of array
1543233294Sstas * @param type output data
1544233294Sstas *
1545233294Sstas * @return Return an error code or 0.
1546233294Sstas * @ingroup krb5_crypto
1547233294Sstas */
1548233294Sstas
1549233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1550233294Sstaskrb5_create_checksum_iov(krb5_context context,
1551233294Sstas			 krb5_crypto crypto,
1552233294Sstas			 unsigned usage,
1553233294Sstas			 krb5_crypto_iov *data,
1554233294Sstas			 unsigned int num_data,
1555233294Sstas			 krb5_cksumtype *type)
1556233294Sstas{
1557233294Sstas    Checksum cksum;
1558233294Sstas    krb5_crypto_iov *civ;
1559233294Sstas    krb5_error_code ret;
1560233294Sstas    size_t i;
1561233294Sstas    size_t len;
1562233294Sstas    char *p, *q;
1563233294Sstas
1564233294Sstas    if(!derived_crypto(context, crypto)) {
1565233294Sstas	krb5_clear_error_message(context);
1566233294Sstas	return KRB5_CRYPTO_INTERNAL;
1567233294Sstas    }
1568233294Sstas
1569233294Sstas    civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1570233294Sstas    if (civ == NULL)
1571233294Sstas	return KRB5_BAD_MSIZE;
1572233294Sstas
1573233294Sstas    len = 0;
1574233294Sstas    for (i = 0; i < num_data; i++) {
1575233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1576233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1577233294Sstas	    continue;
1578233294Sstas	len += data[i].data.length;
1579233294Sstas    }
1580233294Sstas
1581233294Sstas    p = q = malloc(len);
1582233294Sstas
1583233294Sstas    for (i = 0; i < num_data; i++) {
1584233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1585233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1586233294Sstas	    continue;
1587233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1588233294Sstas	q += data[i].data.length;
1589233294Sstas    }
1590233294Sstas
1591233294Sstas    ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1592233294Sstas    free(p);
1593233294Sstas    if (ret)
1594233294Sstas	return ret;
1595233294Sstas
1596233294Sstas    if (type)
1597233294Sstas	*type = cksum.cksumtype;
1598233294Sstas
1599233294Sstas    if (cksum.checksum.length > civ->data.length) {
1600233294Sstas	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1601233294Sstas			       N_("Checksum larger then input buffer", ""));
1602233294Sstas	free_Checksum(&cksum);
1603233294Sstas	return KRB5_BAD_MSIZE;
1604233294Sstas    }
1605233294Sstas
1606233294Sstas    civ->data.length = cksum.checksum.length;
1607233294Sstas    memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1608233294Sstas    free_Checksum(&cksum);
1609233294Sstas
1610233294Sstas    return 0;
1611233294Sstas}
1612233294Sstas
1613233294Sstas/**
1614233294Sstas * Verify a Kerberos message checksum.
1615233294Sstas *
1616233294Sstas * @param context Kerberos context
1617233294Sstas * @param crypto Kerberos crypto context
1618233294Sstas * @param usage Key usage for this buffer
1619233294Sstas * @param data array of buffers to process
1620233294Sstas * @param num_data length of array
1621233294Sstas * @param type return checksum type if not NULL
1622233294Sstas *
1623233294Sstas * @return Return an error code or 0.
1624233294Sstas * @ingroup krb5_crypto
1625233294Sstas */
1626233294Sstas
1627233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1628233294Sstaskrb5_verify_checksum_iov(krb5_context context,
1629233294Sstas			 krb5_crypto crypto,
1630233294Sstas			 unsigned usage,
1631233294Sstas			 krb5_crypto_iov *data,
1632233294Sstas			 unsigned int num_data,
1633233294Sstas			 krb5_cksumtype *type)
1634233294Sstas{
1635233294Sstas    struct _krb5_encryption_type *et = crypto->et;
1636233294Sstas    Checksum cksum;
1637233294Sstas    krb5_crypto_iov *civ;
1638233294Sstas    krb5_error_code ret;
1639233294Sstas    size_t i;
1640233294Sstas    size_t len;
1641233294Sstas    char *p, *q;
1642233294Sstas
1643233294Sstas    if(!derived_crypto(context, crypto)) {
1644233294Sstas	krb5_clear_error_message(context);
1645233294Sstas	return KRB5_CRYPTO_INTERNAL;
1646233294Sstas    }
1647233294Sstas
1648233294Sstas    civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1649233294Sstas    if (civ == NULL)
1650233294Sstas	return KRB5_BAD_MSIZE;
1651233294Sstas
1652233294Sstas    len = 0;
1653233294Sstas    for (i = 0; i < num_data; i++) {
1654233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1655233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1656233294Sstas	    continue;
1657233294Sstas	len += data[i].data.length;
1658233294Sstas    }
1659233294Sstas
1660233294Sstas    p = q = malloc(len);
1661233294Sstas
1662233294Sstas    for (i = 0; i < num_data; i++) {
1663233294Sstas	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1664233294Sstas	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1665233294Sstas	    continue;
1666233294Sstas	memcpy(q, data[i].data.data, data[i].data.length);
1667233294Sstas	q += data[i].data.length;
1668233294Sstas    }
1669233294Sstas
1670233294Sstas    cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1671233294Sstas    cksum.checksum.length = civ->data.length;
1672233294Sstas    cksum.checksum.data = civ->data.data;
1673233294Sstas
1674233294Sstas    ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1675233294Sstas    free(p);
1676233294Sstas
1677233294Sstas    if (ret == 0 && type)
1678233294Sstas	*type = cksum.cksumtype;
1679233294Sstas
1680233294Sstas    return ret;
1681233294Sstas}
1682233294Sstas
1683233294Sstas
1684233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1685233294Sstaskrb5_crypto_length(krb5_context context,
1686233294Sstas		   krb5_crypto crypto,
1687233294Sstas		   int type,
1688233294Sstas		   size_t *len)
1689233294Sstas{
1690233294Sstas    if (!derived_crypto(context, crypto)) {
1691233294Sstas	krb5_set_error_message(context, EINVAL, "not a derived crypto");
1692233294Sstas	return EINVAL;
1693233294Sstas    }
1694233294Sstas
1695233294Sstas    switch(type) {
1696233294Sstas    case KRB5_CRYPTO_TYPE_EMPTY:
1697233294Sstas	*len = 0;
1698233294Sstas	return 0;
1699233294Sstas    case KRB5_CRYPTO_TYPE_HEADER:
1700233294Sstas	*len = crypto->et->blocksize;
1701233294Sstas	return 0;
1702233294Sstas    case KRB5_CRYPTO_TYPE_DATA:
1703233294Sstas    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1704233294Sstas	/* len must already been filled in */
1705233294Sstas	return 0;
1706233294Sstas    case KRB5_CRYPTO_TYPE_PADDING:
1707233294Sstas	if (crypto->et->padsize > 1)
1708233294Sstas	    *len = crypto->et->padsize;
1709233294Sstas	else
1710233294Sstas	    *len = 0;
1711233294Sstas	return 0;
1712233294Sstas    case KRB5_CRYPTO_TYPE_TRAILER:
1713233294Sstas	*len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1714233294Sstas	return 0;
1715233294Sstas    case KRB5_CRYPTO_TYPE_CHECKSUM:
1716233294Sstas	if (crypto->et->keyed_checksum)
1717233294Sstas	    *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1718233294Sstas	else
1719233294Sstas	    *len = CHECKSUMSIZE(crypto->et->checksum);
1720233294Sstas	return 0;
1721233294Sstas    }
1722233294Sstas    krb5_set_error_message(context, EINVAL,
1723233294Sstas			   "%d not a supported type", type);
1724233294Sstas    return EINVAL;
1725233294Sstas}
1726233294Sstas
1727233294Sstas
1728233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1729233294Sstaskrb5_crypto_length_iov(krb5_context context,
1730233294Sstas		       krb5_crypto crypto,
1731233294Sstas		       krb5_crypto_iov *data,
1732233294Sstas		       unsigned int num_data)
1733233294Sstas{
1734233294Sstas    krb5_error_code ret;
1735233294Sstas    size_t i;
1736233294Sstas
1737233294Sstas    for (i = 0; i < num_data; i++) {
1738233294Sstas	ret = krb5_crypto_length(context, crypto,
1739233294Sstas				 data[i].flags,
1740233294Sstas				 &data[i].data.length);
1741233294Sstas	if (ret)
1742233294Sstas	    return ret;
1743233294Sstas    }
1744233294Sstas    return 0;
1745233294Sstas}
1746233294Sstas
1747233294Sstas
1748233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
174972448Sassarkrb5_encrypt_ivec(krb5_context context,
175072448Sassar		  krb5_crypto crypto,
175172448Sassar		  unsigned usage,
1752178828Sdfr		  const void *data,
175372448Sassar		  size_t len,
175472448Sassar		  krb5_data *result,
175572448Sassar		  void *ivec)
175672448Sassar{
175772448Sassar    if(derived_crypto(context, crypto))
1758233294Sstas	return encrypt_internal_derived(context, crypto, usage,
175972448Sassar					data, len, result, ivec);
176072448Sassar    else if (special_crypto(context, crypto))
176172448Sassar	return encrypt_internal_special (context, crypto, usage,
176272448Sassar					 data, len, result, ivec);
176372448Sassar    else
176472448Sassar	return encrypt_internal(context, crypto, data, len, result, ivec);
176572448Sassar}
176672448Sassar
1767233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
176855682Smarkmkrb5_encrypt(krb5_context context,
176955682Smarkm	     krb5_crypto crypto,
177055682Smarkm	     unsigned usage,
1771178828Sdfr	     const void *data,
177255682Smarkm	     size_t len,
177355682Smarkm	     krb5_data *result)
177455682Smarkm{
177572448Sassar    return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
177655682Smarkm}
177755682Smarkm
1778233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
177955682Smarkmkrb5_encrypt_EncryptedData(krb5_context context,
178055682Smarkm			   krb5_crypto crypto,
178155682Smarkm			   unsigned usage,
178255682Smarkm			   void *data,
178355682Smarkm			   size_t len,
178455682Smarkm			   int kvno,
178555682Smarkm			   EncryptedData *result)
178655682Smarkm{
178755682Smarkm    result->etype = CRYPTO_ETYPE(crypto);
178855682Smarkm    if(kvno){
178955682Smarkm	ALLOC(result->kvno, 1);
179055682Smarkm	*result->kvno = kvno;
179155682Smarkm    }else
179255682Smarkm	result->kvno = NULL;
179355682Smarkm    return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
179455682Smarkm}
179555682Smarkm
1796233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
179772448Sassarkrb5_decrypt_ivec(krb5_context context,
179872448Sassar		  krb5_crypto crypto,
179972448Sassar		  unsigned usage,
180072448Sassar		  void *data,
180172448Sassar		  size_t len,
180272448Sassar		  krb5_data *result,
180372448Sassar		  void *ivec)
180472448Sassar{
180572448Sassar    if(derived_crypto(context, crypto))
1806233294Sstas	return decrypt_internal_derived(context, crypto, usage,
180772448Sassar					data, len, result, ivec);
180872448Sassar    else if (special_crypto (context, crypto))
180972448Sassar	return decrypt_internal_special(context, crypto, usage,
181072448Sassar					data, len, result, ivec);
181172448Sassar    else
181272448Sassar	return decrypt_internal(context, crypto, data, len, result, ivec);
181372448Sassar}
181472448Sassar
1815233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
181655682Smarkmkrb5_decrypt(krb5_context context,
181755682Smarkm	     krb5_crypto crypto,
181855682Smarkm	     unsigned usage,
181955682Smarkm	     void *data,
182055682Smarkm	     size_t len,
182155682Smarkm	     krb5_data *result)
182255682Smarkm{
182372448Sassar    return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
182472448Sassar			      NULL);
182555682Smarkm}
182655682Smarkm
1827233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
182855682Smarkmkrb5_decrypt_EncryptedData(krb5_context context,
182955682Smarkm			   krb5_crypto crypto,
183055682Smarkm			   unsigned usage,
183172448Sassar			   const EncryptedData *e,
183255682Smarkm			   krb5_data *result)
183355682Smarkm{
1834233294Sstas    return krb5_decrypt(context, crypto, usage,
183555682Smarkm			e->cipher.data, e->cipher.length, result);
183655682Smarkm}
183755682Smarkm
183855682Smarkm/************************************************************
183955682Smarkm *                                                          *
184055682Smarkm ************************************************************/
184155682Smarkm
1842233294Sstaskrb5_error_code
1843233294Sstas_krb5_derive_key(krb5_context context,
1844233294Sstas		 struct _krb5_encryption_type *et,
1845233294Sstas		 struct _krb5_key_data *key,
1846233294Sstas		 const void *constant,
1847233294Sstas		 size_t len)
184878536Sassar{
1849233294Sstas    unsigned char *k = NULL;
185055682Smarkm    unsigned int nblocks = 0, i;
185155682Smarkm    krb5_error_code ret = 0;
1852233294Sstas    struct _krb5_key_type *kt = et->keytype;
1853178828Sdfr
185455682Smarkm    ret = _key_schedule(context, key);
185555682Smarkm    if(ret)
185655682Smarkm	return ret;
1857178828Sdfr    if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
185855682Smarkm	nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
185955682Smarkm	k = malloc(nblocks * et->blocksize);
186078536Sassar	if(k == NULL) {
1861233294Sstas	    ret = ENOMEM;
1862233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1863233294Sstas	    goto out;
186478536Sassar	}
1865178828Sdfr	ret = _krb5_n_fold(constant, len, k, et->blocksize);
1866178828Sdfr	if (ret) {
1867233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1868233294Sstas	    goto out;
1869178828Sdfr	}
1870233294Sstas
187155682Smarkm	for(i = 0; i < nblocks; i++) {
187255682Smarkm	    if(i > 0)
1873233294Sstas		memcpy(k + i * et->blocksize,
187455682Smarkm		       k + (i - 1) * et->blocksize,
187555682Smarkm		       et->blocksize);
187678536Sassar	    (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
187778536Sassar			   1, 0, NULL);
187855682Smarkm	}
187955682Smarkm    } else {
188072448Sassar	/* this case is probably broken, but won't be run anyway */
188155682Smarkm	void *c = malloc(len);
188255682Smarkm	size_t res_len = (kt->bits + 7) / 8;
188355682Smarkm
188478536Sassar	if(len != 0 && c == NULL) {
1885233294Sstas	    ret = ENOMEM;
1886233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1887233294Sstas	    goto out;
188878536Sassar	}
188955682Smarkm	memcpy(c, constant, len);
189078536Sassar	(*et->encrypt)(context, key, c, len, 1, 0, NULL);
189155682Smarkm	k = malloc(res_len);
189278536Sassar	if(res_len != 0 && k == NULL) {
189378536Sassar	    free(c);
1894233294Sstas	    ret = ENOMEM;
1895233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1896233294Sstas	    goto out;
189778536Sassar	}
1898178828Sdfr	ret = _krb5_n_fold(c, len, k, res_len);
1899233294Sstas	free(c);
1900178828Sdfr	if (ret) {
1901233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1902233294Sstas	    goto out;
1903178828Sdfr	}
190455682Smarkm    }
1905233294Sstas
190655682Smarkm    /* XXX keytype dependent post-processing */
190755682Smarkm    switch(kt->type) {
1908233294Sstas    case ETYPE_OLD_DES3_CBC_SHA1:
1909233294Sstas	_krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
191055682Smarkm	break;
1911233294Sstas    case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
1912233294Sstas    case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
1913120948Snectar	memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
1914120948Snectar	break;
191555682Smarkm    default:
191655682Smarkm	ret = KRB5_CRYPTO_INTERNAL;
1917233294Sstas	krb5_set_error_message(context, ret,
1918233294Sstas			       N_("derive_key() called with unknown keytype (%u)", ""),
1919233294Sstas			       kt->type);
192055682Smarkm	break;
192155682Smarkm    }
1922233294Sstas out:
1923178828Sdfr    if (key->schedule) {
1924233294Sstas	free_key_schedule(context, key, et);
1925178828Sdfr	key->schedule = NULL;
1926178828Sdfr    }
1927233294Sstas    if (k) {
1928233294Sstas	memset(k, 0, nblocks * et->blocksize);
1929233294Sstas	free(k);
1930233294Sstas    }
193155682Smarkm    return ret;
193255682Smarkm}
193355682Smarkm
1934233294Sstasstatic struct _krb5_key_data *
193555682Smarkm_new_derived_key(krb5_crypto crypto, unsigned usage)
193655682Smarkm{
1937233294Sstas    struct _krb5_key_usage *d = crypto->key_usage;
193855682Smarkm    d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
193955682Smarkm    if(d == NULL)
194055682Smarkm	return NULL;
194155682Smarkm    crypto->key_usage = d;
194255682Smarkm    d += crypto->num_key_usage++;
194355682Smarkm    memset(d, 0, sizeof(*d));
194455682Smarkm    d->usage = usage;
194555682Smarkm    return &d->key;
194655682Smarkm}
194755682Smarkm
1948233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
194978536Sassarkrb5_derive_key(krb5_context context,
195078536Sassar		const krb5_keyblock *key,
195178536Sassar		krb5_enctype etype,
195278536Sassar		const void *constant,
195378536Sassar		size_t constant_len,
195478536Sassar		krb5_keyblock **derived_key)
195578536Sassar{
195678536Sassar    krb5_error_code ret;
1957233294Sstas    struct _krb5_encryption_type *et;
1958233294Sstas    struct _krb5_key_data d;
195978536Sassar
1960178828Sdfr    *derived_key = NULL;
1961178828Sdfr
1962233294Sstas    et = _krb5_find_enctype (etype);
196378536Sassar    if (et == NULL) {
1964233294Sstas        return unsupported_enctype (context, etype);
196578536Sassar    }
196678536Sassar
1967178828Sdfr    ret = krb5_copy_keyblock(context, key, &d.key);
196878536Sassar    if (ret)
196978536Sassar	return ret;
197078536Sassar
197178536Sassar    d.schedule = NULL;
1972233294Sstas    ret = _krb5_derive_key(context, et, &d, constant, constant_len);
1973178828Sdfr    if (ret == 0)
1974178828Sdfr	ret = krb5_copy_keyblock(context, d.key, derived_key);
1975233294Sstas    _krb5_free_key_data(context, &d, et);
197678536Sassar    return ret;
197778536Sassar}
197878536Sassar
197955682Smarkmstatic krb5_error_code
1980233294Sstas_get_derived_key(krb5_context context,
1981233294Sstas		 krb5_crypto crypto,
1982233294Sstas		 unsigned usage,
1983233294Sstas		 struct _krb5_key_data **key)
198455682Smarkm{
198555682Smarkm    int i;
1986233294Sstas    struct _krb5_key_data *d;
198755682Smarkm    unsigned char constant[5];
198855682Smarkm
198955682Smarkm    for(i = 0; i < crypto->num_key_usage; i++)
199055682Smarkm	if(crypto->key_usage[i].usage == usage) {
199155682Smarkm	    *key = &crypto->key_usage[i].key;
199255682Smarkm	    return 0;
199355682Smarkm	}
199455682Smarkm    d = _new_derived_key(crypto, usage);
199578536Sassar    if(d == NULL) {
1996233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
199755682Smarkm	return ENOMEM;
199878536Sassar    }
199955682Smarkm    krb5_copy_keyblock(context, crypto->key.key, &d->key);
200055682Smarkm    _krb5_put_int(constant, usage, 5);
2001233294Sstas    _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
200255682Smarkm    *key = d;
200355682Smarkm    return 0;
200455682Smarkm}
200555682Smarkm
2006233294Sstas/**
2007233294Sstas * Create a crypto context used for all encryption and signature
2008233294Sstas * operation. The encryption type to use is taken from the key, but
2009233294Sstas * can be overridden with the enctype parameter.  This can be useful
2010233294Sstas * for encryptions types which is compatiable (DES for example).
2011233294Sstas *
2012233294Sstas * To free the crypto context, use krb5_crypto_destroy().
2013233294Sstas *
2014233294Sstas * @param context Kerberos context
2015233294Sstas * @param key the key block information with all key data
2016233294Sstas * @param etype the encryption type
2017233294Sstas * @param crypto the resulting crypto context
2018233294Sstas *
2019233294Sstas * @return Return an error code or 0.
2020233294Sstas *
2021233294Sstas * @ingroup krb5_crypto
2022233294Sstas */
202355682Smarkm
2024233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
202555682Smarkmkrb5_crypto_init(krb5_context context,
202678536Sassar		 const krb5_keyblock *key,
202755682Smarkm		 krb5_enctype etype,
202855682Smarkm		 krb5_crypto *crypto)
202955682Smarkm{
203055682Smarkm    krb5_error_code ret;
203155682Smarkm    ALLOC(*crypto, 1);
203278536Sassar    if(*crypto == NULL) {
2033233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
203455682Smarkm	return ENOMEM;
203578536Sassar    }
203655682Smarkm    if(etype == ETYPE_NULL)
203755682Smarkm	etype = key->keytype;
2038233294Sstas    (*crypto)->et = _krb5_find_enctype(etype);
2039178828Sdfr    if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
204055682Smarkm	free(*crypto);
2041178828Sdfr	*crypto = NULL;
2042233294Sstas	return unsupported_enctype(context, etype);
204355682Smarkm    }
2044102647Snectar    if((*crypto)->et->keytype->size != key->keyvalue.length) {
2045102647Snectar	free(*crypto);
2046178828Sdfr	*crypto = NULL;
2047233294Sstas	krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2048233294Sstas				"encryption key has bad length");
2049102647Snectar	return KRB5_BAD_KEYSIZE;
2050102647Snectar    }
205155682Smarkm    ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
205255682Smarkm    if(ret) {
205355682Smarkm	free(*crypto);
2054178828Sdfr	*crypto = NULL;
205555682Smarkm	return ret;
205655682Smarkm    }
205755682Smarkm    (*crypto)->key.schedule = NULL;
205855682Smarkm    (*crypto)->num_key_usage = 0;
205955682Smarkm    (*crypto)->key_usage = NULL;
206055682Smarkm    return 0;
206155682Smarkm}
206255682Smarkm
206355682Smarkmstatic void
2064233294Sstasfree_key_schedule(krb5_context context,
2065233294Sstas		  struct _krb5_key_data *key,
2066233294Sstas		  struct _krb5_encryption_type *et)
206755682Smarkm{
2068233294Sstas    if (et->keytype->cleanup)
2069233294Sstas	(*et->keytype->cleanup)(context, key);
2070233294Sstas    memset(key->schedule->data, 0, key->schedule->length);
2071233294Sstas    krb5_free_data(context, key->schedule);
2072233294Sstas}
2073233294Sstas
2074233294Sstasvoid
2075233294Sstas_krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2076233294Sstas	      struct _krb5_encryption_type *et)
2077233294Sstas{
207855682Smarkm    krb5_free_keyblock(context, key->key);
207955682Smarkm    if(key->schedule) {
2080233294Sstas	free_key_schedule(context, key, et);
2081233294Sstas	key->schedule = NULL;
208255682Smarkm    }
208355682Smarkm}
208455682Smarkm
208555682Smarkmstatic void
2086233294Sstasfree_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2087233294Sstas	       struct _krb5_encryption_type *et)
208855682Smarkm{
2089233294Sstas    _krb5_free_key_data(context, &ku->key, et);
209055682Smarkm}
209155682Smarkm
2092233294Sstas/**
2093233294Sstas * Free a crypto context created by krb5_crypto_init().
2094233294Sstas *
2095233294Sstas * @param context Kerberos context
2096233294Sstas * @param crypto crypto context to free
2097233294Sstas *
2098233294Sstas * @return Return an error code or 0.
2099233294Sstas *
2100233294Sstas * @ingroup krb5_crypto
2101233294Sstas */
2102233294Sstas
2103233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
210455682Smarkmkrb5_crypto_destroy(krb5_context context,
210555682Smarkm		    krb5_crypto crypto)
210655682Smarkm{
210755682Smarkm    int i;
2108233294Sstas
210955682Smarkm    for(i = 0; i < crypto->num_key_usage; i++)
2110233294Sstas	free_key_usage(context, &crypto->key_usage[i], crypto->et);
211155682Smarkm    free(crypto->key_usage);
2112233294Sstas    _krb5_free_key_data(context, &crypto->key, crypto->et);
211355682Smarkm    free (crypto);
211455682Smarkm    return 0;
211555682Smarkm}
211655682Smarkm
2117233294Sstas/**
2118233294Sstas * Return the blocksize used algorithm referenced by the crypto context
2119233294Sstas *
2120233294Sstas * @param context Kerberos context
2121233294Sstas * @param crypto crypto context to query
2122233294Sstas * @param blocksize the resulting blocksize
2123233294Sstas *
2124233294Sstas * @return Return an error code or 0.
2125233294Sstas *
2126233294Sstas * @ingroup krb5_crypto
2127233294Sstas */
2128233294Sstas
2129233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2130103426Snectarkrb5_crypto_getblocksize(krb5_context context,
2131103426Snectar			 krb5_crypto crypto,
2132103426Snectar			 size_t *blocksize)
2133103426Snectar{
2134103426Snectar    *blocksize = crypto->et->blocksize;
2135103426Snectar    return 0;
2136103426Snectar}
2137103426Snectar
2138233294Sstas/**
2139233294Sstas * Return the encryption type used by the crypto context
2140233294Sstas *
2141233294Sstas * @param context Kerberos context
2142233294Sstas * @param crypto crypto context to query
2143233294Sstas * @param enctype the resulting encryption type
2144233294Sstas *
2145233294Sstas * @return Return an error code or 0.
2146233294Sstas *
2147233294Sstas * @ingroup krb5_crypto
2148233294Sstas */
2149233294Sstas
2150233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2151178828Sdfrkrb5_crypto_getenctype(krb5_context context,
2152178828Sdfr		       krb5_crypto crypto,
2153178828Sdfr		       krb5_enctype *enctype)
2154178828Sdfr{
2155178828Sdfr    *enctype = crypto->et->type;
2156233294Sstas    return 0;
2157178828Sdfr}
2158178828Sdfr
2159233294Sstas/**
2160233294Sstas * Return the padding size used by the crypto context
2161233294Sstas *
2162233294Sstas * @param context Kerberos context
2163233294Sstas * @param crypto crypto context to query
2164233294Sstas * @param padsize the return padding size
2165233294Sstas *
2166233294Sstas * @return Return an error code or 0.
2167233294Sstas *
2168233294Sstas * @ingroup krb5_crypto
2169233294Sstas */
2170233294Sstas
2171233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2172178828Sdfrkrb5_crypto_getpadsize(krb5_context context,
2173178828Sdfr                       krb5_crypto crypto,
2174233294Sstas                       size_t *padsize)
2175178828Sdfr{
2176178828Sdfr    *padsize = crypto->et->padsize;
2177178828Sdfr    return 0;
2178178828Sdfr}
2179178828Sdfr
2180233294Sstas/**
2181233294Sstas * Return the confounder size used by the crypto context
2182233294Sstas *
2183233294Sstas * @param context Kerberos context
2184233294Sstas * @param crypto crypto context to query
2185233294Sstas * @param confoundersize the returned confounder size
2186233294Sstas *
2187233294Sstas * @return Return an error code or 0.
2188233294Sstas *
2189233294Sstas * @ingroup krb5_crypto
2190233294Sstas */
2191233294Sstas
2192233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2193178828Sdfrkrb5_crypto_getconfoundersize(krb5_context context,
2194178828Sdfr                              krb5_crypto crypto,
2195178828Sdfr                              size_t *confoundersize)
2196178828Sdfr{
2197178828Sdfr    *confoundersize = crypto->et->confoundersize;
2198178828Sdfr    return 0;
2199178828Sdfr}
2200178828Sdfr
2201233294Sstas
2202233294Sstas/**
2203233294Sstas * Disable encryption type
2204233294Sstas *
2205233294Sstas * @param context Kerberos 5 context
2206233294Sstas * @param enctype encryption type to disable
2207233294Sstas *
2208233294Sstas * @return Return an error code or 0.
2209233294Sstas *
2210233294Sstas * @ingroup krb5_crypto
2211233294Sstas */
2212233294Sstas
2213233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2214178828Sdfrkrb5_enctype_disable(krb5_context context,
2215178828Sdfr		     krb5_enctype enctype)
2216178828Sdfr{
2217233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2218178828Sdfr    if(et == NULL) {
2219178828Sdfr	if (context)
2220233294Sstas	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2221233294Sstas				    N_("encryption type %d not supported", ""),
2222233294Sstas				    enctype);
2223178828Sdfr	return KRB5_PROG_ETYPE_NOSUPP;
2224178828Sdfr    }
2225178828Sdfr    et->flags |= F_DISABLED;
2226178828Sdfr    return 0;
2227178828Sdfr}
2228178828Sdfr
2229233294Sstas/**
2230233294Sstas * Enable encryption type
2231233294Sstas *
2232233294Sstas * @param context Kerberos 5 context
2233233294Sstas * @param enctype encryption type to enable
2234233294Sstas *
2235233294Sstas * @return Return an error code or 0.
2236233294Sstas *
2237233294Sstas * @ingroup krb5_crypto
2238233294Sstas */
2239233294Sstas
2240233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2241233294Sstaskrb5_enctype_enable(krb5_context context,
2242233294Sstas		    krb5_enctype enctype)
224355682Smarkm{
2244233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
224578536Sassar    if(et == NULL) {
2246233294Sstas	if (context)
2247233294Sstas	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2248233294Sstas				    N_("encryption type %d not supported", ""),
2249233294Sstas				    enctype);
225055682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
225178536Sassar    }
2252233294Sstas    et->flags &= ~F_DISABLED;
2253233294Sstas    return 0;
2254233294Sstas}
2255178828Sdfr
2256233294Sstas/**
2257233294Sstas * Enable or disable all weak encryption types
2258233294Sstas *
2259233294Sstas * @param context Kerberos 5 context
2260233294Sstas * @param enable true to enable, false to disable
2261233294Sstas *
2262233294Sstas * @return Return an error code or 0.
2263233294Sstas *
2264233294Sstas * @ingroup krb5_crypto
2265233294Sstas */
2266233294Sstas
2267233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2268233294Sstaskrb5_allow_weak_crypto(krb5_context context,
2269233294Sstas		       krb5_boolean enable)
2270233294Sstas{
2271233294Sstas    int i;
2272233294Sstas
2273233294Sstas    for(i = 0; i < _krb5_num_etypes; i++)
2274233294Sstas	if(_krb5_etypes[i]->flags & F_WEAK) {
2275233294Sstas	    if(enable)
2276233294Sstas		_krb5_etypes[i]->flags &= ~F_DISABLED;
2277233294Sstas	    else
2278233294Sstas		_krb5_etypes[i]->flags |= F_DISABLED;
2279233294Sstas	}
2280233294Sstas    return 0;
228155682Smarkm}
228255682Smarkm
228372448Sassarstatic size_t
228472448Sassarwrapped_length (krb5_context context,
228572448Sassar		krb5_crypto  crypto,
228672448Sassar		size_t       data_len)
228772448Sassar{
2288233294Sstas    struct _krb5_encryption_type *et = crypto->et;
2289120948Snectar    size_t padsize = et->padsize;
2290178828Sdfr    size_t checksumsize = CHECKSUMSIZE(et->checksum);
229172448Sassar    size_t res;
229272448Sassar
2293178828Sdfr    res =  et->confoundersize + checksumsize + data_len;
2294120948Snectar    res =  (res + padsize - 1) / padsize * padsize;
229572448Sassar    return res;
229672448Sassar}
229772448Sassar
229872448Sassarstatic size_t
229972448Sassarwrapped_length_dervied (krb5_context context,
230072448Sassar			krb5_crypto  crypto,
230172448Sassar			size_t       data_len)
230272448Sassar{
2303233294Sstas    struct _krb5_encryption_type *et = crypto->et;
2304120948Snectar    size_t padsize = et->padsize;
230572448Sassar    size_t res;
230672448Sassar
230772448Sassar    res =  et->confoundersize + data_len;
2308120948Snectar    res =  (res + padsize - 1) / padsize * padsize;
2309178828Sdfr    if (et->keyed_checksum)
2310178828Sdfr	res += et->keyed_checksum->checksumsize;
2311178828Sdfr    else
2312178828Sdfr	res += et->checksum->checksumsize;
231372448Sassar    return res;
231472448Sassar}
231572448Sassar
231655682Smarkm/*
231755682Smarkm * Return the size of an encrypted packet of length `data_len'
231855682Smarkm */
231955682Smarkm
2320233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
232155682Smarkmkrb5_get_wrapped_length (krb5_context context,
232255682Smarkm			 krb5_crypto  crypto,
232355682Smarkm			 size_t       data_len)
232455682Smarkm{
232572448Sassar    if (derived_crypto (context, crypto))
232672448Sassar	return wrapped_length_dervied (context, crypto, data_len);
232772448Sassar    else
232872448Sassar	return wrapped_length (context, crypto, data_len);
232955682Smarkm}
233055682Smarkm
2331178828Sdfr/*
2332178828Sdfr * Return the size of an encrypted packet of length `data_len'
2333178828Sdfr */
2334178828Sdfr
2335178828Sdfrstatic size_t
2336178828Sdfrcrypto_overhead (krb5_context context,
2337178828Sdfr		 krb5_crypto  crypto)
2338178828Sdfr{
2339233294Sstas    struct _krb5_encryption_type *et = crypto->et;
2340178828Sdfr    size_t res;
2341178828Sdfr
2342178828Sdfr    res = CHECKSUMSIZE(et->checksum);
2343178828Sdfr    res += et->confoundersize;
2344178828Sdfr    if (et->padsize > 1)
2345178828Sdfr	res += et->padsize;
2346178828Sdfr    return res;
2347178828Sdfr}
2348178828Sdfr
2349178828Sdfrstatic size_t
2350178828Sdfrcrypto_overhead_dervied (krb5_context context,
2351178828Sdfr			 krb5_crypto  crypto)
2352178828Sdfr{
2353233294Sstas    struct _krb5_encryption_type *et = crypto->et;
2354178828Sdfr    size_t res;
2355178828Sdfr
2356178828Sdfr    if (et->keyed_checksum)
2357178828Sdfr	res = CHECKSUMSIZE(et->keyed_checksum);
2358178828Sdfr    else
2359178828Sdfr	res = CHECKSUMSIZE(et->checksum);
2360178828Sdfr    res += et->confoundersize;
2361178828Sdfr    if (et->padsize > 1)
2362178828Sdfr	res += et->padsize;
2363178828Sdfr    return res;
2364178828Sdfr}
2365178828Sdfr
2366233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2367178828Sdfrkrb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2368178828Sdfr{
2369178828Sdfr    if (derived_crypto (context, crypto))
2370178828Sdfr	return crypto_overhead_dervied (context, crypto);
2371178828Sdfr    else
2372178828Sdfr	return crypto_overhead (context, crypto);
2373178828Sdfr}
2374178828Sdfr
2375233294Sstas/**
2376233294Sstas * Converts the random bytestring to a protocol key according to
2377233294Sstas * Kerberos crypto frame work. It may be assumed that all the bits of
2378233294Sstas * the input string are equally random, even though the entropy
2379233294Sstas * present in the random source may be limited.
2380233294Sstas *
2381233294Sstas * @param context Kerberos 5 context
2382233294Sstas * @param type the enctype resulting key will be of
2383233294Sstas * @param data input random data to convert to a key
2384233294Sstas * @param size size of input random data, at least krb5_enctype_keysize() long
2385233294Sstas * @param key key, output key, free with krb5_free_keyblock_contents()
2386233294Sstas *
2387233294Sstas * @return Return an error code or 0.
2388233294Sstas *
2389233294Sstas * @ingroup krb5_crypto
2390233294Sstas */
2391233294Sstas
2392233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2393178828Sdfrkrb5_random_to_key(krb5_context context,
2394178828Sdfr		   krb5_enctype type,
2395178828Sdfr		   const void *data,
2396178828Sdfr		   size_t size,
2397178828Sdfr		   krb5_keyblock *key)
2398178828Sdfr{
2399178828Sdfr    krb5_error_code ret;
2400233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2401178828Sdfr    if(et == NULL) {
2402233294Sstas	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2403233294Sstas			       N_("encryption type %d not supported", ""),
2404233294Sstas			       type);
2405178828Sdfr	return KRB5_PROG_ETYPE_NOSUPP;
2406178828Sdfr    }
2407178828Sdfr    if ((et->keytype->bits + 7) / 8 > size) {
2408233294Sstas	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2409233294Sstas			       N_("encryption key %s needs %d bytes "
2410233294Sstas				  "of random to make an encryption key "
2411233294Sstas				  "out of it", ""),
2412233294Sstas			       et->name, (int)et->keytype->size);
2413178828Sdfr	return KRB5_PROG_ETYPE_NOSUPP;
2414178828Sdfr    }
2415178828Sdfr    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2416233294Sstas    if(ret)
2417178828Sdfr	return ret;
2418178828Sdfr    key->keytype = type;
2419178828Sdfr    if (et->keytype->random_to_key)
2420178828Sdfr 	(*et->keytype->random_to_key)(context, key, data, size);
2421178828Sdfr    else
2422178828Sdfr	memcpy(key->keyvalue.data, data, et->keytype->size);
2423178828Sdfr
2424178828Sdfr    return 0;
2425178828Sdfr}
2426178828Sdfr
2427178828Sdfr
2428178828Sdfr
2429233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2430178828Sdfrkrb5_crypto_prf_length(krb5_context context,
2431178828Sdfr		       krb5_enctype type,
2432178828Sdfr		       size_t *length)
2433178828Sdfr{
2434233294Sstas    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2435178828Sdfr
2436178828Sdfr    if(et == NULL || et->prf_length == 0) {
2437233294Sstas	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2438233294Sstas			       N_("encryption type %d not supported", ""),
2439233294Sstas			       type);
2440178828Sdfr	return KRB5_PROG_ETYPE_NOSUPP;
2441178828Sdfr    }
2442178828Sdfr
2443178828Sdfr    *length = et->prf_length;
2444178828Sdfr    return 0;
2445178828Sdfr}
2446178828Sdfr
2447233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2448178828Sdfrkrb5_crypto_prf(krb5_context context,
2449178828Sdfr		const krb5_crypto crypto,
2450233294Sstas		const krb5_data *input,
2451178828Sdfr		krb5_data *output)
2452178828Sdfr{
2453233294Sstas    struct _krb5_encryption_type *et = crypto->et;
2454178828Sdfr
2455178828Sdfr    krb5_data_zero(output);
2456178828Sdfr
2457178828Sdfr    if(et->prf == NULL) {
2458233294Sstas	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2459233294Sstas			       "kerberos prf for %s not supported",
2460233294Sstas			       et->name);
2461178828Sdfr	return KRB5_PROG_ETYPE_NOSUPP;
2462178828Sdfr    }
2463178828Sdfr
2464178828Sdfr    return (*et->prf)(context, crypto, input, output);
2465178828Sdfr}
2466178828Sdfr
2467233294Sstasstatic krb5_error_code
2468233294Sstaskrb5_crypto_prfplus(krb5_context context,
2469233294Sstas		    const krb5_crypto crypto,
2470233294Sstas		    const krb5_data *input,
2471233294Sstas		    size_t length,
2472233294Sstas		    krb5_data *output)
2473233294Sstas{
2474233294Sstas    krb5_error_code ret;
2475233294Sstas    krb5_data input2;
2476233294Sstas    unsigned char i = 1;
2477233294Sstas    unsigned char *p;
2478178828Sdfr
2479233294Sstas    krb5_data_zero(&input2);
2480233294Sstas    krb5_data_zero(output);
2481178828Sdfr
2482233294Sstas    krb5_clear_error_message(context);
248355682Smarkm
2484233294Sstas    ret = krb5_data_alloc(output, length);
2485233294Sstas    if (ret) goto out;
2486233294Sstas    ret = krb5_data_alloc(&input2, input->length + 1);
2487233294Sstas    if (ret) goto out;
248857416Smarkm
2489233294Sstas    krb5_clear_error_message(context);
2490233294Sstas
2491233294Sstas    memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2492233294Sstas
2493233294Sstas    p = output->data;
2494233294Sstas
2495233294Sstas    while (length) {
2496233294Sstas	krb5_data block;
2497233294Sstas
2498233294Sstas	((unsigned char *)input2.data)[0] = i++;
2499233294Sstas
2500233294Sstas	ret = krb5_crypto_prf(context, crypto, &input2, &block);
2501233294Sstas	if (ret)
2502233294Sstas	    goto out;
2503233294Sstas
2504233294Sstas	if (block.length < length) {
2505233294Sstas	    memcpy(p, block.data, block.length);
2506233294Sstas	    length -= block.length;
2507233294Sstas	} else {
2508233294Sstas	    memcpy(p, block.data, length);
2509233294Sstas	    length = 0;
2510233294Sstas	}
2511233294Sstas	p += block.length;
2512233294Sstas	krb5_data_free(&block);
2513233294Sstas    }
2514233294Sstas
2515233294Sstas out:
2516233294Sstas    krb5_data_free(&input2);
2517233294Sstas    if (ret)
2518233294Sstas	krb5_data_free(output);
251955682Smarkm    return 0;
252055682Smarkm}
252155682Smarkm
2522233294Sstas/**
2523233294Sstas * The FX-CF2 key derivation function, used in FAST and preauth framework.
2524233294Sstas *
2525233294Sstas * @param context Kerberos 5 context
2526233294Sstas * @param crypto1 first key to combine
2527233294Sstas * @param crypto2 second key to combine
2528233294Sstas * @param pepper1 factor to combine with first key to garante uniqueness
2529233294Sstas * @param pepper2 factor to combine with second key to garante uniqueness
2530233294Sstas * @param enctype the encryption type of the resulting key
2531233294Sstas * @param res allocated key, free with krb5_free_keyblock_contents()
2532233294Sstas *
2533233294Sstas * @return Return an error code or 0.
2534233294Sstas *
2535233294Sstas * @ingroup krb5_crypto
2536233294Sstas */
253755682Smarkm
2538233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2539233294Sstaskrb5_crypto_fx_cf2(krb5_context context,
2540233294Sstas		   const krb5_crypto crypto1,
2541233294Sstas		   const krb5_crypto crypto2,
2542233294Sstas		   krb5_data *pepper1,
2543233294Sstas		   krb5_data *pepper2,
2544233294Sstas		   krb5_enctype enctype,
2545233294Sstas		   krb5_keyblock *res)
254672448Sassar{
254772448Sassar    krb5_error_code ret;
2548233294Sstas    krb5_data os1, os2;
2549233294Sstas    size_t i, keysize;
255072448Sassar
2551233294Sstas    memset(res, 0, sizeof(*res));
2552233294Sstas
2553233294Sstas    ret = krb5_enctype_keysize(context, enctype, &keysize);
255472448Sassar    if (ret)
2555233294Sstas	return ret;
255672448Sassar
2557233294Sstas    ret = krb5_data_alloc(&res->keyvalue, keysize);
2558233294Sstas    if (ret)
2559233294Sstas	goto out;
2560233294Sstas    ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2561233294Sstas    if (ret)
2562233294Sstas	goto out;
2563233294Sstas    ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2564233294Sstas    if (ret)
2565233294Sstas	goto out;
256672448Sassar
2567233294Sstas    res->keytype = enctype;
2568233294Sstas    {
2569233294Sstas	unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data;
2570233294Sstas	for (i = 0; i < keysize; i++)
2571233294Sstas	    p3[i] = p1[i] ^ p2[i];
2572233294Sstas    }
2573233294Sstas out:
2574233294Sstas    if (ret)
2575233294Sstas	krb5_data_free(&res->keyvalue);
2576233294Sstas    krb5_data_free(&os1);
2577233294Sstas    krb5_data_free(&os2);
257872448Sassar
2579233294Sstas    return ret;
2580233294Sstas}
258172448Sassar
258272448Sassar
258372448Sassar
2584233294Sstas#ifndef HEIMDAL_SMALLER
258572448Sassar
2586233294Sstas/**
2587233294Sstas * Deprecated: keytypes doesn't exists, they are really enctypes.
2588233294Sstas *
2589233294Sstas * @ingroup krb5_deprecated
2590233294Sstas */
259172448Sassar
2592233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2593233294Sstaskrb5_keytype_to_enctypes (krb5_context context,
2594233294Sstas			  krb5_keytype keytype,
2595233294Sstas			  unsigned *len,
2596233294Sstas			  krb5_enctype **val)
2597233294Sstas    KRB5_DEPRECATED_FUNCTION("Use X instead")
2598233294Sstas{
2599233294Sstas    int i;
2600233294Sstas    unsigned n = 0;
2601233294Sstas    krb5_enctype *ret;
2602233294Sstas
2603233294Sstas    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2604233294Sstas	if (_krb5_etypes[i]->keytype->type == keytype
2605233294Sstas	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2606233294Sstas	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2607233294Sstas	    ++n;
2608233294Sstas    }
2609233294Sstas    if (n == 0) {
2610233294Sstas	krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
2611233294Sstas			       "Keytype have no mapping");
2612233294Sstas	return KRB5_PROG_KEYTYPE_NOSUPP;
2613233294Sstas    }
2614233294Sstas
2615233294Sstas    ret = malloc(n * sizeof(*ret));
2616233294Sstas    if (ret == NULL && n != 0) {
2617233294Sstas	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2618233294Sstas	return ENOMEM;
2619233294Sstas    }
2620233294Sstas    n = 0;
2621233294Sstas    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2622233294Sstas	if (_krb5_etypes[i]->keytype->type == keytype
2623233294Sstas	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2624233294Sstas	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2625233294Sstas	    ret[n++] = _krb5_etypes[i]->type;
2626233294Sstas    }
2627233294Sstas    *len = n;
2628233294Sstas    *val = ret;
262972448Sassar    return 0;
263072448Sassar}
2631233294Sstas
2632233294Sstas/**
2633233294Sstas * Deprecated: keytypes doesn't exists, they are really enctypes.
2634233294Sstas *
2635233294Sstas * @ingroup krb5_deprecated
2636233294Sstas */
2637233294Sstas
2638233294Sstas/* if two enctypes have compatible keys */
2639233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2640233294Sstaskrb5_enctypes_compatible_keys(krb5_context context,
2641233294Sstas			      krb5_enctype etype1,
2642233294Sstas			      krb5_enctype etype2)
2643233294Sstas    KRB5_DEPRECATED_FUNCTION("Use X instead")
2644233294Sstas{
2645233294Sstas    struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
2646233294Sstas    struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
2647233294Sstas    return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2648233294Sstas}
2649233294Sstas
2650233294Sstas#endif /* HEIMDAL_SMALLER */
2651