/* * 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 #include #include #include #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); }