1 /* 2 * Copyright 2004 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 (*(enc->keysize))(&keybytes, &keylength); 112 113 /* 114 * Allocate and set up buffers 115 */ 116 117 if ((r1 = (unsigned char *) malloc(keybytes)) == NULL) 118 return (ENOMEM); 119 120 if ((r2 = (unsigned char *) malloc(keybytes)) == NULL) { 121 free(r1); 122 return (ENOMEM); 123 } 124 125 if ((rnd = (unsigned char *) malloc(keybytes)) == NULL) { 126 free(r1); 127 free(r2); 128 return (ENOMEM); 129 } 130 131 if ((combined = (unsigned char *) malloc(keybytes * 2)) == NULL) { 132 free(r1); 133 free(r2); 134 free(rnd); 135 return (ENOMEM); 136 } 137 138 if ((output = (unsigned char *) malloc(keylength)) == NULL) { 139 free(r1); 140 free(r2); 141 free(rnd); 142 free(combined); 143 return (ENOMEM); 144 } 145 146 /* 147 * Get R1 and R2 (by running the input keys through the DR algorithm. 148 * Note this is most of derive-key, but not all. 149 */ 150 151 input.length = key2->length; 152 input.data = (char *) key2->contents; 153 if ((ret = dr(context, enc, key1, r1, &input))) 154 goto cleanup; 155 156 #if 0 157 { 158 int i; 159 printf("R1 ="); 160 for (i = 0; i < keybytes; i++) 161 printf(" %02x", (unsigned char) r1[i]); 162 printf("\n"); 163 } 164 #endif 165 166 input.length = key1->length; 167 input.data = (char *) key1->contents; 168 if ((ret = dr(context, enc, key2, r2, &input))) 169 goto cleanup; 170 171 #if 0 172 { 173 int i; 174 printf("R2 ="); 175 for (i = 0; i < keybytes; i++) 176 printf(" %02x", (unsigned char) r2[i]); 177 printf("\n"); 178 } 179 #endif 180 181 /* 182 * Concatenate the two keys together, and then run them through 183 * n-fold to reduce them to a length appropriate for the random-to-key 184 * operation. Note here that krb5_nfold() takes sizes in bits, hence 185 * the multiply by 8. 186 */ 187 188 memcpy(combined, r1, keybytes); 189 memcpy(combined + keybytes, r2, keybytes); 190 191 krb5_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd); 192 193 #if 0 194 { 195 int i; 196 printf("rnd ="); 197 for (i = 0; i < keybytes; i++) 198 printf(" %02x", (unsigned char) rnd[i]); 199 printf("\n"); 200 } 201 #endif 202 203 /* 204 * Run the "random" bits through random-to-key to produce a encryption 205 * key. 206 */ 207 208 randbits.length = keybytes; 209 randbits.data = (char *) rnd; 210 tkey.length = keylength; 211 tkey.contents = output; 212 213 if ((ret = (*(enc->make_key))(context, &randbits, &tkey))) 214 goto cleanup; 215 216 #if 0 217 { 218 int i; 219 printf("tkey ="); 220 for (i = 0; i < tkey.length; i++) 221 printf(" %02x", (unsigned char) tkey.contents[i]); 222 printf("\n"); 223 } 224 #endif 225 226 /* 227 * Run through derive-key one more time to produce the final key. 228 * Note that the input to derive-key is the ASCII string "combine". 229 */ 230 231 input.length = 7; /* Note; change this if string length changes */ 232 input.data = "combine"; 233 234 /* 235 * Just FYI: _if_ we have space here in the key, then simply use it 236 * without modification. But if the key is blank (no allocated storage) 237 * then allocate some memory for it. This allows programs to use one of 238 * the existing keys as the output key, _or_ pass in a blank keyblock 239 * for us to allocate. It's easier for us to allocate it since we already 240 * know the crypto library internals 241 */ 242 243 if (outkey->length == 0 || outkey->contents == NULL) { 244 outkey->contents = (krb5_octet *) malloc(keylength); 245 if (!outkey->contents) { 246 ret = ENOMEM; 247 goto cleanup; 248 } 249 outkey->length = keylength; 250 outkey->enctype = key1->enctype; 251 myalloc = 1; 252 } 253 254 if ((ret = krb5_derive_key(context, enc, &tkey, outkey, &input))) { 255 if (myalloc) { 256 free(outkey->contents); 257 outkey->contents = NULL; 258 } 259 goto cleanup; 260 } 261 262 #if 0 263 { 264 int i; 265 printf("output ="); 266 for (i = 0; i < outkey->length; i++) 267 printf(" %02x", (unsigned char) outkey->contents[i]); 268 printf("\n"); 269 } 270 #endif 271 272 ret = 0; 273 274 cleanup: 275 memset(r1, 0, keybytes); 276 memset(r2, 0, keybytes); 277 memset(rnd, 0, keybytes); 278 memset(combined, 0, keybytes * 2); 279 memset(output, 0, keylength); 280 281 free(r1); 282 free(r2); 283 free(rnd); 284 free(combined); 285 free(output); 286 287 return (ret); 288 } 289 290 /* 291 * Our DR function; mostly taken from derive.c 292 */ 293 294 static krb5_error_code dr 295 ( krb5_context context, 296 const struct krb5_enc_provider *enc, 297 const krb5_keyblock *inkey, 298 unsigned char *out, 299 const krb5_data *in_constant) 300 { 301 size_t blocksize, keybytes, keylength, n; 302 unsigned char *inblockdata, *outblockdata; 303 krb5_data inblock, outblock; 304 305 (*(enc->block_size))(&blocksize); 306 (*(enc->keysize))(&keybytes, &keylength); 307 308 /* allocate and set up buffers */ 309 310 if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL) 311 return(ENOMEM); 312 313 if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) { 314 free(inblockdata); 315 return(ENOMEM); 316 } 317 318 inblock.data = (char *) inblockdata; 319 inblock.length = blocksize; 320 321 outblock.data = (char *) outblockdata; 322 outblock.length = blocksize; 323 324 /* initialize the input block */ 325 326 if (in_constant->length == inblock.length) { 327 memcpy(inblock.data, in_constant->data, inblock.length); 328 } else { 329 krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data, 330 inblock.length*8, (unsigned char *) inblock.data); 331 } 332 333 /* loop encrypting the blocks until enough key bytes are generated */ 334 335 n = 0; 336 while (n < keybytes) { 337 (*(enc->encrypt))(context, inkey, 0, &inblock, &outblock); 338 339 if ((keybytes - n) <= outblock.length) { 340 memcpy(out+n, outblock.data, (keybytes - n)); 341 break; 342 } 343 344 memcpy(out+n, outblock.data, outblock.length); 345 memcpy(inblock.data, outblock.data, outblock.length); 346 n += outblock.length; 347 } 348 349 /* clean memory, free resources and exit */ 350 351 memset(inblockdata, 0, blocksize); 352 memset(outblockdata, 0, blocksize); 353 354 free(outblockdata); 355 free(inblockdata); 356 357 return(0); 358 } 359 360