1*d3273b5bSchristos /* $NetBSD: crypto.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "krb5_locl.h"
37ca1c9b0cSelric
38ca1c9b0cSelric struct _krb5_key_usage {
39ca1c9b0cSelric unsigned usage;
40ca1c9b0cSelric struct _krb5_key_data key;
41ca1c9b0cSelric };
42ca1c9b0cSelric
43ca1c9b0cSelric
44ca1c9b0cSelric #ifndef HEIMDAL_SMALLER
45ca1c9b0cSelric #define DES3_OLD_ENCTYPE 1
46ca1c9b0cSelric #endif
47ca1c9b0cSelric
48ca1c9b0cSelric static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
49ca1c9b0cSelric unsigned, struct _krb5_key_data**);
50ca1c9b0cSelric static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
51ca1c9b0cSelric
52ca1c9b0cSelric static void free_key_schedule(krb5_context,
53ca1c9b0cSelric struct _krb5_key_data *,
54ca1c9b0cSelric struct _krb5_encryption_type *);
55ca1c9b0cSelric
564f77a458Spettai /*
574f77a458Spettai * Converts etype to a user readable string and sets as a side effect
584f77a458Spettai * the krb5_error_message containing this string. Returns
594f77a458Spettai * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
604f77a458Spettai * which case the error code of the etype convesion is returned.
614f77a458Spettai */
624f77a458Spettai
634f77a458Spettai static krb5_error_code
unsupported_enctype(krb5_context context,krb5_enctype etype)644f77a458Spettai unsupported_enctype(krb5_context context, krb5_enctype etype)
654f77a458Spettai {
664f77a458Spettai krb5_error_code ret;
674f77a458Spettai char *name;
684f77a458Spettai
694f77a458Spettai ret = krb5_enctype_to_string(context, etype, &name);
704f77a458Spettai if (ret)
714f77a458Spettai return ret;
724f77a458Spettai
734f77a458Spettai krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
744f77a458Spettai N_("Encryption type %s not supported", ""),
754f77a458Spettai name);
764f77a458Spettai free(name);
774f77a458Spettai return KRB5_PROG_ETYPE_NOSUPP;
784f77a458Spettai }
794f77a458Spettai
804f77a458Spettai /*
814f77a458Spettai *
824f77a458Spettai */
83ca1c9b0cSelric
84ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_keysize(krb5_context context,krb5_enctype type,size_t * keysize)85ca1c9b0cSelric krb5_enctype_keysize(krb5_context context,
86ca1c9b0cSelric krb5_enctype type,
87ca1c9b0cSelric size_t *keysize)
88ca1c9b0cSelric {
89ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(type);
90ca1c9b0cSelric if(et == NULL) {
914f77a458Spettai return unsupported_enctype (context, type);
92ca1c9b0cSelric }
93ca1c9b0cSelric *keysize = et->keytype->size;
94ca1c9b0cSelric return 0;
95ca1c9b0cSelric }
96ca1c9b0cSelric
97ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_keybits(krb5_context context,krb5_enctype type,size_t * keybits)98ca1c9b0cSelric krb5_enctype_keybits(krb5_context context,
99ca1c9b0cSelric krb5_enctype type,
100ca1c9b0cSelric size_t *keybits)
101ca1c9b0cSelric {
102ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(type);
103ca1c9b0cSelric if(et == NULL) {
1044f77a458Spettai return unsupported_enctype (context, type);
105ca1c9b0cSelric }
106ca1c9b0cSelric *keybits = et->keytype->bits;
107ca1c9b0cSelric return 0;
108ca1c9b0cSelric }
109ca1c9b0cSelric
110ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_generate_random_keyblock(krb5_context context,krb5_enctype type,krb5_keyblock * key)111ca1c9b0cSelric krb5_generate_random_keyblock(krb5_context context,
112ca1c9b0cSelric krb5_enctype type,
113ca1c9b0cSelric krb5_keyblock *key)
114ca1c9b0cSelric {
115ca1c9b0cSelric krb5_error_code ret;
116ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(type);
117ca1c9b0cSelric if(et == NULL) {
1184f77a458Spettai return unsupported_enctype (context, type);
119ca1c9b0cSelric }
120ca1c9b0cSelric ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
121ca1c9b0cSelric if(ret)
122ca1c9b0cSelric return ret;
123ca1c9b0cSelric key->keytype = type;
124ca1c9b0cSelric if(et->keytype->random_key)
125ca1c9b0cSelric (*et->keytype->random_key)(context, key);
126ca1c9b0cSelric else
127ca1c9b0cSelric krb5_generate_random_block(key->keyvalue.data,
128ca1c9b0cSelric key->keyvalue.length);
129ca1c9b0cSelric return 0;
130ca1c9b0cSelric }
131ca1c9b0cSelric
132ca1c9b0cSelric static krb5_error_code
_key_schedule(krb5_context context,struct _krb5_key_data * key)133ca1c9b0cSelric _key_schedule(krb5_context context,
134ca1c9b0cSelric struct _krb5_key_data *key)
135ca1c9b0cSelric {
136ca1c9b0cSelric krb5_error_code ret;
137ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
138ca1c9b0cSelric struct _krb5_key_type *kt;
139ca1c9b0cSelric
140ca1c9b0cSelric if (et == NULL) {
1414f77a458Spettai return unsupported_enctype (context,
142ca1c9b0cSelric key->key->keytype);
143ca1c9b0cSelric }
144ca1c9b0cSelric
145ca1c9b0cSelric kt = et->keytype;
146ca1c9b0cSelric
147ca1c9b0cSelric if(kt->schedule == NULL)
148ca1c9b0cSelric return 0;
149ca1c9b0cSelric if (key->schedule != NULL)
150ca1c9b0cSelric return 0;
151ca1c9b0cSelric ALLOC(key->schedule, 1);
152b9d004c6Schristos if (key->schedule == NULL)
153b9d004c6Schristos return krb5_enomem(context);
154ca1c9b0cSelric ret = krb5_data_alloc(key->schedule, kt->schedule_size);
155ca1c9b0cSelric if(ret) {
156ca1c9b0cSelric free(key->schedule);
157ca1c9b0cSelric key->schedule = NULL;
158ca1c9b0cSelric return ret;
159ca1c9b0cSelric }
160ca1c9b0cSelric (*kt->schedule)(context, kt, key);
161ca1c9b0cSelric return 0;
162ca1c9b0cSelric }
163ca1c9b0cSelric
164ca1c9b0cSelric /************************************************************
165ca1c9b0cSelric * *
166ca1c9b0cSelric ************************************************************/
167ca1c9b0cSelric
168ca1c9b0cSelric static krb5_error_code
SHA1_checksum(krb5_context context,struct _krb5_key_data * key,const void * data,size_t len,unsigned usage,Checksum * C)169ca1c9b0cSelric SHA1_checksum(krb5_context context,
170ca1c9b0cSelric struct _krb5_key_data *key,
171ca1c9b0cSelric const void *data,
172ca1c9b0cSelric size_t len,
173ca1c9b0cSelric unsigned usage,
174ca1c9b0cSelric Checksum *C)
175ca1c9b0cSelric {
176ca1c9b0cSelric if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
177ca1c9b0cSelric krb5_abortx(context, "sha1 checksum failed");
178ca1c9b0cSelric return 0;
179ca1c9b0cSelric }
180ca1c9b0cSelric
181ca1c9b0cSelric /* HMAC according to RFC2104 */
182b9d004c6Schristos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_internal_hmac(krb5_context context,struct _krb5_checksum_type * cm,const void * data,size_t len,unsigned usage,struct _krb5_key_data * keyblock,Checksum * result)183ca1c9b0cSelric _krb5_internal_hmac(krb5_context context,
184ca1c9b0cSelric struct _krb5_checksum_type *cm,
185ca1c9b0cSelric const void *data,
186ca1c9b0cSelric size_t len,
187ca1c9b0cSelric unsigned usage,
188ca1c9b0cSelric struct _krb5_key_data *keyblock,
189ca1c9b0cSelric Checksum *result)
190ca1c9b0cSelric {
191ca1c9b0cSelric unsigned char *ipad, *opad;
192ca1c9b0cSelric unsigned char *key;
193ca1c9b0cSelric size_t key_len;
1944f77a458Spettai size_t i;
195ca1c9b0cSelric
196ca1c9b0cSelric ipad = malloc(cm->blocksize + len);
197ca1c9b0cSelric if (ipad == NULL)
198ca1c9b0cSelric return ENOMEM;
199ca1c9b0cSelric opad = malloc(cm->blocksize + cm->checksumsize);
200ca1c9b0cSelric if (opad == NULL) {
201ca1c9b0cSelric free(ipad);
202ca1c9b0cSelric return ENOMEM;
203ca1c9b0cSelric }
204ca1c9b0cSelric memset(ipad, 0x36, cm->blocksize);
205ca1c9b0cSelric memset(opad, 0x5c, cm->blocksize);
206ca1c9b0cSelric
207ca1c9b0cSelric if(keyblock->key->keyvalue.length > cm->blocksize){
208ca1c9b0cSelric (*cm->checksum)(context,
209ca1c9b0cSelric keyblock,
210ca1c9b0cSelric keyblock->key->keyvalue.data,
211ca1c9b0cSelric keyblock->key->keyvalue.length,
212ca1c9b0cSelric usage,
213ca1c9b0cSelric result);
214ca1c9b0cSelric key = result->checksum.data;
215ca1c9b0cSelric key_len = result->checksum.length;
216ca1c9b0cSelric } else {
217ca1c9b0cSelric key = keyblock->key->keyvalue.data;
218ca1c9b0cSelric key_len = keyblock->key->keyvalue.length;
219ca1c9b0cSelric }
220ca1c9b0cSelric for(i = 0; i < key_len; i++){
221ca1c9b0cSelric ipad[i] ^= key[i];
222ca1c9b0cSelric opad[i] ^= key[i];
223ca1c9b0cSelric }
224ca1c9b0cSelric memcpy(ipad + cm->blocksize, data, len);
225ca1c9b0cSelric (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
226ca1c9b0cSelric usage, result);
227ca1c9b0cSelric memcpy(opad + cm->blocksize, result->checksum.data,
228ca1c9b0cSelric result->checksum.length);
229ca1c9b0cSelric (*cm->checksum)(context, keyblock, opad,
230ca1c9b0cSelric cm->blocksize + cm->checksumsize, usage, result);
231ca1c9b0cSelric memset(ipad, 0, cm->blocksize + len);
232ca1c9b0cSelric free(ipad);
233ca1c9b0cSelric memset(opad, 0, cm->blocksize + cm->checksumsize);
234ca1c9b0cSelric free(opad);
235ca1c9b0cSelric
236ca1c9b0cSelric return 0;
237ca1c9b0cSelric }
238ca1c9b0cSelric
239ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_hmac(krb5_context context,krb5_cksumtype cktype,const void * data,size_t len,unsigned usage,krb5_keyblock * key,Checksum * result)240ca1c9b0cSelric krb5_hmac(krb5_context context,
241ca1c9b0cSelric krb5_cksumtype cktype,
242ca1c9b0cSelric const void *data,
243ca1c9b0cSelric size_t len,
244ca1c9b0cSelric unsigned usage,
245ca1c9b0cSelric krb5_keyblock *key,
246ca1c9b0cSelric Checksum *result)
247ca1c9b0cSelric {
248ca1c9b0cSelric struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
249ca1c9b0cSelric struct _krb5_key_data kd;
250ca1c9b0cSelric krb5_error_code ret;
251ca1c9b0cSelric
252ca1c9b0cSelric if (c == NULL) {
253ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
254ca1c9b0cSelric N_("checksum type %d not supported", ""),
255ca1c9b0cSelric cktype);
256ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
257ca1c9b0cSelric }
258ca1c9b0cSelric
259ca1c9b0cSelric kd.key = key;
260ca1c9b0cSelric kd.schedule = NULL;
261ca1c9b0cSelric
262ca1c9b0cSelric ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result);
263ca1c9b0cSelric
264ca1c9b0cSelric if (kd.schedule)
265ca1c9b0cSelric krb5_free_data(context, kd.schedule);
266ca1c9b0cSelric
267ca1c9b0cSelric return ret;
268ca1c9b0cSelric }
269ca1c9b0cSelric
270ca1c9b0cSelric krb5_error_code
_krb5_SP_HMAC_SHA1_checksum(krb5_context context,struct _krb5_key_data * key,const void * data,size_t len,unsigned usage,Checksum * result)271ca1c9b0cSelric _krb5_SP_HMAC_SHA1_checksum(krb5_context context,
272ca1c9b0cSelric struct _krb5_key_data *key,
273ca1c9b0cSelric const void *data,
274ca1c9b0cSelric size_t len,
275ca1c9b0cSelric unsigned usage,
276ca1c9b0cSelric Checksum *result)
277ca1c9b0cSelric {
278ca1c9b0cSelric struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
279ca1c9b0cSelric Checksum res;
280ca1c9b0cSelric char sha1_data[20];
281ca1c9b0cSelric krb5_error_code ret;
282ca1c9b0cSelric
283ca1c9b0cSelric res.checksum.data = sha1_data;
284ca1c9b0cSelric res.checksum.length = sizeof(sha1_data);
285ca1c9b0cSelric
286ca1c9b0cSelric ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res);
287ca1c9b0cSelric if (ret)
288ca1c9b0cSelric krb5_abortx(context, "hmac failed");
289ca1c9b0cSelric memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
290ca1c9b0cSelric return 0;
291ca1c9b0cSelric }
292ca1c9b0cSelric
293ca1c9b0cSelric struct _krb5_checksum_type _krb5_checksum_sha1 = {
294ca1c9b0cSelric CKSUMTYPE_SHA1,
295ca1c9b0cSelric "sha1",
296ca1c9b0cSelric 64,
297ca1c9b0cSelric 20,
298ca1c9b0cSelric F_CPROOF,
299ca1c9b0cSelric SHA1_checksum,
300ca1c9b0cSelric NULL
301ca1c9b0cSelric };
302ca1c9b0cSelric
303b9d004c6Schristos KRB5_LIB_FUNCTION struct _krb5_checksum_type * KRB5_LIB_CALL
_krb5_find_checksum(krb5_cksumtype type)304ca1c9b0cSelric _krb5_find_checksum(krb5_cksumtype type)
305ca1c9b0cSelric {
306ca1c9b0cSelric int i;
307ca1c9b0cSelric for(i = 0; i < _krb5_num_checksums; i++)
308ca1c9b0cSelric if(_krb5_checksum_types[i]->type == type)
309ca1c9b0cSelric return _krb5_checksum_types[i];
310ca1c9b0cSelric return NULL;
311ca1c9b0cSelric }
312ca1c9b0cSelric
313ca1c9b0cSelric static krb5_error_code
get_checksum_key(krb5_context context,krb5_crypto crypto,unsigned usage,struct _krb5_checksum_type * ct,struct _krb5_key_data ** key)314ca1c9b0cSelric get_checksum_key(krb5_context context,
315ca1c9b0cSelric krb5_crypto crypto,
316ca1c9b0cSelric unsigned usage, /* not krb5_key_usage */
317ca1c9b0cSelric struct _krb5_checksum_type *ct,
318ca1c9b0cSelric struct _krb5_key_data **key)
319ca1c9b0cSelric {
320ca1c9b0cSelric krb5_error_code ret = 0;
321ca1c9b0cSelric
322ca1c9b0cSelric if(ct->flags & F_DERIVED)
323ca1c9b0cSelric ret = _get_derived_key(context, crypto, usage, key);
324ca1c9b0cSelric else if(ct->flags & F_VARIANT) {
3254f77a458Spettai size_t i;
326ca1c9b0cSelric
327ca1c9b0cSelric *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
328b9d004c6Schristos if (*key == NULL)
329b9d004c6Schristos return krb5_enomem(context);
330ca1c9b0cSelric ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
331ca1c9b0cSelric if(ret)
332ca1c9b0cSelric return ret;
333ca1c9b0cSelric for(i = 0; i < (*key)->key->keyvalue.length; i++)
334ca1c9b0cSelric ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
335ca1c9b0cSelric } else {
336ca1c9b0cSelric *key = &crypto->key;
337ca1c9b0cSelric }
338ca1c9b0cSelric if(ret == 0)
339ca1c9b0cSelric ret = _key_schedule(context, *key);
340ca1c9b0cSelric return ret;
341ca1c9b0cSelric }
342ca1c9b0cSelric
343ca1c9b0cSelric static krb5_error_code
create_checksum(krb5_context context,struct _krb5_checksum_type * ct,krb5_crypto crypto,unsigned usage,void * data,size_t len,Checksum * result)344ca1c9b0cSelric create_checksum (krb5_context context,
345ca1c9b0cSelric struct _krb5_checksum_type *ct,
346ca1c9b0cSelric krb5_crypto crypto,
347ca1c9b0cSelric unsigned usage,
348ca1c9b0cSelric void *data,
349ca1c9b0cSelric size_t len,
350ca1c9b0cSelric Checksum *result)
351ca1c9b0cSelric {
352ca1c9b0cSelric krb5_error_code ret;
353ca1c9b0cSelric struct _krb5_key_data *dkey;
354ca1c9b0cSelric int keyed_checksum;
355ca1c9b0cSelric
356ca1c9b0cSelric if (ct->flags & F_DISABLED) {
357ca1c9b0cSelric krb5_clear_error_message (context);
358ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
359ca1c9b0cSelric }
360ca1c9b0cSelric keyed_checksum = (ct->flags & F_KEYED) != 0;
361ca1c9b0cSelric if(keyed_checksum && crypto == NULL) {
362ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
363ca1c9b0cSelric N_("Checksum type %s is keyed but no "
364ca1c9b0cSelric "crypto context (key) was passed in", ""),
365ca1c9b0cSelric ct->name);
366ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
367ca1c9b0cSelric }
368ca1c9b0cSelric if(keyed_checksum) {
369ca1c9b0cSelric ret = get_checksum_key(context, crypto, usage, ct, &dkey);
370ca1c9b0cSelric if (ret)
371ca1c9b0cSelric return ret;
372ca1c9b0cSelric } else
373ca1c9b0cSelric dkey = NULL;
374ca1c9b0cSelric result->cksumtype = ct->type;
375ca1c9b0cSelric ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
376ca1c9b0cSelric if (ret)
377ca1c9b0cSelric return (ret);
378ca1c9b0cSelric return (*ct->checksum)(context, dkey, data, len, usage, result);
379ca1c9b0cSelric }
380ca1c9b0cSelric
381ca1c9b0cSelric static int
arcfour_checksum_p(struct _krb5_checksum_type * ct,krb5_crypto crypto)382ca1c9b0cSelric arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
383ca1c9b0cSelric {
384ca1c9b0cSelric return (ct->type == CKSUMTYPE_HMAC_MD5) &&
385ca1c9b0cSelric (crypto->key.key->keytype == KEYTYPE_ARCFOUR);
386ca1c9b0cSelric }
387ca1c9b0cSelric
388ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_create_checksum(krb5_context context,krb5_crypto crypto,krb5_key_usage usage,int type,void * data,size_t len,Checksum * result)389ca1c9b0cSelric krb5_create_checksum(krb5_context context,
390ca1c9b0cSelric krb5_crypto crypto,
391ca1c9b0cSelric krb5_key_usage usage,
392ca1c9b0cSelric int type,
393ca1c9b0cSelric void *data,
394ca1c9b0cSelric size_t len,
395ca1c9b0cSelric Checksum *result)
396ca1c9b0cSelric {
397ca1c9b0cSelric struct _krb5_checksum_type *ct = NULL;
398ca1c9b0cSelric unsigned keyusage;
399ca1c9b0cSelric
400ca1c9b0cSelric /* type 0 -> pick from crypto */
401ca1c9b0cSelric if (type) {
402ca1c9b0cSelric ct = _krb5_find_checksum(type);
403ca1c9b0cSelric } else if (crypto) {
404ca1c9b0cSelric ct = crypto->et->keyed_checksum;
405ca1c9b0cSelric if (ct == NULL)
406ca1c9b0cSelric ct = crypto->et->checksum;
407ca1c9b0cSelric }
408ca1c9b0cSelric
409ca1c9b0cSelric if(ct == NULL) {
410ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
411ca1c9b0cSelric N_("checksum type %d not supported", ""),
412ca1c9b0cSelric type);
413ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
414ca1c9b0cSelric }
415ca1c9b0cSelric
416ca1c9b0cSelric if (arcfour_checksum_p(ct, crypto)) {
417ca1c9b0cSelric keyusage = usage;
418ca1c9b0cSelric _krb5_usage2arcfour(context, &keyusage);
419ca1c9b0cSelric } else
420ca1c9b0cSelric keyusage = CHECKSUM_USAGE(usage);
421ca1c9b0cSelric
422ca1c9b0cSelric return create_checksum(context, ct, crypto, keyusage,
423ca1c9b0cSelric data, len, result);
424ca1c9b0cSelric }
425ca1c9b0cSelric
426ca1c9b0cSelric static krb5_error_code
verify_checksum(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,Checksum * cksum)427ca1c9b0cSelric verify_checksum(krb5_context context,
428ca1c9b0cSelric krb5_crypto crypto,
429ca1c9b0cSelric unsigned usage, /* not krb5_key_usage */
430ca1c9b0cSelric void *data,
431ca1c9b0cSelric size_t len,
432ca1c9b0cSelric Checksum *cksum)
433ca1c9b0cSelric {
434ca1c9b0cSelric krb5_error_code ret;
435ca1c9b0cSelric struct _krb5_key_data *dkey;
436ca1c9b0cSelric int keyed_checksum;
437ca1c9b0cSelric Checksum c;
438ca1c9b0cSelric struct _krb5_checksum_type *ct;
439ca1c9b0cSelric
440ca1c9b0cSelric ct = _krb5_find_checksum(cksum->cksumtype);
441ca1c9b0cSelric if (ct == NULL || (ct->flags & F_DISABLED)) {
442ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
443ca1c9b0cSelric N_("checksum type %d not supported", ""),
444ca1c9b0cSelric cksum->cksumtype);
445ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
446ca1c9b0cSelric }
447ca1c9b0cSelric if(ct->checksumsize != cksum->checksum.length) {
448ca1c9b0cSelric krb5_clear_error_message (context);
449ca1c9b0cSelric krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
450ca1c9b0cSelric N_("Decrypt integrity check failed for checksum type %s, "
451ca1c9b0cSelric "length was %u, expected %u", ""),
452ca1c9b0cSelric ct->name, (unsigned)cksum->checksum.length,
453ca1c9b0cSelric (unsigned)ct->checksumsize);
454ca1c9b0cSelric
455ca1c9b0cSelric return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
456ca1c9b0cSelric }
457ca1c9b0cSelric keyed_checksum = (ct->flags & F_KEYED) != 0;
458ca1c9b0cSelric if(keyed_checksum) {
459ca1c9b0cSelric struct _krb5_checksum_type *kct;
460ca1c9b0cSelric if (crypto == NULL) {
461ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
462ca1c9b0cSelric N_("Checksum type %s is keyed but no "
463ca1c9b0cSelric "crypto context (key) was passed in", ""),
464ca1c9b0cSelric ct->name);
465ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
466ca1c9b0cSelric }
467ca1c9b0cSelric kct = crypto->et->keyed_checksum;
4684f77a458Spettai if (kct == NULL || kct->type != ct->type) {
469ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
470ca1c9b0cSelric N_("Checksum type %s is keyed, but "
471ca1c9b0cSelric "the key type %s passed didnt have that checksum "
472ca1c9b0cSelric "type as the keyed type", ""),
473ca1c9b0cSelric ct->name, crypto->et->name);
474ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
475ca1c9b0cSelric }
476ca1c9b0cSelric
477ca1c9b0cSelric ret = get_checksum_key(context, crypto, usage, ct, &dkey);
478ca1c9b0cSelric if (ret)
479ca1c9b0cSelric return ret;
480ca1c9b0cSelric } else
481ca1c9b0cSelric dkey = NULL;
482ca1c9b0cSelric
483ca1c9b0cSelric /*
484ca1c9b0cSelric * If checksum have a verify function, lets use that instead of
485ca1c9b0cSelric * calling ->checksum and then compare result.
486ca1c9b0cSelric */
487ca1c9b0cSelric
488ca1c9b0cSelric if(ct->verify) {
489ca1c9b0cSelric ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
490ca1c9b0cSelric if (ret)
491ca1c9b0cSelric krb5_set_error_message(context, ret,
492ca1c9b0cSelric N_("Decrypt integrity check failed for checksum "
493ca1c9b0cSelric "type %s, key type %s", ""),
494ca1c9b0cSelric ct->name, (crypto != NULL)? crypto->et->name : "(none)");
495ca1c9b0cSelric return ret;
496ca1c9b0cSelric }
497ca1c9b0cSelric
498ca1c9b0cSelric ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
499ca1c9b0cSelric if (ret)
500ca1c9b0cSelric return ret;
501ca1c9b0cSelric
502ca1c9b0cSelric ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
503ca1c9b0cSelric if (ret) {
504ca1c9b0cSelric krb5_data_free(&c.checksum);
505ca1c9b0cSelric return ret;
506ca1c9b0cSelric }
507ca1c9b0cSelric
508ca1c9b0cSelric if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
509ca1c9b0cSelric ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
510ca1c9b0cSelric krb5_set_error_message(context, ret,
511ca1c9b0cSelric N_("Decrypt integrity check failed for checksum "
512ca1c9b0cSelric "type %s, key type %s", ""),
513ca1c9b0cSelric ct->name, crypto ? crypto->et->name : "(unkeyed)");
514ca1c9b0cSelric } else {
515ca1c9b0cSelric ret = 0;
516ca1c9b0cSelric }
517ca1c9b0cSelric krb5_data_free (&c.checksum);
518ca1c9b0cSelric return ret;
519ca1c9b0cSelric }
520ca1c9b0cSelric
521ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_checksum(krb5_context context,krb5_crypto crypto,krb5_key_usage usage,void * data,size_t len,Checksum * cksum)522ca1c9b0cSelric krb5_verify_checksum(krb5_context context,
523ca1c9b0cSelric krb5_crypto crypto,
524ca1c9b0cSelric krb5_key_usage usage,
525ca1c9b0cSelric void *data,
526ca1c9b0cSelric size_t len,
527ca1c9b0cSelric Checksum *cksum)
528ca1c9b0cSelric {
529ca1c9b0cSelric struct _krb5_checksum_type *ct;
530ca1c9b0cSelric unsigned keyusage;
531ca1c9b0cSelric
532ca1c9b0cSelric ct = _krb5_find_checksum(cksum->cksumtype);
533ca1c9b0cSelric if(ct == NULL) {
534ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
535ca1c9b0cSelric N_("checksum type %d not supported", ""),
536ca1c9b0cSelric cksum->cksumtype);
537ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
538ca1c9b0cSelric }
539ca1c9b0cSelric
540ca1c9b0cSelric if (arcfour_checksum_p(ct, crypto)) {
541ca1c9b0cSelric keyusage = usage;
542ca1c9b0cSelric _krb5_usage2arcfour(context, &keyusage);
543ca1c9b0cSelric } else
544ca1c9b0cSelric keyusage = CHECKSUM_USAGE(usage);
545ca1c9b0cSelric
546ca1c9b0cSelric return verify_checksum(context, crypto, keyusage,
547ca1c9b0cSelric data, len, cksum);
548ca1c9b0cSelric }
549ca1c9b0cSelric
550ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_get_checksum_type(krb5_context context,krb5_crypto crypto,krb5_cksumtype * type)551ca1c9b0cSelric krb5_crypto_get_checksum_type(krb5_context context,
552ca1c9b0cSelric krb5_crypto crypto,
553ca1c9b0cSelric krb5_cksumtype *type)
554ca1c9b0cSelric {
555ca1c9b0cSelric struct _krb5_checksum_type *ct = NULL;
556ca1c9b0cSelric
557ca1c9b0cSelric if (crypto != NULL) {
558ca1c9b0cSelric ct = crypto->et->keyed_checksum;
559ca1c9b0cSelric if (ct == NULL)
560ca1c9b0cSelric ct = crypto->et->checksum;
561ca1c9b0cSelric }
562ca1c9b0cSelric
563ca1c9b0cSelric if (ct == NULL) {
564ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
565ca1c9b0cSelric N_("checksum type not found", ""));
566ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
567ca1c9b0cSelric }
568ca1c9b0cSelric
569ca1c9b0cSelric *type = ct->type;
570ca1c9b0cSelric
571ca1c9b0cSelric return 0;
572ca1c9b0cSelric }
573ca1c9b0cSelric
574ca1c9b0cSelric
575ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_checksumsize(krb5_context context,krb5_cksumtype type,size_t * size)576ca1c9b0cSelric krb5_checksumsize(krb5_context context,
577ca1c9b0cSelric krb5_cksumtype type,
578ca1c9b0cSelric size_t *size)
579ca1c9b0cSelric {
580ca1c9b0cSelric struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
581ca1c9b0cSelric if(ct == NULL) {
582ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
583ca1c9b0cSelric N_("checksum type %d not supported", ""),
584ca1c9b0cSelric type);
585ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
586ca1c9b0cSelric }
587ca1c9b0cSelric *size = ct->checksumsize;
588ca1c9b0cSelric return 0;
589ca1c9b0cSelric }
590ca1c9b0cSelric
591ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_checksum_is_keyed(krb5_context context,krb5_cksumtype type)592ca1c9b0cSelric krb5_checksum_is_keyed(krb5_context context,
593ca1c9b0cSelric krb5_cksumtype type)
594ca1c9b0cSelric {
595ca1c9b0cSelric struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
596ca1c9b0cSelric if(ct == NULL) {
597ca1c9b0cSelric if (context)
598ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
599ca1c9b0cSelric N_("checksum type %d not supported", ""),
600ca1c9b0cSelric type);
601ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
602ca1c9b0cSelric }
603ca1c9b0cSelric return ct->flags & F_KEYED;
604ca1c9b0cSelric }
605ca1c9b0cSelric
606ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_checksum_is_collision_proof(krb5_context context,krb5_cksumtype type)607ca1c9b0cSelric krb5_checksum_is_collision_proof(krb5_context context,
608ca1c9b0cSelric krb5_cksumtype type)
609ca1c9b0cSelric {
610ca1c9b0cSelric struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
611ca1c9b0cSelric if(ct == NULL) {
612ca1c9b0cSelric if (context)
613ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
614ca1c9b0cSelric N_("checksum type %d not supported", ""),
615ca1c9b0cSelric type);
616ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
617ca1c9b0cSelric }
618ca1c9b0cSelric return ct->flags & F_CPROOF;
619ca1c9b0cSelric }
620ca1c9b0cSelric
621ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_checksum_disable(krb5_context context,krb5_cksumtype type)622ca1c9b0cSelric krb5_checksum_disable(krb5_context context,
623ca1c9b0cSelric krb5_cksumtype type)
624ca1c9b0cSelric {
625ca1c9b0cSelric struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
626ca1c9b0cSelric if(ct == NULL) {
627ca1c9b0cSelric if (context)
628ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
629ca1c9b0cSelric N_("checksum type %d not supported", ""),
630ca1c9b0cSelric type);
631ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
632ca1c9b0cSelric }
633ca1c9b0cSelric ct->flags |= F_DISABLED;
634ca1c9b0cSelric return 0;
635ca1c9b0cSelric }
636ca1c9b0cSelric
637ca1c9b0cSelric /************************************************************
638ca1c9b0cSelric * *
639ca1c9b0cSelric ************************************************************/
640ca1c9b0cSelric
641b9d004c6Schristos KRB5_LIB_FUNCTION struct _krb5_encryption_type * KRB5_LIB_CALL
_krb5_find_enctype(krb5_enctype type)642ca1c9b0cSelric _krb5_find_enctype(krb5_enctype type)
643ca1c9b0cSelric {
644ca1c9b0cSelric int i;
645ca1c9b0cSelric for(i = 0; i < _krb5_num_etypes; i++)
646ca1c9b0cSelric if(_krb5_etypes[i]->type == type)
647ca1c9b0cSelric return _krb5_etypes[i];
648ca1c9b0cSelric return NULL;
649ca1c9b0cSelric }
650ca1c9b0cSelric
651ca1c9b0cSelric
652ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_to_string(krb5_context context,krb5_enctype etype,char ** string)653ca1c9b0cSelric krb5_enctype_to_string(krb5_context context,
654ca1c9b0cSelric krb5_enctype etype,
655ca1c9b0cSelric char **string)
656ca1c9b0cSelric {
657ca1c9b0cSelric struct _krb5_encryption_type *e;
658ca1c9b0cSelric e = _krb5_find_enctype(etype);
659ca1c9b0cSelric if(e == NULL) {
660ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
661ca1c9b0cSelric N_("encryption type %d not supported", ""),
662ca1c9b0cSelric etype);
663ca1c9b0cSelric *string = NULL;
664ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
665ca1c9b0cSelric }
666ca1c9b0cSelric *string = strdup(e->name);
667b9d004c6Schristos if (*string == NULL)
668b9d004c6Schristos return krb5_enomem(context);
669ca1c9b0cSelric return 0;
670ca1c9b0cSelric }
671ca1c9b0cSelric
672ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_string_to_enctype(krb5_context context,const char * string,krb5_enctype * etype)673ca1c9b0cSelric krb5_string_to_enctype(krb5_context context,
674ca1c9b0cSelric const char *string,
675ca1c9b0cSelric krb5_enctype *etype)
676ca1c9b0cSelric {
677ca1c9b0cSelric int i;
678b9d004c6Schristos for(i = 0; i < _krb5_num_etypes; i++) {
679ca1c9b0cSelric if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
680ca1c9b0cSelric *etype = _krb5_etypes[i]->type;
681ca1c9b0cSelric return 0;
682ca1c9b0cSelric }
683b9d004c6Schristos if(_krb5_etypes[i]->alias != NULL &&
684b9d004c6Schristos strcasecmp(_krb5_etypes[i]->alias, string) == 0){
685b9d004c6Schristos *etype = _krb5_etypes[i]->type;
686b9d004c6Schristos return 0;
687b9d004c6Schristos }
688b9d004c6Schristos }
689ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
690ca1c9b0cSelric N_("encryption type %s not supported", ""),
691ca1c9b0cSelric string);
692ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
693ca1c9b0cSelric }
694ca1c9b0cSelric
695ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_to_keytype(krb5_context context,krb5_enctype etype,krb5_keytype * keytype)696ca1c9b0cSelric krb5_enctype_to_keytype(krb5_context context,
697ca1c9b0cSelric krb5_enctype etype,
698ca1c9b0cSelric krb5_keytype *keytype)
699ca1c9b0cSelric {
700ca1c9b0cSelric struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
701ca1c9b0cSelric if(e == NULL) {
7024f77a458Spettai return unsupported_enctype (context, etype);
703ca1c9b0cSelric }
704ca1c9b0cSelric *keytype = e->keytype->type; /* XXX */
705ca1c9b0cSelric return 0;
706ca1c9b0cSelric }
707ca1c9b0cSelric
7084f77a458Spettai /**
7094f77a458Spettai * Check if a enctype is valid, return 0 if it is.
7104f77a458Spettai *
7114f77a458Spettai * @param context Kerberos context
7124f77a458Spettai * @param etype enctype to check if its valid or not
7134f77a458Spettai *
7144f77a458Spettai * @return Return an error code for an failure or 0 on success (enctype valid).
7154f77a458Spettai * @ingroup krb5_crypto
7164f77a458Spettai */
7174f77a458Spettai
718ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_valid(krb5_context context,krb5_enctype etype)719ca1c9b0cSelric krb5_enctype_valid(krb5_context context,
720ca1c9b0cSelric krb5_enctype etype)
721ca1c9b0cSelric {
722ca1c9b0cSelric struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
7234f77a458Spettai if(e && (e->flags & F_DISABLED) == 0)
7244f77a458Spettai return 0;
7254f77a458Spettai if (context == NULL)
726ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
7274f77a458Spettai if(e == NULL) {
7284f77a458Spettai return unsupported_enctype (context, etype);
729ca1c9b0cSelric }
7304f77a458Spettai /* Must be (e->flags & F_DISABLED) */
731ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
732ca1c9b0cSelric N_("encryption type %s is disabled", ""),
733ca1c9b0cSelric e->name);
734ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
735ca1c9b0cSelric }
736ca1c9b0cSelric
737ca1c9b0cSelric /**
738ca1c9b0cSelric * Return the coresponding encryption type for a checksum type.
739ca1c9b0cSelric *
740ca1c9b0cSelric * @param context Kerberos context
741ca1c9b0cSelric * @param ctype The checksum type to get the result enctype for
742ca1c9b0cSelric * @param etype The returned encryption, when the matching etype is
743ca1c9b0cSelric * not found, etype is set to ETYPE_NULL.
744ca1c9b0cSelric *
745ca1c9b0cSelric * @return Return an error code for an failure or 0 on success.
746ca1c9b0cSelric * @ingroup krb5_crypto
747ca1c9b0cSelric */
748ca1c9b0cSelric
749ca1c9b0cSelric
750ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cksumtype_to_enctype(krb5_context context,krb5_cksumtype ctype,krb5_enctype * etype)751ca1c9b0cSelric krb5_cksumtype_to_enctype(krb5_context context,
752ca1c9b0cSelric krb5_cksumtype ctype,
753ca1c9b0cSelric krb5_enctype *etype)
754ca1c9b0cSelric {
755ca1c9b0cSelric int i;
756ca1c9b0cSelric
757ca1c9b0cSelric *etype = ETYPE_NULL;
758ca1c9b0cSelric
759ca1c9b0cSelric for(i = 0; i < _krb5_num_etypes; i++) {
760ca1c9b0cSelric if(_krb5_etypes[i]->keyed_checksum &&
761ca1c9b0cSelric _krb5_etypes[i]->keyed_checksum->type == ctype)
762ca1c9b0cSelric {
763ca1c9b0cSelric *etype = _krb5_etypes[i]->type;
764ca1c9b0cSelric return 0;
765ca1c9b0cSelric }
766ca1c9b0cSelric }
767ca1c9b0cSelric
768ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
769ca1c9b0cSelric N_("checksum type %d not supported", ""),
770ca1c9b0cSelric (int)ctype);
771ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
772ca1c9b0cSelric }
773ca1c9b0cSelric
774ca1c9b0cSelric
775ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_cksumtype_valid(krb5_context context,krb5_cksumtype ctype)776ca1c9b0cSelric krb5_cksumtype_valid(krb5_context context,
777ca1c9b0cSelric krb5_cksumtype ctype)
778ca1c9b0cSelric {
779ca1c9b0cSelric struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
780ca1c9b0cSelric if (c == NULL) {
781ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
782ca1c9b0cSelric N_("checksum type %d not supported", ""),
783ca1c9b0cSelric ctype);
784ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
785ca1c9b0cSelric }
786ca1c9b0cSelric if (c->flags & F_DISABLED) {
787ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
788ca1c9b0cSelric N_("checksum type %s is disabled", ""),
789ca1c9b0cSelric c->name);
790ca1c9b0cSelric return KRB5_PROG_SUMTYPE_NOSUPP;
791ca1c9b0cSelric }
792ca1c9b0cSelric return 0;
793ca1c9b0cSelric }
794ca1c9b0cSelric
795ca1c9b0cSelric static krb5_boolean
derived_crypto(krb5_context context,krb5_crypto crypto)796ca1c9b0cSelric derived_crypto(krb5_context context,
797ca1c9b0cSelric krb5_crypto crypto)
798ca1c9b0cSelric {
799ca1c9b0cSelric return (crypto->et->flags & F_DERIVED) != 0;
800ca1c9b0cSelric }
801ca1c9b0cSelric
802ca1c9b0cSelric #define CHECKSUMSIZE(C) ((C)->checksumsize)
803ca1c9b0cSelric #define CHECKSUMTYPE(C) ((C)->type)
804ca1c9b0cSelric
805ca1c9b0cSelric static krb5_error_code
encrypt_internal_derived(krb5_context context,krb5_crypto crypto,unsigned usage,const void * data,size_t len,krb5_data * result,void * ivec)806ca1c9b0cSelric encrypt_internal_derived(krb5_context context,
807ca1c9b0cSelric krb5_crypto crypto,
808ca1c9b0cSelric unsigned usage,
809ca1c9b0cSelric const void *data,
810ca1c9b0cSelric size_t len,
811ca1c9b0cSelric krb5_data *result,
812ca1c9b0cSelric void *ivec)
813ca1c9b0cSelric {
814ca1c9b0cSelric size_t sz, block_sz, checksum_sz, total_sz;
815ca1c9b0cSelric Checksum cksum;
816ca1c9b0cSelric unsigned char *p, *q;
817ca1c9b0cSelric krb5_error_code ret;
818ca1c9b0cSelric struct _krb5_key_data *dkey;
819ca1c9b0cSelric const struct _krb5_encryption_type *et = crypto->et;
820ca1c9b0cSelric
821ca1c9b0cSelric checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
822ca1c9b0cSelric
823ca1c9b0cSelric sz = et->confoundersize + len;
824ca1c9b0cSelric block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
825ca1c9b0cSelric total_sz = block_sz + checksum_sz;
826ca1c9b0cSelric p = calloc(1, total_sz);
827b9d004c6Schristos if (p == NULL)
828b9d004c6Schristos return krb5_enomem(context);
829ca1c9b0cSelric
830ca1c9b0cSelric q = p;
831ca1c9b0cSelric krb5_generate_random_block(q, et->confoundersize); /* XXX */
832ca1c9b0cSelric q += et->confoundersize;
833ca1c9b0cSelric memcpy(q, data, len);
834ca1c9b0cSelric
835ca1c9b0cSelric ret = create_checksum(context,
836ca1c9b0cSelric et->keyed_checksum,
837ca1c9b0cSelric crypto,
838ca1c9b0cSelric INTEGRITY_USAGE(usage),
839ca1c9b0cSelric p,
840ca1c9b0cSelric block_sz,
841ca1c9b0cSelric &cksum);
842ca1c9b0cSelric if(ret == 0 && cksum.checksum.length != checksum_sz) {
843ca1c9b0cSelric free_Checksum (&cksum);
844ca1c9b0cSelric krb5_clear_error_message (context);
845ca1c9b0cSelric ret = KRB5_CRYPTO_INTERNAL;
846ca1c9b0cSelric }
847ca1c9b0cSelric if(ret)
848ca1c9b0cSelric goto fail;
849ca1c9b0cSelric memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
850ca1c9b0cSelric free_Checksum (&cksum);
851ca1c9b0cSelric ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
852ca1c9b0cSelric if(ret)
853ca1c9b0cSelric goto fail;
854ca1c9b0cSelric ret = _key_schedule(context, dkey);
855ca1c9b0cSelric if(ret)
856ca1c9b0cSelric goto fail;
857ca1c9b0cSelric ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
858ca1c9b0cSelric if (ret)
859ca1c9b0cSelric goto fail;
860ca1c9b0cSelric result->data = p;
861ca1c9b0cSelric result->length = total_sz;
862ca1c9b0cSelric return 0;
863ca1c9b0cSelric fail:
864ca1c9b0cSelric memset(p, 0, total_sz);
865ca1c9b0cSelric free(p);
866ca1c9b0cSelric return ret;
867ca1c9b0cSelric }
868ca1c9b0cSelric
869b9d004c6Schristos static krb5_error_code
encrypt_internal_enc_then_cksum(krb5_context context,krb5_crypto crypto,unsigned usage,const void * data,size_t len,krb5_data * result,void * ivec)870b9d004c6Schristos encrypt_internal_enc_then_cksum(krb5_context context,
871b9d004c6Schristos krb5_crypto crypto,
872b9d004c6Schristos unsigned usage,
873b9d004c6Schristos const void *data,
874b9d004c6Schristos size_t len,
875b9d004c6Schristos krb5_data *result,
876b9d004c6Schristos void *ivec)
877b9d004c6Schristos {
878b9d004c6Schristos size_t sz, block_sz, checksum_sz, total_sz;
879b9d004c6Schristos Checksum cksum;
880b9d004c6Schristos unsigned char *p, *q, *ivc = NULL;
881b9d004c6Schristos krb5_error_code ret;
882b9d004c6Schristos struct _krb5_key_data *dkey;
883b9d004c6Schristos const struct _krb5_encryption_type *et = crypto->et;
884b9d004c6Schristos
885b9d004c6Schristos checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
886b9d004c6Schristos
887b9d004c6Schristos sz = et->confoundersize + len;
888b9d004c6Schristos block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
889b9d004c6Schristos total_sz = block_sz + checksum_sz;
890b9d004c6Schristos p = calloc(1, total_sz);
891b9d004c6Schristos if (p == NULL)
892b9d004c6Schristos return krb5_enomem(context);
893b9d004c6Schristos
894b9d004c6Schristos q = p;
895b9d004c6Schristos krb5_generate_random_block(q, et->confoundersize); /* XXX */
896b9d004c6Schristos q += et->confoundersize;
897b9d004c6Schristos memcpy(q, data, len);
898b9d004c6Schristos
899b9d004c6Schristos ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
900b9d004c6Schristos if(ret)
901b9d004c6Schristos goto fail;
902b9d004c6Schristos ret = _key_schedule(context, dkey);
903b9d004c6Schristos if(ret)
904b9d004c6Schristos goto fail;
905b9d004c6Schristos
906b9d004c6Schristos /* XXX EVP style update API would avoid needing to allocate here */
907b9d004c6Schristos ivc = malloc(et->blocksize + block_sz);
908b9d004c6Schristos if (ivc == NULL) {
909b9d004c6Schristos ret = krb5_enomem(context);
910b9d004c6Schristos goto fail;
911b9d004c6Schristos }
912b9d004c6Schristos if (ivec)
913b9d004c6Schristos memcpy(ivc, ivec, et->blocksize);
914b9d004c6Schristos else
915b9d004c6Schristos memset(ivc, 0, et->blocksize);
916b9d004c6Schristos
917b9d004c6Schristos ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
918b9d004c6Schristos if (ret)
919b9d004c6Schristos goto fail;
920b9d004c6Schristos memcpy(&ivc[et->blocksize], p, block_sz);
921b9d004c6Schristos
922b9d004c6Schristos ret = create_checksum(context,
923b9d004c6Schristos et->keyed_checksum,
924b9d004c6Schristos crypto,
925b9d004c6Schristos INTEGRITY_USAGE(usage),
926b9d004c6Schristos ivc,
927b9d004c6Schristos et->blocksize + block_sz,
928b9d004c6Schristos &cksum);
929b9d004c6Schristos if(ret == 0 && cksum.checksum.length != checksum_sz) {
930b9d004c6Schristos free_Checksum (&cksum);
931b9d004c6Schristos krb5_clear_error_message (context);
932b9d004c6Schristos ret = KRB5_CRYPTO_INTERNAL;
933b9d004c6Schristos }
934b9d004c6Schristos if(ret)
935b9d004c6Schristos goto fail;
936b9d004c6Schristos memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
937b9d004c6Schristos free_Checksum (&cksum);
938b9d004c6Schristos result->data = p;
939b9d004c6Schristos result->length = total_sz;
940b9d004c6Schristos free(ivc);
941b9d004c6Schristos return 0;
942b9d004c6Schristos fail:
943b9d004c6Schristos memset_s(p, total_sz, 0, total_sz);
944b9d004c6Schristos free(p);
945b9d004c6Schristos free(ivc);
946b9d004c6Schristos return ret;
947b9d004c6Schristos }
948ca1c9b0cSelric
949ca1c9b0cSelric static krb5_error_code
encrypt_internal(krb5_context context,krb5_crypto crypto,const void * data,size_t len,krb5_data * result,void * ivec)950ca1c9b0cSelric encrypt_internal(krb5_context context,
951ca1c9b0cSelric krb5_crypto crypto,
952ca1c9b0cSelric const void *data,
953ca1c9b0cSelric size_t len,
954ca1c9b0cSelric krb5_data *result,
955ca1c9b0cSelric void *ivec)
956ca1c9b0cSelric {
957ca1c9b0cSelric size_t sz, block_sz, checksum_sz;
958ca1c9b0cSelric Checksum cksum;
959ca1c9b0cSelric unsigned char *p, *q;
960ca1c9b0cSelric krb5_error_code ret;
961ca1c9b0cSelric const struct _krb5_encryption_type *et = crypto->et;
962ca1c9b0cSelric
963ca1c9b0cSelric checksum_sz = CHECKSUMSIZE(et->checksum);
964ca1c9b0cSelric
965ca1c9b0cSelric sz = et->confoundersize + checksum_sz + len;
966ca1c9b0cSelric block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
967ca1c9b0cSelric p = calloc(1, block_sz);
968b9d004c6Schristos if (p == NULL)
969b9d004c6Schristos return krb5_enomem(context);
970ca1c9b0cSelric
971ca1c9b0cSelric q = p;
972ca1c9b0cSelric krb5_generate_random_block(q, et->confoundersize); /* XXX */
973ca1c9b0cSelric q += et->confoundersize;
974ca1c9b0cSelric memset(q, 0, checksum_sz);
975ca1c9b0cSelric q += checksum_sz;
976ca1c9b0cSelric memcpy(q, data, len);
977ca1c9b0cSelric
978ca1c9b0cSelric ret = create_checksum(context,
979ca1c9b0cSelric et->checksum,
980ca1c9b0cSelric crypto,
981ca1c9b0cSelric 0,
982ca1c9b0cSelric p,
983ca1c9b0cSelric block_sz,
984ca1c9b0cSelric &cksum);
985ca1c9b0cSelric if(ret == 0 && cksum.checksum.length != checksum_sz) {
986ca1c9b0cSelric krb5_clear_error_message (context);
987ca1c9b0cSelric free_Checksum(&cksum);
988ca1c9b0cSelric ret = KRB5_CRYPTO_INTERNAL;
989ca1c9b0cSelric }
990ca1c9b0cSelric if(ret)
991ca1c9b0cSelric goto fail;
992ca1c9b0cSelric memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
993ca1c9b0cSelric free_Checksum(&cksum);
994ca1c9b0cSelric ret = _key_schedule(context, &crypto->key);
995ca1c9b0cSelric if(ret)
996ca1c9b0cSelric goto fail;
997ca1c9b0cSelric ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
998ca1c9b0cSelric if (ret) {
999ca1c9b0cSelric memset(p, 0, block_sz);
1000ca1c9b0cSelric free(p);
1001ca1c9b0cSelric return ret;
1002ca1c9b0cSelric }
1003ca1c9b0cSelric result->data = p;
1004ca1c9b0cSelric result->length = block_sz;
1005ca1c9b0cSelric return 0;
1006ca1c9b0cSelric fail:
1007ca1c9b0cSelric memset(p, 0, block_sz);
1008ca1c9b0cSelric free(p);
1009ca1c9b0cSelric return ret;
1010ca1c9b0cSelric }
1011ca1c9b0cSelric
1012ca1c9b0cSelric static krb5_error_code
encrypt_internal_special(krb5_context context,krb5_crypto crypto,int usage,const void * data,size_t len,krb5_data * result,void * ivec)1013ca1c9b0cSelric encrypt_internal_special(krb5_context context,
1014ca1c9b0cSelric krb5_crypto crypto,
1015ca1c9b0cSelric int usage,
1016ca1c9b0cSelric const void *data,
1017ca1c9b0cSelric size_t len,
1018ca1c9b0cSelric krb5_data *result,
1019ca1c9b0cSelric void *ivec)
1020ca1c9b0cSelric {
1021ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1022ca1c9b0cSelric size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1023ca1c9b0cSelric size_t sz = len + cksum_sz + et->confoundersize;
1024ca1c9b0cSelric char *tmp, *p;
1025ca1c9b0cSelric krb5_error_code ret;
1026ca1c9b0cSelric
1027ca1c9b0cSelric tmp = malloc (sz);
1028b9d004c6Schristos if (tmp == NULL)
1029b9d004c6Schristos return krb5_enomem(context);
1030ca1c9b0cSelric p = tmp;
1031ca1c9b0cSelric memset (p, 0, cksum_sz);
1032ca1c9b0cSelric p += cksum_sz;
1033ca1c9b0cSelric krb5_generate_random_block(p, et->confoundersize);
1034ca1c9b0cSelric p += et->confoundersize;
1035ca1c9b0cSelric memcpy (p, data, len);
1036ca1c9b0cSelric ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
1037ca1c9b0cSelric if (ret) {
1038ca1c9b0cSelric memset(tmp, 0, sz);
1039ca1c9b0cSelric free(tmp);
1040ca1c9b0cSelric return ret;
1041ca1c9b0cSelric }
1042ca1c9b0cSelric result->data = tmp;
1043ca1c9b0cSelric result->length = sz;
1044ca1c9b0cSelric return 0;
1045ca1c9b0cSelric }
1046ca1c9b0cSelric
1047ca1c9b0cSelric static krb5_error_code
decrypt_internal_derived(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,krb5_data * result,void * ivec)1048ca1c9b0cSelric decrypt_internal_derived(krb5_context context,
1049ca1c9b0cSelric krb5_crypto crypto,
1050ca1c9b0cSelric unsigned usage,
1051ca1c9b0cSelric void *data,
1052ca1c9b0cSelric size_t len,
1053ca1c9b0cSelric krb5_data *result,
1054ca1c9b0cSelric void *ivec)
1055ca1c9b0cSelric {
1056ca1c9b0cSelric size_t checksum_sz;
1057ca1c9b0cSelric Checksum cksum;
1058ca1c9b0cSelric unsigned char *p;
1059ca1c9b0cSelric krb5_error_code ret;
1060ca1c9b0cSelric struct _krb5_key_data *dkey;
1061ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1062ca1c9b0cSelric unsigned long l;
1063ca1c9b0cSelric
1064ca1c9b0cSelric checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1065ca1c9b0cSelric if (len < checksum_sz + et->confoundersize) {
1066ca1c9b0cSelric krb5_set_error_message(context, KRB5_BAD_MSIZE,
1067ca1c9b0cSelric N_("Encrypted data shorter then "
1068ca1c9b0cSelric "checksum + confunder", ""));
1069ca1c9b0cSelric return KRB5_BAD_MSIZE;
1070ca1c9b0cSelric }
1071ca1c9b0cSelric
1072ca1c9b0cSelric if (((len - checksum_sz) % et->padsize) != 0) {
1073ca1c9b0cSelric krb5_clear_error_message(context);
1074ca1c9b0cSelric return KRB5_BAD_MSIZE;
1075ca1c9b0cSelric }
1076ca1c9b0cSelric
1077ca1c9b0cSelric p = malloc(len);
1078b9d004c6Schristos if (len != 0 && p == NULL)
1079b9d004c6Schristos return krb5_enomem(context);
1080ca1c9b0cSelric memcpy(p, data, len);
1081ca1c9b0cSelric
1082ca1c9b0cSelric len -= checksum_sz;
1083ca1c9b0cSelric
1084ca1c9b0cSelric ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1085ca1c9b0cSelric if(ret) {
1086ca1c9b0cSelric free(p);
1087ca1c9b0cSelric return ret;
1088ca1c9b0cSelric }
1089ca1c9b0cSelric ret = _key_schedule(context, dkey);
1090ca1c9b0cSelric if(ret) {
1091ca1c9b0cSelric free(p);
1092ca1c9b0cSelric return ret;
1093ca1c9b0cSelric }
1094ca1c9b0cSelric ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1095ca1c9b0cSelric if (ret) {
1096ca1c9b0cSelric free(p);
1097ca1c9b0cSelric return ret;
1098ca1c9b0cSelric }
1099ca1c9b0cSelric
1100ca1c9b0cSelric cksum.checksum.data = p + len;
1101ca1c9b0cSelric cksum.checksum.length = checksum_sz;
1102ca1c9b0cSelric cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1103ca1c9b0cSelric
1104ca1c9b0cSelric ret = verify_checksum(context,
1105ca1c9b0cSelric crypto,
1106ca1c9b0cSelric INTEGRITY_USAGE(usage),
1107ca1c9b0cSelric p,
1108ca1c9b0cSelric len,
1109ca1c9b0cSelric &cksum);
1110ca1c9b0cSelric if(ret) {
1111ca1c9b0cSelric free(p);
1112ca1c9b0cSelric return ret;
1113ca1c9b0cSelric }
1114ca1c9b0cSelric l = len - et->confoundersize;
1115ca1c9b0cSelric memmove(p, p + et->confoundersize, l);
1116ca1c9b0cSelric result->data = realloc(p, l);
1117ca1c9b0cSelric if(result->data == NULL && l != 0) {
1118ca1c9b0cSelric free(p);
1119b9d004c6Schristos return krb5_enomem(context);
1120b9d004c6Schristos }
1121b9d004c6Schristos result->length = l;
1122b9d004c6Schristos return 0;
1123b9d004c6Schristos }
1124b9d004c6Schristos
1125b9d004c6Schristos static krb5_error_code
decrypt_internal_enc_then_cksum(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,krb5_data * result,void * ivec)1126b9d004c6Schristos decrypt_internal_enc_then_cksum(krb5_context context,
1127b9d004c6Schristos krb5_crypto crypto,
1128b9d004c6Schristos unsigned usage,
1129b9d004c6Schristos void *data,
1130b9d004c6Schristos size_t len,
1131b9d004c6Schristos krb5_data *result,
1132b9d004c6Schristos void *ivec)
1133b9d004c6Schristos {
1134b9d004c6Schristos size_t checksum_sz;
1135b9d004c6Schristos Checksum cksum;
1136b9d004c6Schristos unsigned char *p;
1137b9d004c6Schristos krb5_error_code ret;
1138b9d004c6Schristos struct _krb5_key_data *dkey;
1139b9d004c6Schristos struct _krb5_encryption_type *et = crypto->et;
1140b9d004c6Schristos unsigned long l;
1141b9d004c6Schristos
1142b9d004c6Schristos checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
1143b9d004c6Schristos if (len < checksum_sz + et->confoundersize) {
1144b9d004c6Schristos krb5_set_error_message(context, KRB5_BAD_MSIZE,
1145b9d004c6Schristos N_("Encrypted data shorter then "
1146b9d004c6Schristos "checksum + confunder", ""));
1147b9d004c6Schristos return KRB5_BAD_MSIZE;
1148b9d004c6Schristos }
1149b9d004c6Schristos
1150b9d004c6Schristos if (((len - checksum_sz) % et->padsize) != 0) {
1151b9d004c6Schristos krb5_clear_error_message(context);
1152b9d004c6Schristos return KRB5_BAD_MSIZE;
1153b9d004c6Schristos }
1154b9d004c6Schristos
1155b9d004c6Schristos len -= checksum_sz;
1156b9d004c6Schristos
1157b9d004c6Schristos p = malloc(et->blocksize + len);
1158b9d004c6Schristos if (p == NULL)
1159b9d004c6Schristos return krb5_enomem(context);
1160b9d004c6Schristos
1161b9d004c6Schristos if (ivec)
1162b9d004c6Schristos memcpy(p, ivec, et->blocksize);
1163b9d004c6Schristos else
1164b9d004c6Schristos memset(p, 0, et->blocksize);
1165b9d004c6Schristos memcpy(&p[et->blocksize], data, len);
1166b9d004c6Schristos
1167b9d004c6Schristos cksum.checksum.data = (unsigned char *)data + len;
1168b9d004c6Schristos cksum.checksum.length = checksum_sz;
1169b9d004c6Schristos cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1170b9d004c6Schristos
1171b9d004c6Schristos ret = verify_checksum(context,
1172b9d004c6Schristos crypto,
1173b9d004c6Schristos INTEGRITY_USAGE(usage),
1174b9d004c6Schristos p,
1175b9d004c6Schristos et->blocksize + len,
1176b9d004c6Schristos &cksum);
1177b9d004c6Schristos if(ret) {
1178b9d004c6Schristos free(p);
1179b9d004c6Schristos return ret;
1180b9d004c6Schristos }
1181b9d004c6Schristos
1182b9d004c6Schristos ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1183b9d004c6Schristos if(ret) {
1184b9d004c6Schristos free(p);
1185b9d004c6Schristos return ret;
1186b9d004c6Schristos }
1187b9d004c6Schristos ret = _key_schedule(context, dkey);
1188b9d004c6Schristos if(ret) {
1189b9d004c6Schristos free(p);
1190b9d004c6Schristos return ret;
1191b9d004c6Schristos }
1192b9d004c6Schristos ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec);
1193b9d004c6Schristos if (ret) {
1194b9d004c6Schristos free(p);
1195b9d004c6Schristos return ret;
1196b9d004c6Schristos }
1197b9d004c6Schristos
1198b9d004c6Schristos l = len - et->confoundersize;
1199b9d004c6Schristos memmove(p, p + et->blocksize + et->confoundersize, l);
1200b9d004c6Schristos result->data = realloc(p, l);
1201b9d004c6Schristos if(result->data == NULL && l != 0) {
1202b9d004c6Schristos free(p);
1203b9d004c6Schristos return krb5_enomem(context);
1204ca1c9b0cSelric }
1205ca1c9b0cSelric result->length = l;
1206ca1c9b0cSelric return 0;
1207ca1c9b0cSelric }
1208ca1c9b0cSelric
1209ca1c9b0cSelric static krb5_error_code
decrypt_internal(krb5_context context,krb5_crypto crypto,void * data,size_t len,krb5_data * result,void * ivec)1210ca1c9b0cSelric decrypt_internal(krb5_context context,
1211ca1c9b0cSelric krb5_crypto crypto,
1212ca1c9b0cSelric void *data,
1213ca1c9b0cSelric size_t len,
1214ca1c9b0cSelric krb5_data *result,
1215ca1c9b0cSelric void *ivec)
1216ca1c9b0cSelric {
1217ca1c9b0cSelric krb5_error_code ret;
1218ca1c9b0cSelric unsigned char *p;
1219ca1c9b0cSelric Checksum cksum;
1220ca1c9b0cSelric size_t checksum_sz, l;
1221ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1222ca1c9b0cSelric
1223ca1c9b0cSelric if ((len % et->padsize) != 0) {
1224ca1c9b0cSelric krb5_clear_error_message(context);
1225ca1c9b0cSelric return KRB5_BAD_MSIZE;
1226ca1c9b0cSelric }
1227ca1c9b0cSelric checksum_sz = CHECKSUMSIZE(et->checksum);
1228ca1c9b0cSelric if (len < checksum_sz + et->confoundersize) {
1229ca1c9b0cSelric krb5_set_error_message(context, KRB5_BAD_MSIZE,
1230ca1c9b0cSelric N_("Encrypted data shorter then "
1231ca1c9b0cSelric "checksum + confunder", ""));
1232ca1c9b0cSelric return KRB5_BAD_MSIZE;
1233ca1c9b0cSelric }
1234ca1c9b0cSelric
1235ca1c9b0cSelric p = malloc(len);
1236b9d004c6Schristos if (len != 0 && p == NULL)
1237b9d004c6Schristos return krb5_enomem(context);
1238ca1c9b0cSelric memcpy(p, data, len);
1239ca1c9b0cSelric
1240ca1c9b0cSelric ret = _key_schedule(context, &crypto->key);
1241ca1c9b0cSelric if(ret) {
1242ca1c9b0cSelric free(p);
1243ca1c9b0cSelric return ret;
1244ca1c9b0cSelric }
1245ca1c9b0cSelric ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1246ca1c9b0cSelric if (ret) {
1247ca1c9b0cSelric free(p);
1248ca1c9b0cSelric return ret;
1249ca1c9b0cSelric }
1250ca1c9b0cSelric ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1251ca1c9b0cSelric if(ret) {
1252ca1c9b0cSelric free(p);
1253ca1c9b0cSelric return ret;
1254ca1c9b0cSelric }
1255ca1c9b0cSelric memset(p + et->confoundersize, 0, checksum_sz);
1256ca1c9b0cSelric cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1257ca1c9b0cSelric ret = verify_checksum(context, NULL, 0, p, len, &cksum);
1258ca1c9b0cSelric free_Checksum(&cksum);
1259ca1c9b0cSelric if(ret) {
1260ca1c9b0cSelric free(p);
1261ca1c9b0cSelric return ret;
1262ca1c9b0cSelric }
1263ca1c9b0cSelric l = len - et->confoundersize - checksum_sz;
1264ca1c9b0cSelric memmove(p, p + et->confoundersize + checksum_sz, l);
1265ca1c9b0cSelric result->data = realloc(p, l);
1266ca1c9b0cSelric if(result->data == NULL && l != 0) {
1267ca1c9b0cSelric free(p);
1268b9d004c6Schristos return krb5_enomem(context);
1269ca1c9b0cSelric }
1270ca1c9b0cSelric result->length = l;
1271ca1c9b0cSelric return 0;
1272ca1c9b0cSelric }
1273ca1c9b0cSelric
1274ca1c9b0cSelric static krb5_error_code
decrypt_internal_special(krb5_context context,krb5_crypto crypto,int usage,void * data,size_t len,krb5_data * result,void * ivec)1275ca1c9b0cSelric decrypt_internal_special(krb5_context context,
1276ca1c9b0cSelric krb5_crypto crypto,
1277ca1c9b0cSelric int usage,
1278ca1c9b0cSelric void *data,
1279ca1c9b0cSelric size_t len,
1280ca1c9b0cSelric krb5_data *result,
1281ca1c9b0cSelric void *ivec)
1282ca1c9b0cSelric {
1283ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1284ca1c9b0cSelric size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1285ca1c9b0cSelric size_t sz = len - cksum_sz - et->confoundersize;
1286ca1c9b0cSelric unsigned char *p;
1287ca1c9b0cSelric krb5_error_code ret;
1288ca1c9b0cSelric
1289ca1c9b0cSelric if ((len % et->padsize) != 0) {
1290ca1c9b0cSelric krb5_clear_error_message(context);
1291ca1c9b0cSelric return KRB5_BAD_MSIZE;
1292ca1c9b0cSelric }
1293ca1c9b0cSelric if (len < cksum_sz + et->confoundersize) {
1294ca1c9b0cSelric krb5_set_error_message(context, KRB5_BAD_MSIZE,
1295ca1c9b0cSelric N_("Encrypted data shorter then "
1296ca1c9b0cSelric "checksum + confunder", ""));
1297ca1c9b0cSelric return KRB5_BAD_MSIZE;
1298ca1c9b0cSelric }
1299ca1c9b0cSelric
1300ca1c9b0cSelric p = malloc (len);
1301b9d004c6Schristos if (p == NULL)
1302b9d004c6Schristos return krb5_enomem(context);
1303ca1c9b0cSelric memcpy(p, data, len);
1304ca1c9b0cSelric
1305ca1c9b0cSelric ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1306ca1c9b0cSelric if (ret) {
1307ca1c9b0cSelric free(p);
1308ca1c9b0cSelric return ret;
1309ca1c9b0cSelric }
1310ca1c9b0cSelric
1311ca1c9b0cSelric memmove (p, p + cksum_sz + et->confoundersize, sz);
1312ca1c9b0cSelric result->data = realloc(p, sz);
1313ca1c9b0cSelric if(result->data == NULL && sz != 0) {
1314ca1c9b0cSelric free(p);
1315b9d004c6Schristos return krb5_enomem(context);
1316ca1c9b0cSelric }
1317ca1c9b0cSelric result->length = sz;
1318ca1c9b0cSelric return 0;
1319ca1c9b0cSelric }
1320ca1c9b0cSelric
1321ca1c9b0cSelric static krb5_crypto_iov *
iov_find(krb5_crypto_iov * data,size_t num_data,unsigned type)1322b9d004c6Schristos iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type)
1323ca1c9b0cSelric {
13244f77a458Spettai size_t i;
1325ca1c9b0cSelric for (i = 0; i < num_data; i++)
1326ca1c9b0cSelric if (data[i].flags == type)
1327ca1c9b0cSelric return &data[i];
1328ca1c9b0cSelric return NULL;
1329ca1c9b0cSelric }
1330ca1c9b0cSelric
1331b9d004c6Schristos static size_t
iov_enc_data_len(krb5_crypto_iov * data,int num_data)1332b9d004c6Schristos iov_enc_data_len(krb5_crypto_iov *data, int num_data)
1333b9d004c6Schristos {
1334b9d004c6Schristos size_t i, len;
1335b9d004c6Schristos
1336b9d004c6Schristos for (len = 0, i = 0; i < num_data; i++) {
1337b9d004c6Schristos if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1338b9d004c6Schristos continue;
1339b9d004c6Schristos len += data[i].data.length;
1340b9d004c6Schristos }
1341b9d004c6Schristos
1342b9d004c6Schristos return len;
1343b9d004c6Schristos }
1344b9d004c6Schristos
1345b9d004c6Schristos static size_t
iov_sign_data_len(krb5_crypto_iov * data,int num_data)1346b9d004c6Schristos iov_sign_data_len(krb5_crypto_iov *data, int num_data)
1347b9d004c6Schristos {
1348b9d004c6Schristos size_t i, len;
1349b9d004c6Schristos
1350b9d004c6Schristos for (len = 0, i = 0; i < num_data; i++) {
1351b9d004c6Schristos if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1352b9d004c6Schristos data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1353b9d004c6Schristos continue;
1354b9d004c6Schristos len += data[i].data.length;
1355b9d004c6Schristos }
1356b9d004c6Schristos
1357b9d004c6Schristos return len;
1358b9d004c6Schristos }
1359b9d004c6Schristos
1360b9d004c6Schristos static krb5_error_code
iov_coalesce(krb5_context context,krb5_data * prefix,krb5_crypto_iov * data,int num_data,krb5_boolean inc_sign_data,krb5_data * out)1361b9d004c6Schristos iov_coalesce(krb5_context context,
1362b9d004c6Schristos krb5_data *prefix,
1363b9d004c6Schristos krb5_crypto_iov *data,
1364b9d004c6Schristos int num_data,
1365b9d004c6Schristos krb5_boolean inc_sign_data,
1366b9d004c6Schristos krb5_data *out)
1367b9d004c6Schristos {
1368b9d004c6Schristos unsigned char *p, *q;
1369b9d004c6Schristos krb5_crypto_iov *hiv, *piv;
1370b9d004c6Schristos size_t len;
1371b9d004c6Schristos unsigned int i;
1372b9d004c6Schristos
1373b9d004c6Schristos hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1374b9d004c6Schristos
1375b9d004c6Schristos piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1376b9d004c6Schristos
1377b9d004c6Schristos len = 0;
1378b9d004c6Schristos if (prefix)
1379b9d004c6Schristos len += prefix->length;
1380b9d004c6Schristos len += hiv->data.length;
1381b9d004c6Schristos if (inc_sign_data)
1382b9d004c6Schristos len += iov_sign_data_len(data, num_data);
1383b9d004c6Schristos else
1384b9d004c6Schristos len += iov_enc_data_len(data, num_data);
1385b9d004c6Schristos if (piv)
1386b9d004c6Schristos len += piv->data.length;
1387b9d004c6Schristos
1388b9d004c6Schristos p = q = malloc(len);
1389b9d004c6Schristos if (p == NULL)
1390b9d004c6Schristos return krb5_enomem(context);
1391b9d004c6Schristos
1392b9d004c6Schristos if (prefix) {
1393b9d004c6Schristos memcpy(q, prefix->data, prefix->length);
1394b9d004c6Schristos q += prefix->length;
1395b9d004c6Schristos }
1396b9d004c6Schristos memcpy(q, hiv->data.data, hiv->data.length);
1397b9d004c6Schristos q += hiv->data.length;
1398b9d004c6Schristos for (i = 0; i < num_data; i++) {
1399b9d004c6Schristos if (data[i].flags == KRB5_CRYPTO_TYPE_DATA ||
1400b9d004c6Schristos (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) {
1401b9d004c6Schristos memcpy(q, data[i].data.data, data[i].data.length);
1402b9d004c6Schristos q += data[i].data.length;
1403b9d004c6Schristos }
1404b9d004c6Schristos }
1405b9d004c6Schristos if (piv)
1406b9d004c6Schristos memset(q, 0, piv->data.length);
1407b9d004c6Schristos
1408b9d004c6Schristos out->length = len;
1409b9d004c6Schristos out->data = p;
1410b9d004c6Schristos
1411b9d004c6Schristos return 0;
1412b9d004c6Schristos }
1413b9d004c6Schristos
1414b9d004c6Schristos static krb5_error_code
iov_uncoalesce(krb5_context context,krb5_data * enc_data,krb5_crypto_iov * data,int num_data)1415b9d004c6Schristos iov_uncoalesce(krb5_context context,
1416b9d004c6Schristos krb5_data *enc_data,
1417b9d004c6Schristos krb5_crypto_iov *data,
1418b9d004c6Schristos int num_data)
1419b9d004c6Schristos {
1420b9d004c6Schristos unsigned char *q = enc_data->data;
1421b9d004c6Schristos krb5_crypto_iov *hiv, *piv;
1422b9d004c6Schristos unsigned int i;
1423b9d004c6Schristos
1424b9d004c6Schristos hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1425b9d004c6Schristos
1426b9d004c6Schristos piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1427b9d004c6Schristos
1428b9d004c6Schristos memcpy(hiv->data.data, q, hiv->data.length);
1429b9d004c6Schristos q += hiv->data.length;
1430b9d004c6Schristos
1431b9d004c6Schristos for (i = 0; i < num_data; i++) {
1432b9d004c6Schristos if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1433b9d004c6Schristos continue;
1434b9d004c6Schristos memcpy(data[i].data.data, q, data[i].data.length);
1435b9d004c6Schristos q += data[i].data.length;
1436b9d004c6Schristos }
1437b9d004c6Schristos if (piv)
1438b9d004c6Schristos memcpy(piv->data.data, q, piv->data.length);
1439b9d004c6Schristos
1440b9d004c6Schristos return 0;
1441b9d004c6Schristos }
1442b9d004c6Schristos
1443b9d004c6Schristos static krb5_error_code
iov_pad_validate(const struct _krb5_encryption_type * et,krb5_crypto_iov * data,int num_data,krb5_crypto_iov ** ppiv)1444b9d004c6Schristos iov_pad_validate(const struct _krb5_encryption_type *et,
1445b9d004c6Schristos krb5_crypto_iov *data,
1446b9d004c6Schristos int num_data,
1447b9d004c6Schristos krb5_crypto_iov **ppiv)
1448b9d004c6Schristos {
1449b9d004c6Schristos krb5_crypto_iov *piv;
1450b9d004c6Schristos size_t sz, headersz, block_sz, pad_sz, len;
1451b9d004c6Schristos
1452b9d004c6Schristos len = iov_enc_data_len(data, num_data);
1453b9d004c6Schristos
1454b9d004c6Schristos headersz = et->confoundersize;
1455b9d004c6Schristos
1456b9d004c6Schristos sz = headersz + len;
1457b9d004c6Schristos block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1458b9d004c6Schristos
1459b9d004c6Schristos pad_sz = block_sz - sz;
1460b9d004c6Schristos
1461b9d004c6Schristos piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1462b9d004c6Schristos /* its ok to have no TYPE_PADDING if there is no padding */
1463b9d004c6Schristos if (piv == NULL && pad_sz != 0)
1464b9d004c6Schristos return KRB5_BAD_MSIZE;
1465b9d004c6Schristos if (piv) {
1466b9d004c6Schristos if (piv->data.length < pad_sz)
1467b9d004c6Schristos return KRB5_BAD_MSIZE;
1468b9d004c6Schristos piv->data.length = pad_sz;
1469b9d004c6Schristos if (pad_sz)
1470b9d004c6Schristos memset(piv->data.data, pad_sz, pad_sz);
1471b9d004c6Schristos else
1472b9d004c6Schristos piv = NULL;
1473b9d004c6Schristos }
1474b9d004c6Schristos
1475b9d004c6Schristos *ppiv = piv;
1476b9d004c6Schristos return 0;
1477b9d004c6Schristos }
1478b9d004c6Schristos
1479ca1c9b0cSelric /**
1480ca1c9b0cSelric * Inline encrypt a kerberos message
1481ca1c9b0cSelric *
1482ca1c9b0cSelric * @param context Kerberos context
1483ca1c9b0cSelric * @param crypto Kerberos crypto context
1484ca1c9b0cSelric * @param usage Key usage for this buffer
1485ca1c9b0cSelric * @param data array of buffers to process
1486ca1c9b0cSelric * @param num_data length of array
1487ca1c9b0cSelric * @param ivec initial cbc/cts vector
1488ca1c9b0cSelric *
1489ca1c9b0cSelric * @return Return an error code or 0.
1490ca1c9b0cSelric * @ingroup krb5_crypto
1491ca1c9b0cSelric *
1492ca1c9b0cSelric * Kerberos encrypted data look like this:
1493ca1c9b0cSelric *
1494ca1c9b0cSelric * 1. KRB5_CRYPTO_TYPE_HEADER
1495ca1c9b0cSelric * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1496ca1c9b0cSelric * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1497ca1c9b0cSelric * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1498ca1c9b0cSelric * commonly used headers and trailers.
1499ca1c9b0cSelric * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1500ca1c9b0cSelric * 4. KRB5_CRYPTO_TYPE_TRAILER
1501ca1c9b0cSelric */
1502ca1c9b0cSelric
1503ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_encrypt_iov_ivec(krb5_context context,krb5_crypto crypto,unsigned usage,krb5_crypto_iov * data,int num_data,void * ivec)1504ca1c9b0cSelric krb5_encrypt_iov_ivec(krb5_context context,
1505ca1c9b0cSelric krb5_crypto crypto,
1506ca1c9b0cSelric unsigned usage,
1507ca1c9b0cSelric krb5_crypto_iov *data,
1508ca1c9b0cSelric int num_data,
1509ca1c9b0cSelric void *ivec)
1510ca1c9b0cSelric {
1511b9d004c6Schristos size_t headersz, trailersz;
1512ca1c9b0cSelric Checksum cksum;
1513b9d004c6Schristos krb5_data enc_data, sign_data;
1514ca1c9b0cSelric krb5_error_code ret;
1515ca1c9b0cSelric struct _krb5_key_data *dkey;
1516ca1c9b0cSelric const struct _krb5_encryption_type *et = crypto->et;
1517ca1c9b0cSelric krb5_crypto_iov *tiv, *piv, *hiv;
1518ca1c9b0cSelric
1519ca1c9b0cSelric if (num_data < 0) {
1520ca1c9b0cSelric krb5_clear_error_message(context);
1521ca1c9b0cSelric return KRB5_CRYPTO_INTERNAL;
1522ca1c9b0cSelric }
1523ca1c9b0cSelric
1524ca1c9b0cSelric if(!derived_crypto(context, crypto)) {
1525ca1c9b0cSelric krb5_clear_error_message(context);
1526ca1c9b0cSelric return KRB5_CRYPTO_INTERNAL;
1527ca1c9b0cSelric }
1528ca1c9b0cSelric
1529b9d004c6Schristos krb5_data_zero(&enc_data);
1530b9d004c6Schristos krb5_data_zero(&sign_data);
1531b9d004c6Schristos
1532ca1c9b0cSelric headersz = et->confoundersize;
1533ca1c9b0cSelric trailersz = CHECKSUMSIZE(et->keyed_checksum);
1534ca1c9b0cSelric
1535ca1c9b0cSelric /* header */
1536b9d004c6Schristos hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1537ca1c9b0cSelric if (hiv == NULL || hiv->data.length != headersz)
1538ca1c9b0cSelric return KRB5_BAD_MSIZE;
1539ca1c9b0cSelric krb5_generate_random_block(hiv->data.data, hiv->data.length);
1540ca1c9b0cSelric
1541ca1c9b0cSelric /* padding */
1542b9d004c6Schristos ret = iov_pad_validate(et, data, num_data, &piv);
1543b9d004c6Schristos if(ret)
1544b9d004c6Schristos goto cleanup;
1545ca1c9b0cSelric
1546ca1c9b0cSelric /* trailer */
1547b9d004c6Schristos tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1548b9d004c6Schristos if (tiv == NULL || tiv->data.length != trailersz) {
1549b9d004c6Schristos ret = KRB5_BAD_MSIZE;
1550b9d004c6Schristos goto cleanup;
1551ca1c9b0cSelric }
1552ca1c9b0cSelric
1553b9d004c6Schristos if (et->flags & F_ENC_THEN_CKSUM) {
1554b9d004c6Schristos unsigned char old_ivec[EVP_MAX_IV_LENGTH];
1555b9d004c6Schristos krb5_data ivec_data;
1556ca1c9b0cSelric
1557b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1558b9d004c6Schristos if(ret)
1559b9d004c6Schristos goto cleanup;
1560b9d004c6Schristos
1561b9d004c6Schristos ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1562b9d004c6Schristos if(ret)
1563b9d004c6Schristos goto cleanup;
1564b9d004c6Schristos
1565b9d004c6Schristos ret = _key_schedule(context, dkey);
1566b9d004c6Schristos if(ret)
1567b9d004c6Schristos goto cleanup;
1568b9d004c6Schristos
1569b9d004c6Schristos heim_assert(et->blocksize <= sizeof(old_ivec),
1570b9d004c6Schristos "blocksize too big for ivec buffer");
1571b9d004c6Schristos
1572b9d004c6Schristos if (ivec)
1573b9d004c6Schristos memcpy(old_ivec, ivec, et->blocksize);
1574b9d004c6Schristos else
1575b9d004c6Schristos memset(old_ivec, 0, et->blocksize);
1576b9d004c6Schristos
1577b9d004c6Schristos ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1578b9d004c6Schristos 1, usage, ivec);
1579b9d004c6Schristos if(ret)
1580b9d004c6Schristos goto cleanup;
1581b9d004c6Schristos
1582b9d004c6Schristos ret = iov_uncoalesce(context, &enc_data, data, num_data);
1583b9d004c6Schristos if(ret)
1584b9d004c6Schristos goto cleanup;
1585b9d004c6Schristos
1586b9d004c6Schristos ivec_data.length = et->blocksize;
1587b9d004c6Schristos ivec_data.data = old_ivec;
1588b9d004c6Schristos
1589b9d004c6Schristos ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1590b9d004c6Schristos if(ret)
1591b9d004c6Schristos goto cleanup;
1592b9d004c6Schristos } else {
1593b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data);
1594b9d004c6Schristos if(ret)
1595b9d004c6Schristos goto cleanup;
1596ca1c9b0cSelric }
1597ca1c9b0cSelric
1598ca1c9b0cSelric ret = create_checksum(context,
1599ca1c9b0cSelric et->keyed_checksum,
1600ca1c9b0cSelric crypto,
1601ca1c9b0cSelric INTEGRITY_USAGE(usage),
1602b9d004c6Schristos sign_data.data,
1603b9d004c6Schristos sign_data.length,
1604ca1c9b0cSelric &cksum);
1605ca1c9b0cSelric if(ret == 0 && cksum.checksum.length != trailersz) {
1606ca1c9b0cSelric free_Checksum (&cksum);
1607ca1c9b0cSelric krb5_clear_error_message (context);
1608ca1c9b0cSelric ret = KRB5_CRYPTO_INTERNAL;
1609ca1c9b0cSelric }
1610ca1c9b0cSelric if(ret)
1611b9d004c6Schristos goto cleanup;
1612ca1c9b0cSelric
1613ca1c9b0cSelric /* save cksum at end */
1614ca1c9b0cSelric memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1615ca1c9b0cSelric free_Checksum (&cksum);
1616ca1c9b0cSelric
1617b9d004c6Schristos if (!(et->flags & F_ENC_THEN_CKSUM)) {
1618b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1619b9d004c6Schristos if(ret)
1620b9d004c6Schristos goto cleanup;
1621ca1c9b0cSelric
1622ca1c9b0cSelric ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1623b9d004c6Schristos if(ret)
1624b9d004c6Schristos goto cleanup;
1625b9d004c6Schristos
1626ca1c9b0cSelric ret = _key_schedule(context, dkey);
1627b9d004c6Schristos if(ret)
1628b9d004c6Schristos goto cleanup;
1629b9d004c6Schristos
1630b9d004c6Schristos ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1631b9d004c6Schristos 1, usage, ivec);
1632b9d004c6Schristos if(ret)
1633b9d004c6Schristos goto cleanup;
1634b9d004c6Schristos
1635b9d004c6Schristos ret = iov_uncoalesce(context, &enc_data, data, num_data);
1636b9d004c6Schristos if(ret)
1637b9d004c6Schristos goto cleanup;
1638ca1c9b0cSelric }
1639ca1c9b0cSelric
1640b9d004c6Schristos cleanup:
1641b9d004c6Schristos if (enc_data.data) {
1642b9d004c6Schristos memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1643b9d004c6Schristos krb5_data_free(&enc_data);
1644ca1c9b0cSelric }
1645b9d004c6Schristos if (sign_data.data) {
1646b9d004c6Schristos memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1647b9d004c6Schristos krb5_data_free(&sign_data);
1648ca1c9b0cSelric }
1649ca1c9b0cSelric return ret;
1650ca1c9b0cSelric }
1651ca1c9b0cSelric
1652ca1c9b0cSelric /**
1653ca1c9b0cSelric * Inline decrypt a Kerberos message.
1654ca1c9b0cSelric *
1655ca1c9b0cSelric * @param context Kerberos context
1656ca1c9b0cSelric * @param crypto Kerberos crypto context
1657ca1c9b0cSelric * @param usage Key usage for this buffer
1658ca1c9b0cSelric * @param data array of buffers to process
1659ca1c9b0cSelric * @param num_data length of array
1660ca1c9b0cSelric * @param ivec initial cbc/cts vector
1661ca1c9b0cSelric *
1662ca1c9b0cSelric * @return Return an error code or 0.
1663ca1c9b0cSelric * @ingroup krb5_crypto
1664ca1c9b0cSelric *
1665ca1c9b0cSelric * 1. KRB5_CRYPTO_TYPE_HEADER
1666ca1c9b0cSelric * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1667ca1c9b0cSelric * any order, however the receiver have to aware of the
1668ca1c9b0cSelric * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1669ca1c9b0cSelric * protocol headers and trailers. The output data will be of same
1670ca1c9b0cSelric * size as the input data or shorter.
1671ca1c9b0cSelric */
1672ca1c9b0cSelric
1673ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decrypt_iov_ivec(krb5_context context,krb5_crypto crypto,unsigned usage,krb5_crypto_iov * data,unsigned int num_data,void * ivec)1674ca1c9b0cSelric krb5_decrypt_iov_ivec(krb5_context context,
1675ca1c9b0cSelric krb5_crypto crypto,
1676ca1c9b0cSelric unsigned usage,
1677ca1c9b0cSelric krb5_crypto_iov *data,
1678ca1c9b0cSelric unsigned int num_data,
1679ca1c9b0cSelric void *ivec)
1680ca1c9b0cSelric {
1681ca1c9b0cSelric Checksum cksum;
1682b9d004c6Schristos krb5_data enc_data, sign_data;
1683ca1c9b0cSelric krb5_error_code ret;
1684ca1c9b0cSelric struct _krb5_key_data *dkey;
1685ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1686ca1c9b0cSelric krb5_crypto_iov *tiv, *hiv;
1687ca1c9b0cSelric
1688ca1c9b0cSelric if(!derived_crypto(context, crypto)) {
1689ca1c9b0cSelric krb5_clear_error_message(context);
1690ca1c9b0cSelric return KRB5_CRYPTO_INTERNAL;
1691ca1c9b0cSelric }
1692ca1c9b0cSelric
1693b9d004c6Schristos /* header */
1694b9d004c6Schristos hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1695b9d004c6Schristos if (hiv == NULL || hiv->data.length != et->confoundersize)
1696ca1c9b0cSelric return KRB5_BAD_MSIZE;
1697ca1c9b0cSelric
1698ca1c9b0cSelric /* trailer */
1699b9d004c6Schristos tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1700b9d004c6Schristos if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum))
1701ca1c9b0cSelric return KRB5_BAD_MSIZE;
1702ca1c9b0cSelric
1703b9d004c6Schristos /* padding */
1704b9d004c6Schristos if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) {
1705ca1c9b0cSelric krb5_clear_error_message(context);
1706ca1c9b0cSelric return KRB5_BAD_MSIZE;
1707ca1c9b0cSelric }
1708ca1c9b0cSelric
1709b9d004c6Schristos krb5_data_zero(&enc_data);
1710b9d004c6Schristos krb5_data_zero(&sign_data);
1711ca1c9b0cSelric
1712b9d004c6Schristos if (!(et->flags & F_ENC_THEN_CKSUM)) {
1713b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1714b9d004c6Schristos if(ret)
1715b9d004c6Schristos goto cleanup;
1716ca1c9b0cSelric
1717ca1c9b0cSelric ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1718b9d004c6Schristos if(ret)
1719b9d004c6Schristos goto cleanup;
1720b9d004c6Schristos
1721ca1c9b0cSelric ret = _key_schedule(context, dkey);
1722b9d004c6Schristos if(ret)
1723b9d004c6Schristos goto cleanup;
1724ca1c9b0cSelric
1725b9d004c6Schristos ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1726b9d004c6Schristos 0, usage, ivec);
1727b9d004c6Schristos if(ret)
1728b9d004c6Schristos goto cleanup;
1729ca1c9b0cSelric
1730b9d004c6Schristos ret = iov_uncoalesce(context, &enc_data, data, num_data);
1731b9d004c6Schristos if(ret)
1732b9d004c6Schristos goto cleanup;
1733ca1c9b0cSelric
1734b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data);
1735b9d004c6Schristos if(ret)
1736b9d004c6Schristos goto cleanup;
1737b9d004c6Schristos } else {
1738b9d004c6Schristos krb5_data ivec_data;
1739b9d004c6Schristos static unsigned char zero_ivec[EVP_MAX_IV_LENGTH];
1740ca1c9b0cSelric
1741b9d004c6Schristos heim_assert(et->blocksize <= sizeof(zero_ivec),
1742b9d004c6Schristos "blocksize too big for ivec buffer");
1743ca1c9b0cSelric
1744b9d004c6Schristos ivec_data.length = et->blocksize;
1745b9d004c6Schristos ivec_data.data = ivec ? ivec : zero_ivec;
1746ca1c9b0cSelric
1747b9d004c6Schristos ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data);
1748b9d004c6Schristos if(ret)
1749b9d004c6Schristos goto cleanup;
1750ca1c9b0cSelric }
1751ca1c9b0cSelric
1752ca1c9b0cSelric cksum.checksum.data = tiv->data.data;
1753ca1c9b0cSelric cksum.checksum.length = tiv->data.length;
1754ca1c9b0cSelric cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1755ca1c9b0cSelric
1756ca1c9b0cSelric ret = verify_checksum(context,
1757ca1c9b0cSelric crypto,
1758ca1c9b0cSelric INTEGRITY_USAGE(usage),
1759b9d004c6Schristos sign_data.data,
1760b9d004c6Schristos sign_data.length,
1761ca1c9b0cSelric &cksum);
1762b9d004c6Schristos if(ret)
1763b9d004c6Schristos goto cleanup;
1764b9d004c6Schristos
1765b9d004c6Schristos if (et->flags & F_ENC_THEN_CKSUM) {
1766b9d004c6Schristos ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data);
1767b9d004c6Schristos if(ret)
1768b9d004c6Schristos goto cleanup;
1769b9d004c6Schristos
1770b9d004c6Schristos ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1771b9d004c6Schristos if(ret)
1772b9d004c6Schristos goto cleanup;
1773b9d004c6Schristos
1774b9d004c6Schristos ret = _key_schedule(context, dkey);
1775b9d004c6Schristos if(ret)
1776b9d004c6Schristos goto cleanup;
1777b9d004c6Schristos
1778b9d004c6Schristos ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length,
1779b9d004c6Schristos 0, usage, ivec);
1780b9d004c6Schristos if(ret)
1781b9d004c6Schristos goto cleanup;
1782b9d004c6Schristos
1783b9d004c6Schristos ret = iov_uncoalesce(context, &enc_data, data, num_data);
1784b9d004c6Schristos if(ret)
1785b9d004c6Schristos goto cleanup;
1786b9d004c6Schristos }
1787b9d004c6Schristos
1788b9d004c6Schristos cleanup:
1789b9d004c6Schristos if (enc_data.data) {
1790b9d004c6Schristos memset_s(enc_data.data, enc_data.length, 0, enc_data.length);
1791b9d004c6Schristos krb5_data_free(&enc_data);
1792b9d004c6Schristos }
1793b9d004c6Schristos if (sign_data.data) {
1794b9d004c6Schristos memset_s(sign_data.data, sign_data.length, 0, sign_data.length);
1795b9d004c6Schristos krb5_data_free(&sign_data);
1796b9d004c6Schristos }
1797ca1c9b0cSelric return ret;
1798ca1c9b0cSelric }
1799ca1c9b0cSelric
1800ca1c9b0cSelric /**
1801ca1c9b0cSelric * Create a Kerberos message checksum.
1802ca1c9b0cSelric *
1803ca1c9b0cSelric * @param context Kerberos context
1804ca1c9b0cSelric * @param crypto Kerberos crypto context
1805ca1c9b0cSelric * @param usage Key usage for this buffer
1806ca1c9b0cSelric * @param data array of buffers to process
1807ca1c9b0cSelric * @param num_data length of array
1808ca1c9b0cSelric * @param type output data
1809ca1c9b0cSelric *
1810ca1c9b0cSelric * @return Return an error code or 0.
1811ca1c9b0cSelric * @ingroup krb5_crypto
1812ca1c9b0cSelric */
1813ca1c9b0cSelric
1814ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_create_checksum_iov(krb5_context context,krb5_crypto crypto,unsigned usage,krb5_crypto_iov * data,unsigned int num_data,krb5_cksumtype * type)1815ca1c9b0cSelric krb5_create_checksum_iov(krb5_context context,
1816ca1c9b0cSelric krb5_crypto crypto,
1817ca1c9b0cSelric unsigned usage,
1818ca1c9b0cSelric krb5_crypto_iov *data,
1819ca1c9b0cSelric unsigned int num_data,
1820ca1c9b0cSelric krb5_cksumtype *type)
1821ca1c9b0cSelric {
1822ca1c9b0cSelric Checksum cksum;
1823ca1c9b0cSelric krb5_crypto_iov *civ;
1824ca1c9b0cSelric krb5_error_code ret;
18254f77a458Spettai size_t i;
1826ca1c9b0cSelric size_t len;
1827ca1c9b0cSelric char *p, *q;
1828ca1c9b0cSelric
1829ca1c9b0cSelric if(!derived_crypto(context, crypto)) {
1830ca1c9b0cSelric krb5_clear_error_message(context);
1831ca1c9b0cSelric return KRB5_CRYPTO_INTERNAL;
1832ca1c9b0cSelric }
1833ca1c9b0cSelric
1834b9d004c6Schristos civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1835ca1c9b0cSelric if (civ == NULL)
1836ca1c9b0cSelric return KRB5_BAD_MSIZE;
1837ca1c9b0cSelric
1838ca1c9b0cSelric len = 0;
1839ca1c9b0cSelric for (i = 0; i < num_data; i++) {
1840ca1c9b0cSelric if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1841ca1c9b0cSelric data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1842ca1c9b0cSelric continue;
1843ca1c9b0cSelric len += data[i].data.length;
1844ca1c9b0cSelric }
1845ca1c9b0cSelric
1846ca1c9b0cSelric p = q = malloc(len);
1847ca1c9b0cSelric
1848ca1c9b0cSelric for (i = 0; i < num_data; i++) {
1849ca1c9b0cSelric if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1850ca1c9b0cSelric data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1851ca1c9b0cSelric continue;
1852ca1c9b0cSelric memcpy(q, data[i].data.data, data[i].data.length);
1853ca1c9b0cSelric q += data[i].data.length;
1854ca1c9b0cSelric }
1855ca1c9b0cSelric
1856ca1c9b0cSelric ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1857ca1c9b0cSelric free(p);
1858ca1c9b0cSelric if (ret)
1859ca1c9b0cSelric return ret;
1860ca1c9b0cSelric
1861ca1c9b0cSelric if (type)
1862ca1c9b0cSelric *type = cksum.cksumtype;
1863ca1c9b0cSelric
1864ca1c9b0cSelric if (cksum.checksum.length > civ->data.length) {
1865ca1c9b0cSelric krb5_set_error_message(context, KRB5_BAD_MSIZE,
1866ca1c9b0cSelric N_("Checksum larger then input buffer", ""));
1867ca1c9b0cSelric free_Checksum(&cksum);
1868ca1c9b0cSelric return KRB5_BAD_MSIZE;
1869ca1c9b0cSelric }
1870ca1c9b0cSelric
1871ca1c9b0cSelric civ->data.length = cksum.checksum.length;
1872ca1c9b0cSelric memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1873ca1c9b0cSelric free_Checksum(&cksum);
1874ca1c9b0cSelric
1875ca1c9b0cSelric return 0;
1876ca1c9b0cSelric }
1877ca1c9b0cSelric
1878ca1c9b0cSelric /**
1879ca1c9b0cSelric * Verify a Kerberos message checksum.
1880ca1c9b0cSelric *
1881ca1c9b0cSelric * @param context Kerberos context
1882ca1c9b0cSelric * @param crypto Kerberos crypto context
1883ca1c9b0cSelric * @param usage Key usage for this buffer
1884ca1c9b0cSelric * @param data array of buffers to process
1885ca1c9b0cSelric * @param num_data length of array
1886ca1c9b0cSelric * @param type return checksum type if not NULL
1887ca1c9b0cSelric *
1888ca1c9b0cSelric * @return Return an error code or 0.
1889ca1c9b0cSelric * @ingroup krb5_crypto
1890ca1c9b0cSelric */
1891ca1c9b0cSelric
1892ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_checksum_iov(krb5_context context,krb5_crypto crypto,unsigned usage,krb5_crypto_iov * data,unsigned int num_data,krb5_cksumtype * type)1893ca1c9b0cSelric krb5_verify_checksum_iov(krb5_context context,
1894ca1c9b0cSelric krb5_crypto crypto,
1895ca1c9b0cSelric unsigned usage,
1896ca1c9b0cSelric krb5_crypto_iov *data,
1897ca1c9b0cSelric unsigned int num_data,
1898ca1c9b0cSelric krb5_cksumtype *type)
1899ca1c9b0cSelric {
1900ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
1901ca1c9b0cSelric Checksum cksum;
1902ca1c9b0cSelric krb5_crypto_iov *civ;
1903ca1c9b0cSelric krb5_error_code ret;
19044f77a458Spettai size_t i;
1905ca1c9b0cSelric size_t len;
1906ca1c9b0cSelric char *p, *q;
1907ca1c9b0cSelric
1908ca1c9b0cSelric if(!derived_crypto(context, crypto)) {
1909ca1c9b0cSelric krb5_clear_error_message(context);
1910ca1c9b0cSelric return KRB5_CRYPTO_INTERNAL;
1911ca1c9b0cSelric }
1912ca1c9b0cSelric
1913b9d004c6Schristos civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1914ca1c9b0cSelric if (civ == NULL)
1915ca1c9b0cSelric return KRB5_BAD_MSIZE;
1916ca1c9b0cSelric
1917ca1c9b0cSelric len = 0;
1918ca1c9b0cSelric for (i = 0; i < num_data; i++) {
1919ca1c9b0cSelric if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1920ca1c9b0cSelric data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1921ca1c9b0cSelric continue;
1922ca1c9b0cSelric len += data[i].data.length;
1923ca1c9b0cSelric }
1924ca1c9b0cSelric
1925ca1c9b0cSelric p = q = malloc(len);
1926ca1c9b0cSelric
1927ca1c9b0cSelric for (i = 0; i < num_data; i++) {
1928ca1c9b0cSelric if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1929ca1c9b0cSelric data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1930ca1c9b0cSelric continue;
1931ca1c9b0cSelric memcpy(q, data[i].data.data, data[i].data.length);
1932ca1c9b0cSelric q += data[i].data.length;
1933ca1c9b0cSelric }
1934ca1c9b0cSelric
1935ca1c9b0cSelric cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1936ca1c9b0cSelric cksum.checksum.length = civ->data.length;
1937ca1c9b0cSelric cksum.checksum.data = civ->data.data;
1938ca1c9b0cSelric
1939ca1c9b0cSelric ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1940ca1c9b0cSelric free(p);
1941ca1c9b0cSelric
1942ca1c9b0cSelric if (ret == 0 && type)
1943ca1c9b0cSelric *type = cksum.cksumtype;
1944ca1c9b0cSelric
1945ca1c9b0cSelric return ret;
1946ca1c9b0cSelric }
1947ca1c9b0cSelric
1948ca1c9b0cSelric
1949ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_length(krb5_context context,krb5_crypto crypto,int type,size_t * len)1950ca1c9b0cSelric krb5_crypto_length(krb5_context context,
1951ca1c9b0cSelric krb5_crypto crypto,
1952ca1c9b0cSelric int type,
1953ca1c9b0cSelric size_t *len)
1954ca1c9b0cSelric {
1955ca1c9b0cSelric if (!derived_crypto(context, crypto)) {
1956ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "not a derived crypto");
1957ca1c9b0cSelric return EINVAL;
1958ca1c9b0cSelric }
1959ca1c9b0cSelric
1960ca1c9b0cSelric switch(type) {
1961ca1c9b0cSelric case KRB5_CRYPTO_TYPE_EMPTY:
1962ca1c9b0cSelric *len = 0;
1963ca1c9b0cSelric return 0;
1964ca1c9b0cSelric case KRB5_CRYPTO_TYPE_HEADER:
1965ca1c9b0cSelric *len = crypto->et->blocksize;
1966ca1c9b0cSelric return 0;
1967ca1c9b0cSelric case KRB5_CRYPTO_TYPE_DATA:
1968ca1c9b0cSelric case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1969ca1c9b0cSelric /* len must already been filled in */
1970ca1c9b0cSelric return 0;
1971ca1c9b0cSelric case KRB5_CRYPTO_TYPE_PADDING:
1972ca1c9b0cSelric if (crypto->et->padsize > 1)
1973ca1c9b0cSelric *len = crypto->et->padsize;
1974ca1c9b0cSelric else
1975ca1c9b0cSelric *len = 0;
1976ca1c9b0cSelric return 0;
1977ca1c9b0cSelric case KRB5_CRYPTO_TYPE_TRAILER:
1978ca1c9b0cSelric *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1979ca1c9b0cSelric return 0;
1980ca1c9b0cSelric case KRB5_CRYPTO_TYPE_CHECKSUM:
1981ca1c9b0cSelric if (crypto->et->keyed_checksum)
1982ca1c9b0cSelric *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1983ca1c9b0cSelric else
1984ca1c9b0cSelric *len = CHECKSUMSIZE(crypto->et->checksum);
1985ca1c9b0cSelric return 0;
1986ca1c9b0cSelric }
1987ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
1988ca1c9b0cSelric "%d not a supported type", type);
1989ca1c9b0cSelric return EINVAL;
1990ca1c9b0cSelric }
1991ca1c9b0cSelric
1992ca1c9b0cSelric
1993ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_length_iov(krb5_context context,krb5_crypto crypto,krb5_crypto_iov * data,unsigned int num_data)1994ca1c9b0cSelric krb5_crypto_length_iov(krb5_context context,
1995ca1c9b0cSelric krb5_crypto crypto,
1996ca1c9b0cSelric krb5_crypto_iov *data,
1997ca1c9b0cSelric unsigned int num_data)
1998ca1c9b0cSelric {
1999ca1c9b0cSelric krb5_error_code ret;
20004f77a458Spettai size_t i;
2001ca1c9b0cSelric
2002ca1c9b0cSelric for (i = 0; i < num_data; i++) {
2003ca1c9b0cSelric ret = krb5_crypto_length(context, crypto,
2004ca1c9b0cSelric data[i].flags,
2005ca1c9b0cSelric &data[i].data.length);
2006ca1c9b0cSelric if (ret)
2007ca1c9b0cSelric return ret;
2008ca1c9b0cSelric }
2009ca1c9b0cSelric return 0;
2010ca1c9b0cSelric }
2011ca1c9b0cSelric
2012ca1c9b0cSelric
2013ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_encrypt_ivec(krb5_context context,krb5_crypto crypto,unsigned usage,const void * data,size_t len,krb5_data * result,void * ivec)2014ca1c9b0cSelric krb5_encrypt_ivec(krb5_context context,
2015ca1c9b0cSelric krb5_crypto crypto,
2016ca1c9b0cSelric unsigned usage,
2017ca1c9b0cSelric const void *data,
2018ca1c9b0cSelric size_t len,
2019ca1c9b0cSelric krb5_data *result,
2020ca1c9b0cSelric void *ivec)
2021ca1c9b0cSelric {
2022b9d004c6Schristos krb5_error_code ret;
2023b9d004c6Schristos
2024b9d004c6Schristos switch (crypto->et->flags & F_CRYPTO_MASK) {
2025b9d004c6Schristos case F_RFC3961_ENC:
2026b9d004c6Schristos ret = encrypt_internal_derived(context, crypto, usage,
2027ca1c9b0cSelric data, len, result, ivec);
2028b9d004c6Schristos break;
2029b9d004c6Schristos case F_SPECIAL:
2030b9d004c6Schristos ret = encrypt_internal_special (context, crypto, usage,
2031ca1c9b0cSelric data, len, result, ivec);
2032b9d004c6Schristos break;
2033b9d004c6Schristos case F_ENC_THEN_CKSUM:
2034b9d004c6Schristos ret = encrypt_internal_enc_then_cksum(context, crypto, usage,
2035b9d004c6Schristos data, len, result, ivec);
2036b9d004c6Schristos break;
2037b9d004c6Schristos default:
2038b9d004c6Schristos ret = encrypt_internal(context, crypto, data, len, result, ivec);
2039b9d004c6Schristos break;
2040b9d004c6Schristos }
2041b9d004c6Schristos
2042b9d004c6Schristos return ret;
2043ca1c9b0cSelric }
2044ca1c9b0cSelric
2045ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_encrypt(krb5_context context,krb5_crypto crypto,unsigned usage,const void * data,size_t len,krb5_data * result)2046ca1c9b0cSelric krb5_encrypt(krb5_context context,
2047ca1c9b0cSelric krb5_crypto crypto,
2048ca1c9b0cSelric unsigned usage,
2049ca1c9b0cSelric const void *data,
2050ca1c9b0cSelric size_t len,
2051ca1c9b0cSelric krb5_data *result)
2052ca1c9b0cSelric {
2053ca1c9b0cSelric return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
2054ca1c9b0cSelric }
2055ca1c9b0cSelric
2056ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_encrypt_EncryptedData(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,int kvno,EncryptedData * result)2057ca1c9b0cSelric krb5_encrypt_EncryptedData(krb5_context context,
2058ca1c9b0cSelric krb5_crypto crypto,
2059ca1c9b0cSelric unsigned usage,
2060ca1c9b0cSelric void *data,
2061ca1c9b0cSelric size_t len,
2062ca1c9b0cSelric int kvno,
2063ca1c9b0cSelric EncryptedData *result)
2064ca1c9b0cSelric {
2065ca1c9b0cSelric result->etype = CRYPTO_ETYPE(crypto);
2066ca1c9b0cSelric if(kvno){
2067ca1c9b0cSelric ALLOC(result->kvno, 1);
2068ca1c9b0cSelric *result->kvno = kvno;
2069ca1c9b0cSelric }else
2070ca1c9b0cSelric result->kvno = NULL;
2071ca1c9b0cSelric return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
2072ca1c9b0cSelric }
2073ca1c9b0cSelric
2074ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decrypt_ivec(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,krb5_data * result,void * ivec)2075ca1c9b0cSelric krb5_decrypt_ivec(krb5_context context,
2076ca1c9b0cSelric krb5_crypto crypto,
2077ca1c9b0cSelric unsigned usage,
2078ca1c9b0cSelric void *data,
2079ca1c9b0cSelric size_t len,
2080ca1c9b0cSelric krb5_data *result,
2081ca1c9b0cSelric void *ivec)
2082ca1c9b0cSelric {
2083b9d004c6Schristos krb5_error_code ret;
2084b9d004c6Schristos
2085b9d004c6Schristos switch (crypto->et->flags & F_CRYPTO_MASK) {
2086b9d004c6Schristos case F_RFC3961_ENC:
2087b9d004c6Schristos ret = decrypt_internal_derived(context, crypto, usage,
2088ca1c9b0cSelric data, len, result, ivec);
2089b9d004c6Schristos break;
2090b9d004c6Schristos case F_SPECIAL:
2091b9d004c6Schristos ret = decrypt_internal_special(context, crypto, usage,
2092ca1c9b0cSelric data, len, result, ivec);
2093b9d004c6Schristos break;
2094b9d004c6Schristos case F_ENC_THEN_CKSUM:
2095b9d004c6Schristos ret = decrypt_internal_enc_then_cksum(context, crypto, usage,
2096b9d004c6Schristos data, len, result, ivec);
2097b9d004c6Schristos break;
2098b9d004c6Schristos default:
2099b9d004c6Schristos ret = decrypt_internal(context, crypto, data, len, result, ivec);
2100b9d004c6Schristos break;
2101b9d004c6Schristos }
2102b9d004c6Schristos
2103b9d004c6Schristos return ret;
2104ca1c9b0cSelric }
2105ca1c9b0cSelric
2106ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decrypt(krb5_context context,krb5_crypto crypto,unsigned usage,void * data,size_t len,krb5_data * result)2107ca1c9b0cSelric krb5_decrypt(krb5_context context,
2108ca1c9b0cSelric krb5_crypto crypto,
2109ca1c9b0cSelric unsigned usage,
2110ca1c9b0cSelric void *data,
2111ca1c9b0cSelric size_t len,
2112ca1c9b0cSelric krb5_data *result)
2113ca1c9b0cSelric {
2114ca1c9b0cSelric return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
2115ca1c9b0cSelric NULL);
2116ca1c9b0cSelric }
2117ca1c9b0cSelric
2118ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_decrypt_EncryptedData(krb5_context context,krb5_crypto crypto,unsigned usage,const EncryptedData * e,krb5_data * result)2119ca1c9b0cSelric krb5_decrypt_EncryptedData(krb5_context context,
2120ca1c9b0cSelric krb5_crypto crypto,
2121ca1c9b0cSelric unsigned usage,
2122ca1c9b0cSelric const EncryptedData *e,
2123ca1c9b0cSelric krb5_data *result)
2124ca1c9b0cSelric {
2125ca1c9b0cSelric return krb5_decrypt(context, crypto, usage,
2126ca1c9b0cSelric e->cipher.data, e->cipher.length, result);
2127ca1c9b0cSelric }
2128ca1c9b0cSelric
2129ca1c9b0cSelric /************************************************************
2130ca1c9b0cSelric * *
2131ca1c9b0cSelric ************************************************************/
2132ca1c9b0cSelric
2133b9d004c6Schristos static krb5_error_code
derive_key_rfc3961(krb5_context context,struct _krb5_encryption_type * et,struct _krb5_key_data * key,const void * constant,size_t len)2134b9d004c6Schristos derive_key_rfc3961(krb5_context context,
2135ca1c9b0cSelric struct _krb5_encryption_type *et,
2136ca1c9b0cSelric struct _krb5_key_data *key,
2137ca1c9b0cSelric const void *constant,
2138ca1c9b0cSelric size_t len)
2139ca1c9b0cSelric {
2140b9d004c6Schristos
2141ca1c9b0cSelric unsigned char *k = NULL;
2142ca1c9b0cSelric unsigned int nblocks = 0, i;
2143ca1c9b0cSelric krb5_error_code ret = 0;
2144ca1c9b0cSelric struct _krb5_key_type *kt = et->keytype;
2145ca1c9b0cSelric
2146ca1c9b0cSelric if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
2147ca1c9b0cSelric nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
2148ca1c9b0cSelric k = malloc(nblocks * et->blocksize);
2149ca1c9b0cSelric if(k == NULL) {
2150b9d004c6Schristos ret = krb5_enomem(context);
2151ca1c9b0cSelric goto out;
2152ca1c9b0cSelric }
2153ca1c9b0cSelric ret = _krb5_n_fold(constant, len, k, et->blocksize);
2154ca1c9b0cSelric if (ret) {
2155b9d004c6Schristos krb5_enomem(context);
2156ca1c9b0cSelric goto out;
2157ca1c9b0cSelric }
2158ca1c9b0cSelric
2159ca1c9b0cSelric for(i = 0; i < nblocks; i++) {
2160ca1c9b0cSelric if(i > 0)
2161ca1c9b0cSelric memcpy(k + i * et->blocksize,
2162ca1c9b0cSelric k + (i - 1) * et->blocksize,
2163ca1c9b0cSelric et->blocksize);
2164ca1c9b0cSelric (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
2165ca1c9b0cSelric 1, 0, NULL);
2166ca1c9b0cSelric }
2167ca1c9b0cSelric } else {
2168ca1c9b0cSelric /* this case is probably broken, but won't be run anyway */
2169ca1c9b0cSelric void *c = malloc(len);
2170ca1c9b0cSelric size_t res_len = (kt->bits + 7) / 8;
2171ca1c9b0cSelric
2172ca1c9b0cSelric if(len != 0 && c == NULL) {
2173b9d004c6Schristos ret = krb5_enomem(context);
2174ca1c9b0cSelric goto out;
2175ca1c9b0cSelric }
2176ca1c9b0cSelric memcpy(c, constant, len);
2177ca1c9b0cSelric (*et->encrypt)(context, key, c, len, 1, 0, NULL);
2178ca1c9b0cSelric k = malloc(res_len);
2179ca1c9b0cSelric if(res_len != 0 && k == NULL) {
2180ca1c9b0cSelric free(c);
2181b9d004c6Schristos ret = krb5_enomem(context);
2182ca1c9b0cSelric goto out;
2183ca1c9b0cSelric }
2184ca1c9b0cSelric ret = _krb5_n_fold(c, len, k, res_len);
2185ca1c9b0cSelric free(c);
2186ca1c9b0cSelric if (ret) {
2187b9d004c6Schristos krb5_enomem(context);
2188ca1c9b0cSelric goto out;
2189ca1c9b0cSelric }
2190ca1c9b0cSelric }
2191ca1c9b0cSelric
2192b9d004c6Schristos if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1)
2193ca1c9b0cSelric _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
2194b9d004c6Schristos else
2195ca1c9b0cSelric memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
2196b9d004c6Schristos
2197b9d004c6Schristos out:
2198b9d004c6Schristos if (k) {
2199b9d004c6Schristos memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize);
2200b9d004c6Schristos free(k);
2201b9d004c6Schristos }
2202b9d004c6Schristos return ret;
2203b9d004c6Schristos }
2204b9d004c6Schristos
2205b9d004c6Schristos static krb5_error_code
derive_key_sp800_hmac(krb5_context context,struct _krb5_encryption_type * et,struct _krb5_key_data * key,const void * constant,size_t len)2206b9d004c6Schristos derive_key_sp800_hmac(krb5_context context,
2207b9d004c6Schristos struct _krb5_encryption_type *et,
2208b9d004c6Schristos struct _krb5_key_data *key,
2209b9d004c6Schristos const void *constant,
2210b9d004c6Schristos size_t len)
2211b9d004c6Schristos {
2212b9d004c6Schristos krb5_error_code ret;
2213b9d004c6Schristos struct _krb5_key_type *kt = et->keytype;
2214b9d004c6Schristos krb5_data label;
2215b9d004c6Schristos const EVP_MD *md = NULL;
2216b9d004c6Schristos const unsigned char *c = constant;
2217b9d004c6Schristos size_t key_len;
2218b9d004c6Schristos krb5_data K1;
2219b9d004c6Schristos
2220b9d004c6Schristos ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md);
2221b9d004c6Schristos if (ret)
2222b9d004c6Schristos return ret;
2223b9d004c6Schristos
2224b9d004c6Schristos /*
2225b9d004c6Schristos * PRF usage: not handled here (output cannot be longer)
2226b9d004c6Schristos * Integrity usage: truncated hash (half length)
2227b9d004c6Schristos * Encryption usage: base key length
2228b9d004c6Schristos */
2229b9d004c6Schristos if (len == 5 && (c[4] == 0x99 || c[4] == 0x55))
2230b9d004c6Schristos key_len = EVP_MD_size(md) / 2;
2231b9d004c6Schristos else
2232b9d004c6Schristos key_len = kt->size;
2233b9d004c6Schristos
2234b9d004c6Schristos ret = krb5_data_alloc(&K1, key_len);
2235b9d004c6Schristos if (ret)
2236b9d004c6Schristos return ret;
2237b9d004c6Schristos
2238b9d004c6Schristos label.data = (void *)constant;
2239b9d004c6Schristos label.length = len;
2240b9d004c6Schristos
2241b9d004c6Schristos ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue,
2242b9d004c6Schristos &label, NULL, md, &K1);
2243b9d004c6Schristos if (ret == 0) {
2244b9d004c6Schristos if (key->key->keyvalue.length > key_len)
2245b9d004c6Schristos key->key->keyvalue.length = key_len;
2246b9d004c6Schristos memcpy(key->key->keyvalue.data, K1.data, key_len);
2247b9d004c6Schristos }
2248b9d004c6Schristos
2249b9d004c6Schristos memset_s(K1.data, K1.length, 0, K1.length);
2250b9d004c6Schristos krb5_data_free(&K1);
2251b9d004c6Schristos
2252b9d004c6Schristos return ret;
2253b9d004c6Schristos }
2254b9d004c6Schristos
2255b9d004c6Schristos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_derive_key(krb5_context context,struct _krb5_encryption_type * et,struct _krb5_key_data * key,const void * constant,size_t len)2256b9d004c6Schristos _krb5_derive_key(krb5_context context,
2257b9d004c6Schristos struct _krb5_encryption_type *et,
2258b9d004c6Schristos struct _krb5_key_data *key,
2259b9d004c6Schristos const void *constant,
2260b9d004c6Schristos size_t len)
2261b9d004c6Schristos {
2262b9d004c6Schristos krb5_error_code ret;
2263b9d004c6Schristos
2264b9d004c6Schristos ret = _key_schedule(context, key);
2265b9d004c6Schristos if(ret)
2266b9d004c6Schristos return ret;
2267b9d004c6Schristos
2268b9d004c6Schristos switch (et->flags & F_KDF_MASK) {
2269b9d004c6Schristos case F_RFC3961_KDF:
2270b9d004c6Schristos ret = derive_key_rfc3961(context, et, key, constant, len);
2271b9d004c6Schristos break;
2272b9d004c6Schristos case F_SP800_108_HMAC_KDF:
2273b9d004c6Schristos ret = derive_key_sp800_hmac(context, et, key, constant, len);
2274ca1c9b0cSelric break;
2275ca1c9b0cSelric default:
2276ca1c9b0cSelric ret = KRB5_CRYPTO_INTERNAL;
2277ca1c9b0cSelric krb5_set_error_message(context, ret,
2278ca1c9b0cSelric N_("derive_key() called with unknown keytype (%u)", ""),
2279b9d004c6Schristos et->keytype->type);
2280ca1c9b0cSelric break;
2281ca1c9b0cSelric }
2282b9d004c6Schristos
2283ca1c9b0cSelric if (key->schedule) {
2284ca1c9b0cSelric free_key_schedule(context, key, et);
2285ca1c9b0cSelric key->schedule = NULL;
2286ca1c9b0cSelric }
2287b9d004c6Schristos
2288ca1c9b0cSelric return ret;
2289ca1c9b0cSelric }
2290ca1c9b0cSelric
2291ca1c9b0cSelric static struct _krb5_key_data *
_new_derived_key(krb5_crypto crypto,unsigned usage)2292ca1c9b0cSelric _new_derived_key(krb5_crypto crypto, unsigned usage)
2293ca1c9b0cSelric {
2294ca1c9b0cSelric struct _krb5_key_usage *d = crypto->key_usage;
2295ca1c9b0cSelric d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
2296ca1c9b0cSelric if(d == NULL)
2297ca1c9b0cSelric return NULL;
2298ca1c9b0cSelric crypto->key_usage = d;
2299ca1c9b0cSelric d += crypto->num_key_usage++;
2300ca1c9b0cSelric memset(d, 0, sizeof(*d));
2301ca1c9b0cSelric d->usage = usage;
2302ca1c9b0cSelric return &d->key;
2303ca1c9b0cSelric }
2304ca1c9b0cSelric
2305ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_derive_key(krb5_context context,const krb5_keyblock * key,krb5_enctype etype,const void * constant,size_t constant_len,krb5_keyblock ** derived_key)2306ca1c9b0cSelric krb5_derive_key(krb5_context context,
2307ca1c9b0cSelric const krb5_keyblock *key,
2308ca1c9b0cSelric krb5_enctype etype,
2309ca1c9b0cSelric const void *constant,
2310ca1c9b0cSelric size_t constant_len,
2311ca1c9b0cSelric krb5_keyblock **derived_key)
2312ca1c9b0cSelric {
2313ca1c9b0cSelric krb5_error_code ret;
2314ca1c9b0cSelric struct _krb5_encryption_type *et;
2315ca1c9b0cSelric struct _krb5_key_data d;
2316ca1c9b0cSelric
2317ca1c9b0cSelric *derived_key = NULL;
2318ca1c9b0cSelric
2319ca1c9b0cSelric et = _krb5_find_enctype (etype);
2320ca1c9b0cSelric if (et == NULL) {
23214f77a458Spettai return unsupported_enctype (context, etype);
2322ca1c9b0cSelric }
2323ca1c9b0cSelric
2324ca1c9b0cSelric ret = krb5_copy_keyblock(context, key, &d.key);
2325ca1c9b0cSelric if (ret)
2326ca1c9b0cSelric return ret;
2327ca1c9b0cSelric
2328ca1c9b0cSelric d.schedule = NULL;
2329ca1c9b0cSelric ret = _krb5_derive_key(context, et, &d, constant, constant_len);
2330ca1c9b0cSelric if (ret == 0)
2331ca1c9b0cSelric ret = krb5_copy_keyblock(context, d.key, derived_key);
2332ca1c9b0cSelric _krb5_free_key_data(context, &d, et);
2333ca1c9b0cSelric return ret;
2334ca1c9b0cSelric }
2335ca1c9b0cSelric
2336ca1c9b0cSelric static krb5_error_code
_get_derived_key(krb5_context context,krb5_crypto crypto,unsigned usage,struct _krb5_key_data ** key)2337ca1c9b0cSelric _get_derived_key(krb5_context context,
2338ca1c9b0cSelric krb5_crypto crypto,
2339ca1c9b0cSelric unsigned usage,
2340ca1c9b0cSelric struct _krb5_key_data **key)
2341ca1c9b0cSelric {
2342ca1c9b0cSelric int i;
2343ca1c9b0cSelric struct _krb5_key_data *d;
2344ca1c9b0cSelric unsigned char constant[5];
2345ca1c9b0cSelric
2346b9d004c6Schristos *key = NULL;
2347ca1c9b0cSelric for(i = 0; i < crypto->num_key_usage; i++)
2348ca1c9b0cSelric if(crypto->key_usage[i].usage == usage) {
2349ca1c9b0cSelric *key = &crypto->key_usage[i].key;
2350ca1c9b0cSelric return 0;
2351ca1c9b0cSelric }
2352ca1c9b0cSelric d = _new_derived_key(crypto, usage);
2353b9d004c6Schristos if (d == NULL)
2354b9d004c6Schristos return krb5_enomem(context);
2355ca1c9b0cSelric *key = d;
2356b9d004c6Schristos krb5_copy_keyblock(context, crypto->key.key, &d->key);
2357b9d004c6Schristos _krb5_put_int(constant, usage, sizeof(constant));
2358b9d004c6Schristos return _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2359ca1c9b0cSelric }
2360ca1c9b0cSelric
2361ca1c9b0cSelric /**
2362ca1c9b0cSelric * Create a crypto context used for all encryption and signature
2363ca1c9b0cSelric * operation. The encryption type to use is taken from the key, but
2364ca1c9b0cSelric * can be overridden with the enctype parameter. This can be useful
2365ca1c9b0cSelric * for encryptions types which is compatiable (DES for example).
2366ca1c9b0cSelric *
2367ca1c9b0cSelric * To free the crypto context, use krb5_crypto_destroy().
2368ca1c9b0cSelric *
2369ca1c9b0cSelric * @param context Kerberos context
2370ca1c9b0cSelric * @param key the key block information with all key data
2371ca1c9b0cSelric * @param etype the encryption type
2372ca1c9b0cSelric * @param crypto the resulting crypto context
2373ca1c9b0cSelric *
2374ca1c9b0cSelric * @return Return an error code or 0.
2375ca1c9b0cSelric *
2376ca1c9b0cSelric * @ingroup krb5_crypto
2377ca1c9b0cSelric */
2378ca1c9b0cSelric
2379ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_init(krb5_context context,const krb5_keyblock * key,krb5_enctype etype,krb5_crypto * crypto)2380ca1c9b0cSelric krb5_crypto_init(krb5_context context,
2381ca1c9b0cSelric const krb5_keyblock *key,
2382ca1c9b0cSelric krb5_enctype etype,
2383ca1c9b0cSelric krb5_crypto *crypto)
2384ca1c9b0cSelric {
2385ca1c9b0cSelric krb5_error_code ret;
2386ca1c9b0cSelric ALLOC(*crypto, 1);
2387b9d004c6Schristos if (*crypto == NULL)
2388b9d004c6Schristos return krb5_enomem(context);
2389b9d004c6Schristos if(etype == (krb5_enctype)ETYPE_NULL)
2390ca1c9b0cSelric etype = key->keytype;
2391ca1c9b0cSelric (*crypto)->et = _krb5_find_enctype(etype);
2392ca1c9b0cSelric if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2393ca1c9b0cSelric free(*crypto);
2394ca1c9b0cSelric *crypto = NULL;
23954f77a458Spettai return unsupported_enctype(context, etype);
2396ca1c9b0cSelric }
2397ca1c9b0cSelric if((*crypto)->et->keytype->size != key->keyvalue.length) {
2398ca1c9b0cSelric free(*crypto);
2399ca1c9b0cSelric *crypto = NULL;
2400ca1c9b0cSelric krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2401ca1c9b0cSelric "encryption key has bad length");
2402ca1c9b0cSelric return KRB5_BAD_KEYSIZE;
2403ca1c9b0cSelric }
2404ca1c9b0cSelric ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2405ca1c9b0cSelric if(ret) {
2406ca1c9b0cSelric free(*crypto);
2407ca1c9b0cSelric *crypto = NULL;
2408ca1c9b0cSelric return ret;
2409ca1c9b0cSelric }
2410ca1c9b0cSelric (*crypto)->key.schedule = NULL;
2411ca1c9b0cSelric (*crypto)->num_key_usage = 0;
2412ca1c9b0cSelric (*crypto)->key_usage = NULL;
2413ca1c9b0cSelric return 0;
2414ca1c9b0cSelric }
2415ca1c9b0cSelric
2416ca1c9b0cSelric static void
free_key_schedule(krb5_context context,struct _krb5_key_data * key,struct _krb5_encryption_type * et)2417ca1c9b0cSelric free_key_schedule(krb5_context context,
2418ca1c9b0cSelric struct _krb5_key_data *key,
2419ca1c9b0cSelric struct _krb5_encryption_type *et)
2420ca1c9b0cSelric {
2421ca1c9b0cSelric if (et->keytype->cleanup)
2422ca1c9b0cSelric (*et->keytype->cleanup)(context, key);
2423ca1c9b0cSelric memset(key->schedule->data, 0, key->schedule->length);
2424ca1c9b0cSelric krb5_free_data(context, key->schedule);
2425ca1c9b0cSelric }
2426ca1c9b0cSelric
2427b9d004c6Schristos KRB5_LIB_FUNCTION void KRB5_LIB_CALL
_krb5_free_key_data(krb5_context context,struct _krb5_key_data * key,struct _krb5_encryption_type * et)2428ca1c9b0cSelric _krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2429ca1c9b0cSelric struct _krb5_encryption_type *et)
2430ca1c9b0cSelric {
2431ca1c9b0cSelric krb5_free_keyblock(context, key->key);
2432ca1c9b0cSelric if(key->schedule) {
2433ca1c9b0cSelric free_key_schedule(context, key, et);
2434ca1c9b0cSelric key->schedule = NULL;
2435ca1c9b0cSelric }
2436ca1c9b0cSelric }
2437ca1c9b0cSelric
2438ca1c9b0cSelric static void
free_key_usage(krb5_context context,struct _krb5_key_usage * ku,struct _krb5_encryption_type * et)2439ca1c9b0cSelric free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2440ca1c9b0cSelric struct _krb5_encryption_type *et)
2441ca1c9b0cSelric {
2442ca1c9b0cSelric _krb5_free_key_data(context, &ku->key, et);
2443ca1c9b0cSelric }
2444ca1c9b0cSelric
2445ca1c9b0cSelric /**
2446ca1c9b0cSelric * Free a crypto context created by krb5_crypto_init().
2447ca1c9b0cSelric *
2448ca1c9b0cSelric * @param context Kerberos context
2449ca1c9b0cSelric * @param crypto crypto context to free
2450ca1c9b0cSelric *
2451ca1c9b0cSelric * @return Return an error code or 0.
2452ca1c9b0cSelric *
2453ca1c9b0cSelric * @ingroup krb5_crypto
2454ca1c9b0cSelric */
2455ca1c9b0cSelric
2456ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_destroy(krb5_context context,krb5_crypto crypto)2457ca1c9b0cSelric krb5_crypto_destroy(krb5_context context,
2458ca1c9b0cSelric krb5_crypto crypto)
2459ca1c9b0cSelric {
2460ca1c9b0cSelric int i;
2461ca1c9b0cSelric
2462ca1c9b0cSelric for(i = 0; i < crypto->num_key_usage; i++)
2463ca1c9b0cSelric free_key_usage(context, &crypto->key_usage[i], crypto->et);
2464ca1c9b0cSelric free(crypto->key_usage);
2465ca1c9b0cSelric _krb5_free_key_data(context, &crypto->key, crypto->et);
2466ca1c9b0cSelric free (crypto);
2467ca1c9b0cSelric return 0;
2468ca1c9b0cSelric }
2469ca1c9b0cSelric
2470ca1c9b0cSelric /**
2471ca1c9b0cSelric * Return the blocksize used algorithm referenced by the crypto context
2472ca1c9b0cSelric *
2473ca1c9b0cSelric * @param context Kerberos context
2474ca1c9b0cSelric * @param crypto crypto context to query
2475ca1c9b0cSelric * @param blocksize the resulting blocksize
2476ca1c9b0cSelric *
2477ca1c9b0cSelric * @return Return an error code or 0.
2478ca1c9b0cSelric *
2479ca1c9b0cSelric * @ingroup krb5_crypto
2480ca1c9b0cSelric */
2481ca1c9b0cSelric
2482ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_getblocksize(krb5_context context,krb5_crypto crypto,size_t * blocksize)2483ca1c9b0cSelric krb5_crypto_getblocksize(krb5_context context,
2484ca1c9b0cSelric krb5_crypto crypto,
2485ca1c9b0cSelric size_t *blocksize)
2486ca1c9b0cSelric {
2487ca1c9b0cSelric *blocksize = crypto->et->blocksize;
2488ca1c9b0cSelric return 0;
2489ca1c9b0cSelric }
2490ca1c9b0cSelric
2491ca1c9b0cSelric /**
2492ca1c9b0cSelric * Return the encryption type used by the crypto context
2493ca1c9b0cSelric *
2494ca1c9b0cSelric * @param context Kerberos context
2495ca1c9b0cSelric * @param crypto crypto context to query
2496ca1c9b0cSelric * @param enctype the resulting encryption type
2497ca1c9b0cSelric *
2498ca1c9b0cSelric * @return Return an error code or 0.
2499ca1c9b0cSelric *
2500ca1c9b0cSelric * @ingroup krb5_crypto
2501ca1c9b0cSelric */
2502ca1c9b0cSelric
2503ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_getenctype(krb5_context context,krb5_crypto crypto,krb5_enctype * enctype)2504ca1c9b0cSelric krb5_crypto_getenctype(krb5_context context,
2505ca1c9b0cSelric krb5_crypto crypto,
2506ca1c9b0cSelric krb5_enctype *enctype)
2507ca1c9b0cSelric {
2508ca1c9b0cSelric *enctype = crypto->et->type;
2509ca1c9b0cSelric return 0;
2510ca1c9b0cSelric }
2511ca1c9b0cSelric
2512ca1c9b0cSelric /**
2513ca1c9b0cSelric * Return the padding size used by the crypto context
2514ca1c9b0cSelric *
2515ca1c9b0cSelric * @param context Kerberos context
2516ca1c9b0cSelric * @param crypto crypto context to query
2517ca1c9b0cSelric * @param padsize the return padding size
2518ca1c9b0cSelric *
2519ca1c9b0cSelric * @return Return an error code or 0.
2520ca1c9b0cSelric *
2521ca1c9b0cSelric * @ingroup krb5_crypto
2522ca1c9b0cSelric */
2523ca1c9b0cSelric
2524ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_getpadsize(krb5_context context,krb5_crypto crypto,size_t * padsize)2525ca1c9b0cSelric krb5_crypto_getpadsize(krb5_context context,
2526ca1c9b0cSelric krb5_crypto crypto,
2527ca1c9b0cSelric size_t *padsize)
2528ca1c9b0cSelric {
2529ca1c9b0cSelric *padsize = crypto->et->padsize;
2530ca1c9b0cSelric return 0;
2531ca1c9b0cSelric }
2532ca1c9b0cSelric
2533ca1c9b0cSelric /**
2534ca1c9b0cSelric * Return the confounder size used by the crypto context
2535ca1c9b0cSelric *
2536ca1c9b0cSelric * @param context Kerberos context
2537ca1c9b0cSelric * @param crypto crypto context to query
2538ca1c9b0cSelric * @param confoundersize the returned confounder size
2539ca1c9b0cSelric *
2540ca1c9b0cSelric * @return Return an error code or 0.
2541ca1c9b0cSelric *
2542ca1c9b0cSelric * @ingroup krb5_crypto
2543ca1c9b0cSelric */
2544ca1c9b0cSelric
2545ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_getconfoundersize(krb5_context context,krb5_crypto crypto,size_t * confoundersize)2546ca1c9b0cSelric krb5_crypto_getconfoundersize(krb5_context context,
2547ca1c9b0cSelric krb5_crypto crypto,
2548ca1c9b0cSelric size_t *confoundersize)
2549ca1c9b0cSelric {
2550ca1c9b0cSelric *confoundersize = crypto->et->confoundersize;
2551ca1c9b0cSelric return 0;
2552ca1c9b0cSelric }
2553ca1c9b0cSelric
2554ca1c9b0cSelric
2555ca1c9b0cSelric /**
2556ca1c9b0cSelric * Disable encryption type
2557ca1c9b0cSelric *
2558ca1c9b0cSelric * @param context Kerberos 5 context
2559ca1c9b0cSelric * @param enctype encryption type to disable
2560ca1c9b0cSelric *
2561ca1c9b0cSelric * @return Return an error code or 0.
2562ca1c9b0cSelric *
2563ca1c9b0cSelric * @ingroup krb5_crypto
2564ca1c9b0cSelric */
2565ca1c9b0cSelric
2566ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_disable(krb5_context context,krb5_enctype enctype)2567ca1c9b0cSelric krb5_enctype_disable(krb5_context context,
2568ca1c9b0cSelric krb5_enctype enctype)
2569ca1c9b0cSelric {
2570ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2571ca1c9b0cSelric if(et == NULL) {
2572ca1c9b0cSelric if (context)
2573ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2574ca1c9b0cSelric N_("encryption type %d not supported", ""),
2575ca1c9b0cSelric enctype);
2576ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2577ca1c9b0cSelric }
2578ca1c9b0cSelric et->flags |= F_DISABLED;
2579ca1c9b0cSelric return 0;
2580ca1c9b0cSelric }
2581ca1c9b0cSelric
2582ca1c9b0cSelric /**
2583ca1c9b0cSelric * Enable encryption type
2584ca1c9b0cSelric *
2585ca1c9b0cSelric * @param context Kerberos 5 context
2586ca1c9b0cSelric * @param enctype encryption type to enable
2587ca1c9b0cSelric *
2588ca1c9b0cSelric * @return Return an error code or 0.
2589ca1c9b0cSelric *
2590ca1c9b0cSelric * @ingroup krb5_crypto
2591ca1c9b0cSelric */
2592ca1c9b0cSelric
2593ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_enctype_enable(krb5_context context,krb5_enctype enctype)2594ca1c9b0cSelric krb5_enctype_enable(krb5_context context,
2595ca1c9b0cSelric krb5_enctype enctype)
2596ca1c9b0cSelric {
2597ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2598ca1c9b0cSelric if(et == NULL) {
2599ca1c9b0cSelric if (context)
2600ca1c9b0cSelric krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2601ca1c9b0cSelric N_("encryption type %d not supported", ""),
2602ca1c9b0cSelric enctype);
2603ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2604ca1c9b0cSelric }
2605ca1c9b0cSelric et->flags &= ~F_DISABLED;
2606ca1c9b0cSelric return 0;
2607ca1c9b0cSelric }
2608ca1c9b0cSelric
2609ca1c9b0cSelric /**
2610ca1c9b0cSelric * Enable or disable all weak encryption types
2611ca1c9b0cSelric *
2612ca1c9b0cSelric * @param context Kerberos 5 context
2613ca1c9b0cSelric * @param enable true to enable, false to disable
2614ca1c9b0cSelric *
2615ca1c9b0cSelric * @return Return an error code or 0.
2616ca1c9b0cSelric *
2617ca1c9b0cSelric * @ingroup krb5_crypto
2618ca1c9b0cSelric */
2619ca1c9b0cSelric
2620ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_allow_weak_crypto(krb5_context context,krb5_boolean enable)2621ca1c9b0cSelric krb5_allow_weak_crypto(krb5_context context,
2622ca1c9b0cSelric krb5_boolean enable)
2623ca1c9b0cSelric {
2624ca1c9b0cSelric int i;
2625ca1c9b0cSelric
2626ca1c9b0cSelric for(i = 0; i < _krb5_num_etypes; i++)
2627ca1c9b0cSelric if(_krb5_etypes[i]->flags & F_WEAK) {
2628ca1c9b0cSelric if(enable)
2629ca1c9b0cSelric _krb5_etypes[i]->flags &= ~F_DISABLED;
2630ca1c9b0cSelric else
2631ca1c9b0cSelric _krb5_etypes[i]->flags |= F_DISABLED;
2632ca1c9b0cSelric }
2633ca1c9b0cSelric return 0;
2634ca1c9b0cSelric }
2635ca1c9b0cSelric
2636b9d004c6Schristos /**
2637b9d004c6Schristos * Returns is the encryption is strong or weak
2638b9d004c6Schristos *
2639b9d004c6Schristos * @param context Kerberos 5 context
2640b9d004c6Schristos * @param enctype encryption type to probe
2641b9d004c6Schristos *
2642b9d004c6Schristos * @return Returns true if encryption type is weak or is not supported.
2643b9d004c6Schristos *
2644b9d004c6Schristos * @ingroup krb5_crypto
2645b9d004c6Schristos */
2646b9d004c6Schristos
2647b9d004c6Schristos KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_is_enctype_weak(krb5_context context,krb5_enctype enctype)2648b9d004c6Schristos krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype)
2649b9d004c6Schristos {
2650b9d004c6Schristos struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2651b9d004c6Schristos if(et == NULL || (et->flags & F_WEAK))
2652b9d004c6Schristos return TRUE;
2653b9d004c6Schristos return FALSE;
2654b9d004c6Schristos }
2655b9d004c6Schristos
2656b9d004c6Schristos /**
2657b9d004c6Schristos * Returns whether the encryption type should use randomly generated salts
2658b9d004c6Schristos *
2659b9d004c6Schristos * @param context Kerberos 5 context
2660b9d004c6Schristos * @param enctype encryption type to probe
2661b9d004c6Schristos *
2662b9d004c6Schristos * @return Returns true if generated salts should have random component
2663b9d004c6Schristos *
2664b9d004c6Schristos * @ingroup krb5_crypto
2665b9d004c6Schristos */
2666b9d004c6Schristos KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
_krb5_enctype_requires_random_salt(krb5_context context,krb5_enctype enctype)2667b9d004c6Schristos _krb5_enctype_requires_random_salt(krb5_context context,
2668b9d004c6Schristos krb5_enctype enctype)
2669b9d004c6Schristos {
2670b9d004c6Schristos struct _krb5_encryption_type *et;
2671b9d004c6Schristos
2672b9d004c6Schristos et = _krb5_find_enctype (enctype);
2673b9d004c6Schristos
2674b9d004c6Schristos return et && (et->flags & F_SP800_108_HMAC_KDF);
2675b9d004c6Schristos }
2676b9d004c6Schristos
2677ca1c9b0cSelric static size_t
wrapped_length(krb5_context context,krb5_crypto crypto,size_t data_len)2678ca1c9b0cSelric wrapped_length (krb5_context context,
2679ca1c9b0cSelric krb5_crypto crypto,
2680ca1c9b0cSelric size_t data_len)
2681ca1c9b0cSelric {
2682ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
2683ca1c9b0cSelric size_t padsize = et->padsize;
2684ca1c9b0cSelric size_t checksumsize = CHECKSUMSIZE(et->checksum);
2685ca1c9b0cSelric size_t res;
2686ca1c9b0cSelric
2687ca1c9b0cSelric res = et->confoundersize + checksumsize + data_len;
2688ca1c9b0cSelric res = (res + padsize - 1) / padsize * padsize;
2689ca1c9b0cSelric return res;
2690ca1c9b0cSelric }
2691ca1c9b0cSelric
2692ca1c9b0cSelric static size_t
wrapped_length_dervied(krb5_context context,krb5_crypto crypto,size_t data_len)2693ca1c9b0cSelric wrapped_length_dervied (krb5_context context,
2694ca1c9b0cSelric krb5_crypto crypto,
2695ca1c9b0cSelric size_t data_len)
2696ca1c9b0cSelric {
2697ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
2698ca1c9b0cSelric size_t padsize = et->padsize;
2699ca1c9b0cSelric size_t res;
2700ca1c9b0cSelric
2701ca1c9b0cSelric res = et->confoundersize + data_len;
2702ca1c9b0cSelric res = (res + padsize - 1) / padsize * padsize;
2703ca1c9b0cSelric if (et->keyed_checksum)
2704ca1c9b0cSelric res += et->keyed_checksum->checksumsize;
2705ca1c9b0cSelric else
2706ca1c9b0cSelric res += et->checksum->checksumsize;
2707ca1c9b0cSelric return res;
2708ca1c9b0cSelric }
2709ca1c9b0cSelric
2710ca1c9b0cSelric /*
2711ca1c9b0cSelric * Return the size of an encrypted packet of length `data_len'
2712ca1c9b0cSelric */
2713ca1c9b0cSelric
2714ca1c9b0cSelric KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
krb5_get_wrapped_length(krb5_context context,krb5_crypto crypto,size_t data_len)2715ca1c9b0cSelric krb5_get_wrapped_length (krb5_context context,
2716ca1c9b0cSelric krb5_crypto crypto,
2717ca1c9b0cSelric size_t data_len)
2718ca1c9b0cSelric {
2719ca1c9b0cSelric if (derived_crypto (context, crypto))
2720ca1c9b0cSelric return wrapped_length_dervied (context, crypto, data_len);
2721ca1c9b0cSelric else
2722ca1c9b0cSelric return wrapped_length (context, crypto, data_len);
2723ca1c9b0cSelric }
2724ca1c9b0cSelric
2725ca1c9b0cSelric /*
2726ca1c9b0cSelric * Return the size of an encrypted packet of length `data_len'
2727ca1c9b0cSelric */
2728ca1c9b0cSelric
2729ca1c9b0cSelric static size_t
crypto_overhead(krb5_context context,krb5_crypto crypto)2730ca1c9b0cSelric crypto_overhead (krb5_context context,
2731ca1c9b0cSelric krb5_crypto crypto)
2732ca1c9b0cSelric {
2733ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
2734ca1c9b0cSelric size_t res;
2735ca1c9b0cSelric
2736ca1c9b0cSelric res = CHECKSUMSIZE(et->checksum);
2737ca1c9b0cSelric res += et->confoundersize;
2738ca1c9b0cSelric if (et->padsize > 1)
2739ca1c9b0cSelric res += et->padsize;
2740ca1c9b0cSelric return res;
2741ca1c9b0cSelric }
2742ca1c9b0cSelric
2743ca1c9b0cSelric static size_t
crypto_overhead_dervied(krb5_context context,krb5_crypto crypto)2744ca1c9b0cSelric crypto_overhead_dervied (krb5_context context,
2745ca1c9b0cSelric krb5_crypto crypto)
2746ca1c9b0cSelric {
2747ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
2748ca1c9b0cSelric size_t res;
2749ca1c9b0cSelric
2750ca1c9b0cSelric if (et->keyed_checksum)
2751ca1c9b0cSelric res = CHECKSUMSIZE(et->keyed_checksum);
2752ca1c9b0cSelric else
2753ca1c9b0cSelric res = CHECKSUMSIZE(et->checksum);
2754ca1c9b0cSelric res += et->confoundersize;
2755ca1c9b0cSelric if (et->padsize > 1)
2756ca1c9b0cSelric res += et->padsize;
2757ca1c9b0cSelric return res;
2758ca1c9b0cSelric }
2759ca1c9b0cSelric
2760ca1c9b0cSelric KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
krb5_crypto_overhead(krb5_context context,krb5_crypto crypto)2761ca1c9b0cSelric krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2762ca1c9b0cSelric {
2763ca1c9b0cSelric if (derived_crypto (context, crypto))
2764ca1c9b0cSelric return crypto_overhead_dervied (context, crypto);
2765ca1c9b0cSelric else
2766ca1c9b0cSelric return crypto_overhead (context, crypto);
2767ca1c9b0cSelric }
2768ca1c9b0cSelric
2769ca1c9b0cSelric /**
2770ca1c9b0cSelric * Converts the random bytestring to a protocol key according to
2771ca1c9b0cSelric * Kerberos crypto frame work. It may be assumed that all the bits of
2772ca1c9b0cSelric * the input string are equally random, even though the entropy
2773ca1c9b0cSelric * present in the random source may be limited.
2774ca1c9b0cSelric *
2775ca1c9b0cSelric * @param context Kerberos 5 context
2776ca1c9b0cSelric * @param type the enctype resulting key will be of
2777ca1c9b0cSelric * @param data input random data to convert to a key
2778ca1c9b0cSelric * @param size size of input random data, at least krb5_enctype_keysize() long
2779ca1c9b0cSelric * @param key key, output key, free with krb5_free_keyblock_contents()
2780ca1c9b0cSelric *
2781ca1c9b0cSelric * @return Return an error code or 0.
2782ca1c9b0cSelric *
2783ca1c9b0cSelric * @ingroup krb5_crypto
2784ca1c9b0cSelric */
2785ca1c9b0cSelric
2786ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_random_to_key(krb5_context context,krb5_enctype type,const void * data,size_t size,krb5_keyblock * key)2787ca1c9b0cSelric krb5_random_to_key(krb5_context context,
2788ca1c9b0cSelric krb5_enctype type,
2789ca1c9b0cSelric const void *data,
2790ca1c9b0cSelric size_t size,
2791ca1c9b0cSelric krb5_keyblock *key)
2792ca1c9b0cSelric {
2793ca1c9b0cSelric krb5_error_code ret;
2794ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2795ca1c9b0cSelric if(et == NULL) {
2796ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2797ca1c9b0cSelric N_("encryption type %d not supported", ""),
2798ca1c9b0cSelric type);
2799ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2800ca1c9b0cSelric }
2801ca1c9b0cSelric if ((et->keytype->bits + 7) / 8 > size) {
2802ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2803ca1c9b0cSelric N_("encryption key %s needs %d bytes "
2804ca1c9b0cSelric "of random to make an encryption key "
2805ca1c9b0cSelric "out of it", ""),
2806ca1c9b0cSelric et->name, (int)et->keytype->size);
2807ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2808ca1c9b0cSelric }
2809ca1c9b0cSelric ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2810ca1c9b0cSelric if(ret)
2811ca1c9b0cSelric return ret;
2812ca1c9b0cSelric key->keytype = type;
2813ca1c9b0cSelric if (et->keytype->random_to_key)
2814ca1c9b0cSelric (*et->keytype->random_to_key)(context, key, data, size);
2815ca1c9b0cSelric else
2816ca1c9b0cSelric memcpy(key->keyvalue.data, data, et->keytype->size);
2817ca1c9b0cSelric
2818ca1c9b0cSelric return 0;
2819ca1c9b0cSelric }
2820ca1c9b0cSelric
2821ca1c9b0cSelric
2822ca1c9b0cSelric
2823ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_prf_length(krb5_context context,krb5_enctype type,size_t * length)2824ca1c9b0cSelric krb5_crypto_prf_length(krb5_context context,
2825ca1c9b0cSelric krb5_enctype type,
2826ca1c9b0cSelric size_t *length)
2827ca1c9b0cSelric {
2828ca1c9b0cSelric struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2829ca1c9b0cSelric
2830ca1c9b0cSelric if(et == NULL || et->prf_length == 0) {
2831ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2832ca1c9b0cSelric N_("encryption type %d not supported", ""),
2833ca1c9b0cSelric type);
2834ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2835ca1c9b0cSelric }
2836ca1c9b0cSelric
2837ca1c9b0cSelric *length = et->prf_length;
2838ca1c9b0cSelric return 0;
2839ca1c9b0cSelric }
2840ca1c9b0cSelric
2841ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_prf(krb5_context context,const krb5_crypto crypto,const krb5_data * input,krb5_data * output)2842ca1c9b0cSelric krb5_crypto_prf(krb5_context context,
2843ca1c9b0cSelric const krb5_crypto crypto,
2844ca1c9b0cSelric const krb5_data *input,
2845ca1c9b0cSelric krb5_data *output)
2846ca1c9b0cSelric {
2847ca1c9b0cSelric struct _krb5_encryption_type *et = crypto->et;
2848ca1c9b0cSelric
2849ca1c9b0cSelric krb5_data_zero(output);
2850ca1c9b0cSelric
2851ca1c9b0cSelric if(et->prf == NULL) {
2852ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2853ca1c9b0cSelric "kerberos prf for %s not supported",
2854ca1c9b0cSelric et->name);
2855ca1c9b0cSelric return KRB5_PROG_ETYPE_NOSUPP;
2856ca1c9b0cSelric }
2857ca1c9b0cSelric
2858ca1c9b0cSelric return (*et->prf)(context, crypto, input, output);
2859ca1c9b0cSelric }
2860ca1c9b0cSelric
2861ca1c9b0cSelric static krb5_error_code
krb5_crypto_prfplus(krb5_context context,const krb5_crypto crypto,const krb5_data * input,size_t length,krb5_data * output)2862ca1c9b0cSelric krb5_crypto_prfplus(krb5_context context,
2863ca1c9b0cSelric const krb5_crypto crypto,
2864ca1c9b0cSelric const krb5_data *input,
2865ca1c9b0cSelric size_t length,
2866ca1c9b0cSelric krb5_data *output)
2867ca1c9b0cSelric {
2868ca1c9b0cSelric krb5_error_code ret;
2869ca1c9b0cSelric krb5_data input2;
2870ca1c9b0cSelric unsigned char i = 1;
2871ca1c9b0cSelric unsigned char *p;
2872ca1c9b0cSelric
2873ca1c9b0cSelric krb5_data_zero(&input2);
2874ca1c9b0cSelric krb5_data_zero(output);
2875ca1c9b0cSelric
2876ca1c9b0cSelric krb5_clear_error_message(context);
2877ca1c9b0cSelric
2878ca1c9b0cSelric ret = krb5_data_alloc(output, length);
2879ca1c9b0cSelric if (ret) goto out;
2880ca1c9b0cSelric ret = krb5_data_alloc(&input2, input->length + 1);
2881ca1c9b0cSelric if (ret) goto out;
2882ca1c9b0cSelric
2883ca1c9b0cSelric krb5_clear_error_message(context);
2884ca1c9b0cSelric
2885ca1c9b0cSelric memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2886ca1c9b0cSelric
2887ca1c9b0cSelric p = output->data;
2888ca1c9b0cSelric
2889ca1c9b0cSelric while (length) {
2890ca1c9b0cSelric krb5_data block;
2891ca1c9b0cSelric
2892ca1c9b0cSelric ((unsigned char *)input2.data)[0] = i++;
2893ca1c9b0cSelric
2894ca1c9b0cSelric ret = krb5_crypto_prf(context, crypto, &input2, &block);
2895ca1c9b0cSelric if (ret)
2896ca1c9b0cSelric goto out;
2897ca1c9b0cSelric
2898ca1c9b0cSelric if (block.length < length) {
2899ca1c9b0cSelric memcpy(p, block.data, block.length);
2900ca1c9b0cSelric length -= block.length;
2901ca1c9b0cSelric } else {
2902ca1c9b0cSelric memcpy(p, block.data, length);
2903ca1c9b0cSelric length = 0;
2904ca1c9b0cSelric }
2905ca1c9b0cSelric p += block.length;
2906ca1c9b0cSelric krb5_data_free(&block);
2907ca1c9b0cSelric }
2908ca1c9b0cSelric
2909ca1c9b0cSelric out:
2910ca1c9b0cSelric krb5_data_free(&input2);
2911ca1c9b0cSelric if (ret)
2912ca1c9b0cSelric krb5_data_free(output);
29134f77a458Spettai return ret;
2914ca1c9b0cSelric }
2915ca1c9b0cSelric
2916ca1c9b0cSelric /**
2917ca1c9b0cSelric * The FX-CF2 key derivation function, used in FAST and preauth framework.
2918ca1c9b0cSelric *
2919ca1c9b0cSelric * @param context Kerberos 5 context
2920ca1c9b0cSelric * @param crypto1 first key to combine
2921ca1c9b0cSelric * @param crypto2 second key to combine
2922ca1c9b0cSelric * @param pepper1 factor to combine with first key to garante uniqueness
2923ca1c9b0cSelric * @param pepper2 factor to combine with second key to garante uniqueness
2924ca1c9b0cSelric * @param enctype the encryption type of the resulting key
2925ca1c9b0cSelric * @param res allocated key, free with krb5_free_keyblock_contents()
2926ca1c9b0cSelric *
2927ca1c9b0cSelric * @return Return an error code or 0.
2928ca1c9b0cSelric *
2929ca1c9b0cSelric * @ingroup krb5_crypto
2930ca1c9b0cSelric */
2931ca1c9b0cSelric
2932ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_crypto_fx_cf2(krb5_context context,const krb5_crypto crypto1,const krb5_crypto crypto2,krb5_data * pepper1,krb5_data * pepper2,krb5_enctype enctype,krb5_keyblock * res)2933ca1c9b0cSelric krb5_crypto_fx_cf2(krb5_context context,
2934ca1c9b0cSelric const krb5_crypto crypto1,
2935ca1c9b0cSelric const krb5_crypto crypto2,
2936ca1c9b0cSelric krb5_data *pepper1,
2937ca1c9b0cSelric krb5_data *pepper2,
2938ca1c9b0cSelric krb5_enctype enctype,
2939ca1c9b0cSelric krb5_keyblock *res)
2940ca1c9b0cSelric {
2941ca1c9b0cSelric krb5_error_code ret;
2942ca1c9b0cSelric krb5_data os1, os2;
2943ca1c9b0cSelric size_t i, keysize;
2944ca1c9b0cSelric
2945ca1c9b0cSelric memset(res, 0, sizeof(*res));
29464f77a458Spettai krb5_data_zero(&os1);
29474f77a458Spettai krb5_data_zero(&os2);
2948ca1c9b0cSelric
2949b9d004c6Schristos ret = krb5_enctype_keybits(context, enctype, &keysize);
2950ca1c9b0cSelric if (ret)
2951ca1c9b0cSelric return ret;
2952b9d004c6Schristos keysize = (keysize + 7) / 8;
2953ca1c9b0cSelric
2954ca1c9b0cSelric ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2955ca1c9b0cSelric if (ret)
2956ca1c9b0cSelric goto out;
2957ca1c9b0cSelric ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2958ca1c9b0cSelric if (ret)
2959ca1c9b0cSelric goto out;
2960ca1c9b0cSelric
2961ca1c9b0cSelric res->keytype = enctype;
2962ca1c9b0cSelric {
2963b9d004c6Schristos unsigned char *p1 = os1.data, *p2 = os2.data;
2964ca1c9b0cSelric for (i = 0; i < keysize; i++)
2965b9d004c6Schristos p1[i] ^= p2[i];
2966ca1c9b0cSelric }
2967b9d004c6Schristos ret = krb5_random_to_key(context, enctype, os1.data, keysize, res);
2968ca1c9b0cSelric out:
2969ca1c9b0cSelric krb5_data_free(&os1);
2970ca1c9b0cSelric krb5_data_free(&os2);
2971ca1c9b0cSelric
2972ca1c9b0cSelric return ret;
2973ca1c9b0cSelric }
2974ca1c9b0cSelric
2975ca1c9b0cSelric
2976ca1c9b0cSelric
2977ca1c9b0cSelric #ifndef HEIMDAL_SMALLER
2978ca1c9b0cSelric
2979ca1c9b0cSelric /**
2980ca1c9b0cSelric * Deprecated: keytypes doesn't exists, they are really enctypes.
2981ca1c9b0cSelric *
2982ca1c9b0cSelric * @ingroup krb5_deprecated
2983ca1c9b0cSelric */
2984ca1c9b0cSelric
2985ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_keytype_to_enctypes(krb5_context context,krb5_keytype keytype,unsigned * len,krb5_enctype ** val)2986ca1c9b0cSelric krb5_keytype_to_enctypes (krb5_context context,
2987ca1c9b0cSelric krb5_keytype keytype,
2988ca1c9b0cSelric unsigned *len,
2989ca1c9b0cSelric krb5_enctype **val)
29904f77a458Spettai KRB5_DEPRECATED_FUNCTION("Use X instead")
2991ca1c9b0cSelric {
2992ca1c9b0cSelric int i;
2993ca1c9b0cSelric unsigned n = 0;
2994ca1c9b0cSelric krb5_enctype *ret;
2995ca1c9b0cSelric
2996ca1c9b0cSelric for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2997ca1c9b0cSelric if (_krb5_etypes[i]->keytype->type == keytype
2998ca1c9b0cSelric && !(_krb5_etypes[i]->flags & F_PSEUDO)
2999ca1c9b0cSelric && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3000ca1c9b0cSelric ++n;
3001ca1c9b0cSelric }
3002ca1c9b0cSelric if (n == 0) {
3003ca1c9b0cSelric krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
3004ca1c9b0cSelric "Keytype have no mapping");
3005ca1c9b0cSelric return KRB5_PROG_KEYTYPE_NOSUPP;
3006ca1c9b0cSelric }
3007ca1c9b0cSelric
3008ca1c9b0cSelric ret = malloc(n * sizeof(*ret));
3009b9d004c6Schristos if (ret == NULL && n != 0)
3010b9d004c6Schristos return krb5_enomem(context);
3011ca1c9b0cSelric n = 0;
3012ca1c9b0cSelric for (i = _krb5_num_etypes - 1; i >= 0; --i) {
3013ca1c9b0cSelric if (_krb5_etypes[i]->keytype->type == keytype
3014ca1c9b0cSelric && !(_krb5_etypes[i]->flags & F_PSEUDO)
3015ca1c9b0cSelric && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
3016ca1c9b0cSelric ret[n++] = _krb5_etypes[i]->type;
3017ca1c9b0cSelric }
3018ca1c9b0cSelric *len = n;
3019ca1c9b0cSelric *val = ret;
3020ca1c9b0cSelric return 0;
3021ca1c9b0cSelric }
3022ca1c9b0cSelric
3023ca1c9b0cSelric /**
3024ca1c9b0cSelric * Deprecated: keytypes doesn't exists, they are really enctypes.
3025ca1c9b0cSelric *
3026ca1c9b0cSelric * @ingroup krb5_deprecated
3027ca1c9b0cSelric */
3028ca1c9b0cSelric
3029ca1c9b0cSelric /* if two enctypes have compatible keys */
3030ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_enctypes_compatible_keys(krb5_context context,krb5_enctype etype1,krb5_enctype etype2)3031ca1c9b0cSelric krb5_enctypes_compatible_keys(krb5_context context,
3032ca1c9b0cSelric krb5_enctype etype1,
3033ca1c9b0cSelric krb5_enctype etype2)
30344f77a458Spettai KRB5_DEPRECATED_FUNCTION("Use X instead")
3035ca1c9b0cSelric {
3036ca1c9b0cSelric struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
3037ca1c9b0cSelric struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
3038ca1c9b0cSelric return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
3039ca1c9b0cSelric }
3040ca1c9b0cSelric
3041ca1c9b0cSelric #endif /* HEIMDAL_SMALLER */
3042