1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
9 *
10 * Permission to use, copy, modify and distribute this software and its
11 * documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the software,
13 * derivative works or modified versions, and any portions thereof.
14 *
15 * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
16 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
17 * RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Key combination function.
20 *
21 * If Key1 and Key2 are two keys to be combined, the algorithm to combine
22 * them is as follows.
23 *
24 * Definitions:
25 *
26 * k-truncate is defined as truncating to the key size the input.
27 *
28 * DR is defined as the generate "random" data from a key
29 * (defined in crypto draft)
30 *
31 * DK is defined as the key derivation function (krb5_derive_key())
32 *
33 * (note: | means "concatenate")
34 *
35 * Combine key algorithm:
36 *
37 * R1 = DR(Key1, n-fold(Key2)) [ Output is length of Key1 ]
38 * R2 = DR(Key2, n-fold(Key1)) [ Output is length of Key2 ]
39 *
40 * rnd = n-fold(R1 | R2) [ Note: output size of nfold must be appropriately
41 * sized for random-to-key function ]
42 * tkey = random-to-key(rnd)
43 * Combine-Key(Key1, Key2) = DK(tkey, CombineConstant)
44 *
45 * CombineConstant is defined as the byte string:
46 *
47 * { 0x63 0x6f 0x6d 0x62 0x69 0x6e 0x65 }, which corresponds to the
48 * ASCII encoding of the string "combine"
49 */
50
51 #include "k5-int.h"
52 #include "etypes.h"
53 #include "dk.h"
54
55 /* Solaris Kerberos */
56 static krb5_error_code dr
57 (krb5_context context,
58 const struct krb5_enc_provider *enc, const krb5_keyblock *inkey,
59 unsigned char *outdata, const krb5_data *in_constant);
60
61 /*
62 * We only support this combine_keys algorithm for des and 3des keys.
63 * Everything else should use the PRF defined in the crypto framework.
64 * We don't implement that yet.
65 */
66
enctype_ok(krb5_enctype e)67 static krb5_boolean enctype_ok (krb5_enctype e)
68 {
69 switch (e) {
70 case ENCTYPE_DES_CBC_CRC:
71 case ENCTYPE_DES_CBC_MD4:
72 case ENCTYPE_DES_CBC_MD5:
73 case ENCTYPE_DES3_CBC_SHA1:
74 return 1;
75 default:
76 return 0;
77 }
78 }
79
krb5int_c_combine_keys(krb5_context context,krb5_keyblock * key1,krb5_keyblock * key2,krb5_keyblock * outkey)80 krb5_error_code krb5int_c_combine_keys
81 (krb5_context context, krb5_keyblock *key1, krb5_keyblock *key2, krb5_keyblock *outkey)
82 {
83 unsigned char *r1, *r2, *combined, *rnd, *output;
84 size_t keybytes, keylength;
85 const struct krb5_enc_provider *enc;
86 krb5_data input, randbits;
87 krb5_keyblock tkey;
88 krb5_error_code ret;
89 int i, myalloc = 0;
90 if (!(enctype_ok(key1->enctype)&&enctype_ok(key2->enctype)))
91 return (KRB5_CRYPTO_INTERNAL);
92
93
94 if (key1->length != key2->length || key1->enctype != key2->enctype)
95 return (KRB5_CRYPTO_INTERNAL);
96
97 /*
98 * Find our encryption algorithm
99 */
100
101 for (i = 0; i < krb5_enctypes_length; i++) {
102 if (krb5_enctypes_list[i].etype == key1->enctype)
103 break;
104 }
105
106 if (i == krb5_enctypes_length)
107 return (KRB5_BAD_ENCTYPE);
108
109 enc = krb5_enctypes_list[i].enc;
110
111 keybytes = enc->keybytes;
112 keylength = enc->keylength;
113
114 /*
115 * Allocate and set up buffers
116 */
117
118 if ((r1 = (unsigned char *) malloc(keybytes)) == NULL)
119 return (ENOMEM);
120
121 if ((r2 = (unsigned char *) malloc(keybytes)) == NULL) {
122 free(r1);
123 return (ENOMEM);
124 }
125
126 if ((rnd = (unsigned char *) malloc(keybytes)) == NULL) {
127 free(r1);
128 free(r2);
129 return (ENOMEM);
130 }
131
132 if ((combined = (unsigned char *) malloc(keybytes * 2)) == NULL) {
133 free(r1);
134 free(r2);
135 free(rnd);
136 return (ENOMEM);
137 }
138
139 if ((output = (unsigned char *) malloc(keylength)) == NULL) {
140 free(r1);
141 free(r2);
142 free(rnd);
143 free(combined);
144 return (ENOMEM);
145 }
146
147 /*
148 * Get R1 and R2 (by running the input keys through the DR algorithm.
149 * Note this is most of derive-key, but not all.
150 */
151
152 input.length = key2->length;
153 input.data = (char *) key2->contents;
154 /* Solaris Kerberos */
155 if ((ret = dr(context, enc, key1, r1, &input)))
156 goto cleanup;
157
158 #if 0
159 {
160 int i;
161 printf("R1 =");
162 for (i = 0; i < keybytes; i++)
163 printf(" %02x", (unsigned char) r1[i]);
164 printf("\n");
165 }
166 #endif
167
168 input.length = key1->length;
169 input.data = (char *) key1->contents;
170 /* Solaris Kerberos */
171 if ((ret = dr(context, enc, key2, r2, &input)))
172 goto cleanup;
173
174 #if 0
175 {
176 int i;
177 printf("R2 =");
178 for (i = 0; i < keybytes; i++)
179 printf(" %02x", (unsigned char) r2[i]);
180 printf("\n");
181 }
182 #endif
183
184 /*
185 * Concatenate the two keys together, and then run them through
186 * n-fold to reduce them to a length appropriate for the random-to-key
187 * operation. Note here that krb5_nfold() takes sizes in bits, hence
188 * the multiply by 8.
189 */
190
191 memcpy(combined, r1, keybytes);
192 memcpy(combined + keybytes, r2, keybytes);
193
194 krb5_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd);
195
196 #if 0
197 {
198 int i;
199 printf("rnd =");
200 for (i = 0; i < keybytes; i++)
201 printf(" %02x", (unsigned char) rnd[i]);
202 printf("\n");
203 }
204 #endif
205
206 /*
207 * Run the "random" bits through random-to-key to produce a encryption
208 * key.
209 */
210
211 randbits.length = keybytes;
212 randbits.data = (char *) rnd;
213 tkey.length = keylength;
214 tkey.contents = output;
215
216 /* Solaris Kerberos */
217 if ((ret = (*(enc->make_key))(context, &randbits, &tkey)))
218 goto cleanup;
219
220 #if 0
221 {
222 int i;
223 printf("tkey =");
224 for (i = 0; i < tkey.length; i++)
225 printf(" %02x", (unsigned char) tkey.contents[i]);
226 printf("\n");
227 }
228 #endif
229
230 /*
231 * Run through derive-key one more time to produce the final key.
232 * Note that the input to derive-key is the ASCII string "combine".
233 */
234
235 input.length = 7; /* Note; change this if string length changes */
236 input.data = "combine";
237
238 /*
239 * Just FYI: _if_ we have space here in the key, then simply use it
240 * without modification. But if the key is blank (no allocated storage)
241 * then allocate some memory for it. This allows programs to use one of
242 * the existing keys as the output key, _or_ pass in a blank keyblock
243 * for us to allocate. It's easier for us to allocate it since we already
244 * know the crypto library internals
245 */
246
247 if (outkey->length == 0 || outkey->contents == NULL) {
248 outkey->contents = (krb5_octet *) malloc(keylength);
249 if (!outkey->contents) {
250 ret = ENOMEM;
251 goto cleanup;
252 }
253 outkey->length = keylength;
254 outkey->enctype = key1->enctype;
255 myalloc = 1;
256 }
257
258 /* Solaris Kerberos */
259 if ((ret = krb5_derive_key(context, enc, &tkey, outkey, &input))) {
260 if (myalloc) {
261 free(outkey->contents);
262 outkey->contents = NULL;
263 }
264 goto cleanup;
265 }
266
267 #if 0
268 {
269 int i;
270 printf("output =");
271 for (i = 0; i < outkey->length; i++)
272 printf(" %02x", (unsigned char) outkey->contents[i]);
273 printf("\n");
274 }
275 #endif
276
277 ret = 0;
278
279 cleanup:
280 memset(r1, 0, keybytes);
281 memset(r2, 0, keybytes);
282 memset(rnd, 0, keybytes);
283 memset(combined, 0, keybytes * 2);
284 memset(output, 0, keylength);
285
286 free(r1);
287 free(r2);
288 free(rnd);
289 free(combined);
290 free(output);
291
292 return (ret);
293 }
294
295 /*
296 * Our DR function; mostly taken from derive.c
297 */
298
299 /* Solaris Kerberos */
dr(krb5_context context,const struct krb5_enc_provider * enc,const krb5_keyblock * inkey,unsigned char * out,const krb5_data * in_constant)300 static krb5_error_code dr
301 ( krb5_context context,
302 const struct krb5_enc_provider *enc,
303 const krb5_keyblock *inkey,
304 unsigned char *out,
305 const krb5_data *in_constant)
306 {
307 size_t blocksize, keybytes, keylength, n;
308 unsigned char *inblockdata, *outblockdata;
309 krb5_data inblock, outblock;
310
311 blocksize = enc->block_size;
312 keybytes = enc->keybytes;
313 keylength = enc->keylength;
314
315 /* allocate and set up buffers */
316
317 if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL)
318 return(ENOMEM);
319
320 if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) {
321 free(inblockdata);
322 return(ENOMEM);
323 }
324
325 inblock.data = (char *) inblockdata;
326 inblock.length = blocksize;
327
328 outblock.data = (char *) outblockdata;
329 outblock.length = blocksize;
330
331 /* initialize the input block */
332
333 if (in_constant->length == inblock.length) {
334 memcpy(inblock.data, in_constant->data, inblock.length);
335 } else {
336 krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data,
337 inblock.length*8, (unsigned char *) inblock.data);
338 }
339
340 /* loop encrypting the blocks until enough key bytes are generated */
341
342 n = 0;
343 while (n < keybytes) {
344 /* Solaris Kerberos */
345 (*(enc->encrypt))(context, inkey, 0, &inblock, &outblock);
346
347 if ((keybytes - n) <= outblock.length) {
348 memcpy(out+n, outblock.data, (keybytes - n));
349 break;
350 }
351
352 memcpy(out+n, outblock.data, outblock.length);
353 memcpy(inblock.data, outblock.data, outblock.length);
354 n += outblock.length;
355 }
356
357 /* clean memory, free resources and exit */
358
359 memset(inblockdata, 0, blocksize);
360 memset(outblockdata, 0, blocksize);
361
362 free(outblockdata);
363 free(inblockdata);
364
365 return(0);
366 }
367
368