OpenSolaris_b135/lib/gss_mechs/mech_dh/dh_common/generic_key.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */

/*
 * Portions of this source code were derived from Berkeley 4.3 BSD
 * under license from the Regents of the University of California.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 *	generic_key.c
 */

#include <mp.h>
#include <time.h>
#include <rpc/rpc.h>
#include <stdlib.h>

#define	BASEBITS		(8 * sizeof (char))
#define	BASE			(1 << BASEBITS)

extern void des_setparity(char *);
extern void des_setparity_g(des_block *);

/*
 * seed the random generator. Here we use the time of day and a supplied
 * password for generating the seed.
 */
static void
setseed(unsigned char *pass)
{
	int i;
	int rseed;
	struct timeval tv;

	(void) gettimeofday(&tv, (struct timezone *)NULL);
	rseed = tv.tv_sec + tv.tv_usec;

	for (i = 0; i < 8; i++) {
		rseed ^= (rseed << 8) | pass[i];
	}
	(void) srandom(rseed);
}

/*
 * Adjust the input key so that it is 0-filled on the left and store
 * the results in key out.
 */
static void
adjust(char *keyout, char *keyin, int keylen)
{
	char *p;
	char *s;
	int hexkeybytes = (keylen+3)/4;

	for (p = keyin; *p; p++);
	for (s = keyout + hexkeybytes; p >= keyin; p--, s--) {
		*s = *p;
	}
	while (s >= keyout) {
		*s-- = '0';
	}
}

/*
 * __generic_gen_dhkeys: Classic Diffie-Hellman key pair generation.
 * Generate a Diffie-Hellman key pair of a given key length using
 * the supplied modulus and root. To calculate the pair we generate
 * a random key of the appropriate key length modulo the modulus.
 * This random key is the private key of the key pair. We now compute
 * the public key as PublicKey = root^PrivateKey % modulus. This routine
 * make use of libmp to do the multiprecision interger arithmetic.
 */
void
__generic_gen_dhkeys(int keylen, /* Size of keys in bits */
		    char *xmodulus, /* The modulus */
		    int proot, /* The prime root */
		    char *public, /* Public key */
		    char *secret, /* Private key */
		    char *pass    /* password to seed with for private key */)
{
	int i, len;
	MINT *pk = mp_itom(0);	/* Initial public key */
	MINT *sk = mp_itom(0);	/* Initial private key */
	MINT *tmp;
	MINT *base = mp_itom(BASE); 	/* We shift by BASEBITS */
	MINT *root = mp_itom(proot);    /* We get the root as a MINT */
	/* Convert the modulus from a hex string to a MINT */
	MINT *modulus = mp_xtom(xmodulus);
	unsigned char seed;
	char *xkey;

	/* Seed the random generate */
	setseed((u_char *)pass);

	/*
	 * We will break up the private key into  groups of BASEBITS where
	 * BASEBITS is equal to the number of bits in an integer type.
	 * Curently, basebits is 8 so the integral type is a character.
	 * We will calculate the number of BASEBITS units that we need so
	 * that we have at least keylen bits.
	 */
	len = ((keylen + BASEBITS - 1) / BASEBITS);

	/*
	 * Now for each BASEBITS we calculate a new random number.
	 * Shift the private key by base bits and then add the
	 * generated random number.
	 */
	for (i = 0; i < len; i++) {
		/* get a random number */
		seed = random() ^ pass[i % 8];
		/* Convert it to a MINT */
		tmp = mp_itom(seed);
		/* Shift the private key */
		mp_mult(sk, base, sk);
		/* Add in the new low order bits */
		mp_madd(sk, tmp, sk);
		/* Free tmp */
		mp_mfree(tmp);
	}

	/* Set timp to 0 */
	tmp = mp_itom(0);
	/* We get the private keys as private key modulo the modulus */
	mp_mdiv(sk, modulus, tmp, sk);
	/* Done with tmp */
	mp_mfree(tmp);
	/* The public key is root^sk % modulus */
	mp_pow(root, sk, modulus, pk);
	/* Convert the private key to a hex string */
	xkey = mp_mtox(sk);
	/* Set leading zeros if necessary and store in secret */
	(void) adjust(secret, xkey, keylen);
	/* Done with xkey */
	free(xkey);
	/* Now set xkey to the hex representation of the public key */
	xkey = mp_mtox(pk);
	/* Set leading zeros and store in public */
	(void) adjust(public, xkey, keylen);

	/* Free storage */
	free(xkey);

	mp_mfree(sk);
	mp_mfree(base);
	mp_mfree(pk);
	mp_mfree(root);
	mp_mfree(modulus);
}

/*
 * Given a key extract keynum des keys
 */
static void
extractdeskeys(MINT *ck, int keylen, des_block keys[], int keynum)
{
	MINT *a;
	short r;
	int i;
	short base = (1 << 8);
	char *k;
	/* len is the total number of bits we need for keynum des keys */
	int len = 8 * sizeof (des_block) * keynum;
	extern void _mp_move(MINT *, MINT *);

	/* Create a MINT a to hold the common key */
	a = mp_itom(0);
	_mp_move(ck, a);


	/*
	 * Calculate the middle byte in the key. We will simply extract
	 * the middle bits of the key for the bits in our DES keys.
	 */
	for (i = 0; i < ((keylen - len)/2)/8; i++)
		mp_sdiv(a, base, a, &r); /* Shift the key by one byte */

	/*
	 * Now take our middle bits referenced by a and shove them
	 * into the array of DES keys.
	 */
	k = (char *)keys;
	for (i = 0; i < sizeof (des_block) * keynum; i++) {
		mp_sdiv(a, base, a, &r);
		*k++ = r;
	}

	/* We're done with a */
	mp_mfree(a);

	/* Set the DES parity for each key */
	for (i = 0; i < keynum; i++)
		if (keylen == 192) /* Old broken way for compatibility */
			des_setparity((char *)&keys[i]);
		else
			des_setparity_g(&keys[i]);
}


/*
 * __generic_common_dhkeys: Generate a set of DES keys based on
 * the Diffie-Hellman common key derived from the supplied key pair
 * of the given key length using the passed in modulus. The common key
 *  is calculated as:
 *
 *	ck = pk ^ sk % modulus
 *
 * We will use the above routine to extract a set of DES keys for the
 * caller.
 */
void
__generic_common_dhkeys(char *pkey, /* Public key of remote */
			char *skey, /* Our private key */
			int keylen, /* All the keys have this many bits */
			char *xmodulus, /* The modulus */
			des_block keys[], /* DES keys to fill */
			int keynum /* The number of DES keys to create */)
{
	/* Convert hex string representations to MINTS */
	MINT *pk = mp_xtom(pkey);
	MINT *sk = mp_xtom(skey);
	MINT *modulus = mp_xtom(xmodulus);
	/* Create a MINT for the common key */
	MINT *ck = mp_itom(0);

	/* ck = pk ^ sk % modulus */
	mp_pow(pk, sk, modulus, ck);

	/* Set the DES keys */
	extractdeskeys(ck, keylen, keys, keynum);

	/* Clean up */
	mp_mfree(pk);
	mp_mfree(sk);
	mp_mfree(modulus);
	mp_mfree(ck);
}