1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS) 10 * 11 * Permission to use, copy, modify and distribute this software and its 12 * documentation is hereby granted, provided that both the copyright 13 * notice and this permission notice appear in all copies of the software, 14 * derivative works or modified versions, and any portions thereof. 15 * 16 * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND 17 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 18 * RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Key combination function. 21 * 22 * If Key1 and Key2 are two keys to be combined, the algorithm to combine 23 * them is as follows. 24 * 25 * Definitions: 26 * 27 * k-truncate is defined as truncating to the key size the input. 28 * 29 * DR is defined as the generate "random" data from a key 30 * (defined in crypto draft) 31 * 32 * DK is defined as the key derivation function (krb5_derive_key()) 33 * 34 * (note: | means "concatenate") 35 * 36 * Combine key algorithm: 37 * 38 * R1 = DR(Key1, n-fold(Key2)) [ Output is length of Key1 ] 39 * R2 = DR(Key2, n-fold(Key1)) [ Output is length of Key2 ] 40 * 41 * rnd = n-fold(R1 | R2) [ Note: output size of nfold must be appropriately 42 * sized for random-to-key function ] 43 * tkey = random-to-key(rnd) 44 * Combine-Key(Key1, Key2) = DK(tkey, CombineConstant) 45 * 46 * CombineConstant is defined as the byte string: 47 * 48 * { 0x63 0x6f 0x6d 0x62 0x69 0x6e 0x65 }, which corresponds to the 49 * ASCII encoding of the string "combine" 50 */ 51 52 #include "k5-int.h" 53 #include "etypes.h" 54 #include "dk.h" 55 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 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 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 if ((ret = dr(context, enc, key1, r1, &input))) 155 goto cleanup; 156 157 #if 0 158 { 159 int i; 160 printf("R1 ="); 161 for (i = 0; i < keybytes; i++) 162 printf(" %02x", (unsigned char) r1[i]); 163 printf("\n"); 164 } 165 #endif 166 167 input.length = key1->length; 168 input.data = (char *) key1->contents; 169 if ((ret = dr(context, enc, key2, r2, &input))) 170 goto cleanup; 171 172 #if 0 173 { 174 int i; 175 printf("R2 ="); 176 for (i = 0; i < keybytes; i++) 177 printf(" %02x", (unsigned char) r2[i]); 178 printf("\n"); 179 } 180 #endif 181 182 /* 183 * Concatenate the two keys together, and then run them through 184 * n-fold to reduce them to a length appropriate for the random-to-key 185 * operation. Note here that krb5_nfold() takes sizes in bits, hence 186 * the multiply by 8. 187 */ 188 189 memcpy(combined, r1, keybytes); 190 memcpy(combined + keybytes, r2, keybytes); 191 192 krb5_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd); 193 194 #if 0 195 { 196 int i; 197 printf("rnd ="); 198 for (i = 0; i < keybytes; i++) 199 printf(" %02x", (unsigned char) rnd[i]); 200 printf("\n"); 201 } 202 #endif 203 204 /* 205 * Run the "random" bits through random-to-key to produce a encryption 206 * key. 207 */ 208 209 randbits.length = keybytes; 210 randbits.data = (char *) rnd; 211 tkey.length = keylength; 212 tkey.contents = output; 213 214 if ((ret = (*(enc->make_key))(context, &randbits, &tkey))) 215 goto cleanup; 216 217 #if 0 218 { 219 int i; 220 printf("tkey ="); 221 for (i = 0; i < tkey.length; i++) 222 printf(" %02x", (unsigned char) tkey.contents[i]); 223 printf("\n"); 224 } 225 #endif 226 227 /* 228 * Run through derive-key one more time to produce the final key. 229 * Note that the input to derive-key is the ASCII string "combine". 230 */ 231 232 input.length = 7; /* Note; change this if string length changes */ 233 input.data = "combine"; 234 235 /* 236 * Just FYI: _if_ we have space here in the key, then simply use it 237 * without modification. But if the key is blank (no allocated storage) 238 * then allocate some memory for it. This allows programs to use one of 239 * the existing keys as the output key, _or_ pass in a blank keyblock 240 * for us to allocate. It's easier for us to allocate it since we already 241 * know the crypto library internals 242 */ 243 244 if (outkey->length == 0 || outkey->contents == NULL) { 245 outkey->contents = (krb5_octet *) malloc(keylength); 246 if (!outkey->contents) { 247 ret = ENOMEM; 248 goto cleanup; 249 } 250 outkey->length = keylength; 251 outkey->enctype = key1->enctype; 252 myalloc = 1; 253 } 254 255 if ((ret = krb5_derive_key(context, enc, &tkey, outkey, &input))) { 256 if (myalloc) { 257 free(outkey->contents); 258 outkey->contents = NULL; 259 } 260 goto cleanup; 261 } 262 263 #if 0 264 { 265 int i; 266 printf("output ="); 267 for (i = 0; i < outkey->length; i++) 268 printf(" %02x", (unsigned char) outkey->contents[i]); 269 printf("\n"); 270 } 271 #endif 272 273 ret = 0; 274 275 cleanup: 276 memset(r1, 0, keybytes); 277 memset(r2, 0, keybytes); 278 memset(rnd, 0, keybytes); 279 memset(combined, 0, keybytes * 2); 280 memset(output, 0, keylength); 281 282 free(r1); 283 free(r2); 284 free(rnd); 285 free(combined); 286 free(output); 287 288 return (ret); 289 } 290 291 /* 292 * Our DR function; mostly taken from derive.c 293 */ 294 295 static krb5_error_code dr 296 ( krb5_context context, 297 const struct krb5_enc_provider *enc, 298 const krb5_keyblock *inkey, 299 unsigned char *out, 300 const krb5_data *in_constant) 301 { 302 size_t blocksize, keybytes, keylength, n; 303 unsigned char *inblockdata, *outblockdata; 304 krb5_data inblock, outblock; 305 306 blocksize = enc->block_size; 307 keybytes = enc->keybytes; 308 keylength = enc->keylength; 309 310 /* allocate and set up buffers */ 311 312 if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL) 313 return(ENOMEM); 314 315 if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) { 316 free(inblockdata); 317 return(ENOMEM); 318 } 319 320 inblock.data = (char *) inblockdata; 321 inblock.length = blocksize; 322 323 outblock.data = (char *) outblockdata; 324 outblock.length = blocksize; 325 326 /* initialize the input block */ 327 328 if (in_constant->length == inblock.length) { 329 memcpy(inblock.data, in_constant->data, inblock.length); 330 } else { 331 krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data, 332 inblock.length*8, (unsigned char *) inblock.data); 333 } 334 335 /* loop encrypting the blocks until enough key bytes are generated */ 336 337 n = 0; 338 while (n < keybytes) { 339 (*(enc->encrypt))(context, inkey, 0, &inblock, &outblock); 340 341 if ((keybytes - n) <= outblock.length) { 342 memcpy(out+n, outblock.data, (keybytes - n)); 343 break; 344 } 345 346 memcpy(out+n, outblock.data, outblock.length); 347 memcpy(inblock.data, outblock.data, outblock.length); 348 n += outblock.length; 349 } 350 351 /* clean memory, free resources and exit */ 352 353 memset(inblockdata, 0, blocksize); 354 memset(outblockdata, 0, blocksize); 355 356 free(outblockdata); 357 free(inblockdata); 358 359 return(0); 360 } 361 362