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 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 /* 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 */ 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