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