generic_key.c revision 2
0N/A/*
710N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
0N/A * Common Development and Distribution License, Version 1.0 only
0N/A * (the "License"). You may not use this file except in compliance
0N/A * with the License.
0N/A *
0N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0N/A * or http://www.opensolaris.org/os/licensing.
0N/A * See the License for the specific language governing permissions
0N/A * and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information: Portions Copyright [yyyy] [name of copyright owner]
0N/A *
0N/A * CDDL HEADER END
0N/A */
0N/A/*
0N/A * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
0N/A * Use is subject to license terms.
0N/A */
0N/A
0N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
0N/A/* All Rights Reserved */
0N/A
0N/A/*
0N/A * Portions of this source code were derived from Berkeley 4.3 BSD
0N/A * under license from the Regents of the University of California.
0N/A */
0N/A
0N/A#pragma ident "%Z%%M% %I% %E% SMI"
710N/A
431N/A/*
0N/A * generic_key.c
0N/A */
0N/A
0N/A#include <mp.h>
0N/A#include <time.h>
0N/A#include <rpc/rpc.h>
0N/A#include <stdlib.h>
0N/A
0N/A#define BASEBITS (8 * sizeof (char))
0N/A#define BASE (1 << BASEBITS)
0N/A
0N/Aextern void des_setparity(char *);
0N/Aextern void des_setparity_g(des_block *);
0N/A
0N/A/*
0N/A * seed the random generator. Here we use the time of day and a supplied
0N/A * password for generating the seed.
0N/A */
0N/Astatic void
0N/Asetseed(unsigned char *pass)
0N/A{
0N/A int i;
0N/A int rseed;
0N/A struct timeval tv;
0N/A
0N/A (void) gettimeofday(&tv, (struct timezone *)NULL);
0N/A rseed = tv.tv_sec + tv.tv_usec;
0N/A
0N/A for (i = 0; i < 8; i++) {
0N/A rseed ^= (rseed << 8) | pass[i];
0N/A }
0N/A (void) srandom(rseed);
0N/A}
0N/A
0N/A/*
0N/A * Adjust the input key so that it is 0-filled on the left and store
0N/A * the results in key out.
0N/A */
0N/Astatic void
0N/Aadjust(char *keyout, char *keyin, int keylen)
0N/A{
0N/A char *p;
0N/A char *s;
0N/A int hexkeybytes = (keylen+3)/4;
0N/A
0N/A for (p = keyin; *p; p++);
0N/A for (s = keyout + hexkeybytes; p >= keyin; p--, s--) {
0N/A *s = *p;
0N/A }
0N/A while (s >= keyout) {
0N/A *s-- = '0';
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * __generic_gen_dhkeys: Classic Diffie-Hellman key pair generation.
0N/A * Generate a Diffie-Hellman key pair of a given key length using
0N/A * the supplied modulus and root. To calculate the pair we generate
0N/A * a random key of the appropriate key length modulo the modulus.
0N/A * This random key is the private key of the key pair. We now compute
0N/A * the public key as PublicKey = root^PrivateKey % modulus. This routine
0N/A * make use of libmp to do the multiprecision interger arithmetic.
0N/A */
0N/Avoid
0N/A__generic_gen_dhkeys(int keylen, /* Size of keys in bits */
0N/A char *xmodulus, /* The modulus */
0N/A int proot, /* The prime root */
0N/A char *public, /* Public key */
0N/A char *secret, /* Private key */
0N/A char *pass /* password to seed with for private key */)
0N/A{
0N/A int i, len;
0N/A MINT *pk = mp_itom(0); /* Initial public key */
0N/A MINT *sk = mp_itom(0); /* Initial private key */
0N/A MINT *tmp;
0N/A MINT *base = mp_itom(BASE); /* We shift by BASEBITS */
0N/A MINT *root = mp_itom(proot); /* We get the root as a MINT */
0N/A /* Convert the modulus from a hex string to a MINT */
0N/A MINT *modulus = mp_xtom(xmodulus);
0N/A unsigned char seed;
0N/A char *xkey;
0N/A
0N/A /* Seed the random generate */
0N/A setseed((u_char *)pass);
0N/A
0N/A /*
0N/A * We will break up the private key into groups of BASEBITS where
0N/A * BASEBITS is equal to the number of bits in an integer type.
0N/A * Curently, basebits is 8 so the integral type is a character.
0N/A * We will calculate the number of BASEBITS units that we need so
0N/A * that we have at least keylen bits.
0N/A */
0N/A len = ((keylen + BASEBITS - 1) / BASEBITS);
0N/A
0N/A /*
0N/A * Now for each BASEBITS we calculate a new random number.
0N/A * Shift the private key by base bits and then add the
0N/A * generated random number.
0N/A */
0N/A for (i = 0; i < len; i++) {
0N/A /* get a random number */
0N/A seed = random() ^ pass[i % 8];
0N/A /* Convert it to a MINT */
0N/A tmp = mp_itom(seed);
0N/A /* Shift the private key */
0N/A mp_mult(sk, base, sk);
0N/A /* Add in the new low order bits */
0N/A mp_madd(sk, tmp, sk);
0N/A /* Free tmp */
0N/A mp_mfree(tmp);
710N/A }
710N/A
710N/A /* Set timp to 0 */
710N/A tmp = mp_itom(0);
710N/A /* We get the private keys as private key modulo the modulus */
0N/A mp_mdiv(sk, modulus, tmp, sk);
0N/A /* Done with tmp */
0N/A mp_mfree(tmp);
0N/A /* The public key is root^sk % modulus */
0N/A mp_pow(root, sk, modulus, pk);
0N/A /* Convert the private key to a hex string */
0N/A xkey = mp_mtox(sk);
0N/A /* Set leading zeros if necessary and store in secret */
0N/A (void) adjust(secret, xkey, keylen);
0N/A /* Done with xkey */
0N/A free(xkey);
0N/A /* Now set xkey to the hex representation of the public key */
0N/A xkey = mp_mtox(pk);
0N/A /* Set leading zeros and store in public */
0N/A (void) adjust(public, xkey, keylen);
0N/A
0N/A /* Free storage */
0N/A free(xkey);
0N/A
0N/A mp_mfree(sk);
0N/A mp_mfree(base);
0N/A mp_mfree(pk);
0N/A mp_mfree(root);
0N/A mp_mfree(modulus);
0N/A}
0N/A
0N/A/*
0N/A * Given a key extract keynum des keys
0N/A */
0N/Astatic void
0N/Aextractdeskeys(MINT *ck, int keylen, des_block keys[], int keynum)
0N/A{
0N/A MINT *a;
0N/A short r;
0N/A int i;
0N/A short base = (1 << 8);
0N/A char *k;
0N/A /* len is the total number of bits we need for keynum des keys */
0N/A int len = 8 * sizeof (des_block) * keynum;
0N/A extern void _mp_move(MINT *, MINT *);
0N/A
0N/A /* Create a MINT a to hold the common key */
0N/A a = mp_itom(0);
0N/A _mp_move(ck, a);
0N/A
0N/A
0N/A /*
0N/A * Calculate the middle byte in the key. We will simply extract
0N/A * the middle bits of the key for the bits in our DES keys.
0N/A */
0N/A for (i = 0; i < ((keylen - len)/2)/8; i++)
0N/A mp_sdiv(a, base, a, &r); /* Shift the key by one byte */
0N/A
0N/A /*
0N/A * Now take our middle bits referenced by a and shove them
0N/A * into the array of DES keys.
0N/A */
0N/A k = (char *)keys;
0N/A for (i = 0; i < sizeof (des_block) * keynum; i++) {
710N/A mp_sdiv(a, base, a, &r);
710N/A *k++ = r;
710N/A }
710N/A
431N/A /* We're done with a */
431N/A mp_mfree(a);
431N/A
431N/A /* Set the DES parity for each key */
431N/A for (i = 0; i < keynum; i++)
431N/A if (keylen == 192) /* Old broken way for compatibility */
431N/A des_setparity((char *)&keys[i]);
431N/A else
431N/A des_setparity_g(&keys[i]);
431N/A}
431N/A
431N/A
431N/A/*
431N/A * __generic_common_dhkeys: Generate a set of DES keys based on
431N/A * the Diffie-Hellman common key derived from the supplied key pair
431N/A * of the given key length using the passed in modulus. The common key
431N/A * is calculated as:
431N/A *
431N/A * ck = pk ^ sk % modulus
431N/A *
431N/A * We will use the above routine to extract a set of DES keys for the
431N/A * caller.
431N/A */
431N/Avoid
431N/A__generic_common_dhkeys(char *pkey, /* Public key of remote */
431N/A char *skey, /* Our private key */
431N/A int keylen, /* All the keys have this many bits */
431N/A char *xmodulus, /* The modulus */
431N/A des_block keys[], /* DES keys to fill */
0N/A int keynum /* The number of DES keys to create */)
0N/A{
0N/A /* Convert hex string representations to MINTS */
0N/A MINT *pk = mp_xtom(pkey);
0N/A MINT *sk = mp_xtom(skey);
0N/A MINT *modulus = mp_xtom(xmodulus);
0N/A /* Create a MINT for the common key */
0N/A MINT *ck = mp_itom(0);
0N/A
0N/A /* ck = pk ^ sk % modulus */
0N/A mp_pow(pk, sk, modulus, ck);
0N/A
0N/A /* Set the DES keys */
0N/A extractdeskeys(ck, keylen, keys, keynum);
0N/A
973N/A /* Clean up */
431N/A mp_mfree(pk);
710N/A mp_mfree(sk);
973N/A mp_mfree(modulus);
431N/A mp_mfree(ck);
431N/A}
431N/A