Home | History | Annotate | Download | only in crypto
      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