1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * generic_key.c 39 */ 40 41 #include <mp.h> 42 #include <time.h> 43 #include <rpc/rpc.h> 44 #include <stdlib.h> 45 46 #define BASEBITS (8 * sizeof (char)) 47 #define BASE (1 << BASEBITS) 48 49 extern void des_setparity(char *); 50 extern void des_setparity_g(des_block *); 51 52 /* 53 * seed the random generator. Here we use the time of day and a supplied 54 * password for generating the seed. 55 */ 56 static void 57 setseed(unsigned char *pass) 58 { 59 int i; 60 int rseed; 61 struct timeval tv; 62 63 (void) gettimeofday(&tv, (struct timezone *)NULL); 64 rseed = tv.tv_sec + tv.tv_usec; 65 66 for (i = 0; i < 8; i++) { 67 rseed ^= (rseed << 8) | pass[i]; 68 } 69 (void) srandom(rseed); 70 } 71 72 /* 73 * Adjust the input key so that it is 0-filled on the left and store 74 * the results in key out. 75 */ 76 static void 77 adjust(char *keyout, char *keyin, int keylen) 78 { 79 char *p; 80 char *s; 81 int hexkeybytes = (keylen+3)/4; 82 83 for (p = keyin; *p; p++); 84 for (s = keyout + hexkeybytes; p >= keyin; p--, s--) { 85 *s = *p; 86 } 87 while (s >= keyout) { 88 *s-- = '0'; 89 } 90 } 91 92 /* 93 * __generic_gen_dhkeys: Classic Diffie-Hellman key pair generation. 94 * Generate a Diffie-Hellman key pair of a given key length using 95 * the supplied modulus and root. To calculate the pair we generate 96 * a random key of the appropriate key length modulo the modulus. 97 * This random key is the private key of the key pair. We now compute 98 * the public key as PublicKey = root^PrivateKey % modulus. This routine 99 * make use of libmp to do the multiprecision interger arithmetic. 100 */ 101 void 102 __generic_gen_dhkeys(int keylen, /* Size of keys in bits */ 103 char *xmodulus, /* The modulus */ 104 int proot, /* The prime root */ 105 char *public, /* Public key */ 106 char *secret, /* Private key */ 107 char *pass /* password to seed with for private key */) 108 { 109 int i, len; 110 MINT *pk = mp_itom(0); /* Initial public key */ 111 MINT *sk = mp_itom(0); /* Initial private key */ 112 MINT *tmp; 113 MINT *base = mp_itom(BASE); /* We shift by BASEBITS */ 114 MINT *root = mp_itom(proot); /* We get the root as a MINT */ 115 /* Convert the modulus from a hex string to a MINT */ 116 MINT *modulus = mp_xtom(xmodulus); 117 unsigned char seed; 118 char *xkey; 119 120 /* Seed the random generate */ 121 setseed((u_char *)pass); 122 123 /* 124 * We will break up the private key into groups of BASEBITS where 125 * BASEBITS is equal to the number of bits in an integer type. 126 * Curently, basebits is 8 so the integral type is a character. 127 * We will calculate the number of BASEBITS units that we need so 128 * that we have at least keylen bits. 129 */ 130 len = ((keylen + BASEBITS - 1) / BASEBITS); 131 132 /* 133 * Now for each BASEBITS we calculate a new random number. 134 * Shift the private key by base bits and then add the 135 * generated random number. 136 */ 137 for (i = 0; i < len; i++) { 138 /* get a random number */ 139 seed = random() ^ pass[i % 8]; 140 /* Convert it to a MINT */ 141 tmp = mp_itom(seed); 142 /* Shift the private key */ 143 mp_mult(sk, base, sk); 144 /* Add in the new low order bits */ 145 mp_madd(sk, tmp, sk); 146 /* Free tmp */ 147 mp_mfree(tmp); 148 } 149 150 /* Set timp to 0 */ 151 tmp = mp_itom(0); 152 /* We get the private keys as private key modulo the modulus */ 153 mp_mdiv(sk, modulus, tmp, sk); 154 /* Done with tmp */ 155 mp_mfree(tmp); 156 /* The public key is root^sk % modulus */ 157 mp_pow(root, sk, modulus, pk); 158 /* Convert the private key to a hex string */ 159 xkey = mp_mtox(sk); 160 /* Set leading zeros if necessary and store in secret */ 161 (void) adjust(secret, xkey, keylen); 162 /* Done with xkey */ 163 free(xkey); 164 /* Now set xkey to the hex representation of the public key */ 165 xkey = mp_mtox(pk); 166 /* Set leading zeros and store in public */ 167 (void) adjust(public, xkey, keylen); 168 169 /* Free storage */ 170 free(xkey); 171 172 mp_mfree(sk); 173 mp_mfree(base); 174 mp_mfree(pk); 175 mp_mfree(root); 176 mp_mfree(modulus); 177 } 178 179 /* 180 * Given a key extract keynum des keys 181 */ 182 static void 183 extractdeskeys(MINT *ck, int keylen, des_block keys[], int keynum) 184 { 185 MINT *a; 186 short r; 187 int i; 188 short base = (1 << 8); 189 char *k; 190 /* len is the total number of bits we need for keynum des keys */ 191 int len = 8 * sizeof (des_block) * keynum; 192 extern void _mp_move(MINT *, MINT *); 193 194 /* Create a MINT a to hold the common key */ 195 a = mp_itom(0); 196 _mp_move(ck, a); 197 198 199 /* 200 * Calculate the middle byte in the key. We will simply extract 201 * the middle bits of the key for the bits in our DES keys. 202 */ 203 for (i = 0; i < ((keylen - len)/2)/8; i++) 204 mp_sdiv(a, base, a, &r); /* Shift the key by one byte */ 205 206 /* 207 * Now take our middle bits referenced by a and shove them 208 * into the array of DES keys. 209 */ 210 k = (char *)keys; 211 for (i = 0; i < sizeof (des_block) * keynum; i++) { 212 mp_sdiv(a, base, a, &r); 213 *k++ = r; 214 } 215 216 /* We're done with a */ 217 mp_mfree(a); 218 219 /* Set the DES parity for each key */ 220 for (i = 0; i < keynum; i++) 221 if (keylen == 192) /* Old broken way for compatibility */ 222 des_setparity((char *)&keys[i]); 223 else 224 des_setparity_g(&keys[i]); 225 } 226 227 228 /* 229 * __generic_common_dhkeys: Generate a set of DES keys based on 230 * the Diffie-Hellman common key derived from the supplied key pair 231 * of the given key length using the passed in modulus. The common key 232 * is calculated as: 233 * 234 * ck = pk ^ sk % modulus 235 * 236 * We will use the above routine to extract a set of DES keys for the 237 * caller. 238 */ 239 void 240 __generic_common_dhkeys(char *pkey, /* Public key of remote */ 241 char *skey, /* Our private key */ 242 int keylen, /* All the keys have this many bits */ 243 char *xmodulus, /* The modulus */ 244 des_block keys[], /* DES keys to fill */ 245 int keynum /* The number of DES keys to create */) 246 { 247 /* Convert hex string representations to MINTS */ 248 MINT *pk = mp_xtom(pkey); 249 MINT *sk = mp_xtom(skey); 250 MINT *modulus = mp_xtom(xmodulus); 251 /* Create a MINT for the common key */ 252 MINT *ck = mp_itom(0); 253 254 /* ck = pk ^ sk % modulus */ 255 mp_pow(pk, sk, modulus, ck); 256 257 /* Set the DES keys */ 258 extractdeskeys(ck, keylen, keys, keynum); 259 260 /* Clean up */ 261 mp_mfree(pk); 262 mp_mfree(sk); 263 mp_mfree(modulus); 264 mp_mfree(ck); 265 } 266