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 /*
36 * generic_key.c
37 */
38
39 #include <mp.h>
40 #include <time.h>
41 #include <rpc/rpc.h>
42 #include <stdlib.h>
43
44 #define BASEBITS (8 * sizeof (char))
45 #define BASE (1 << BASEBITS)
46
47 extern void des_setparity(char *);
48 extern void des_setparity_g(des_block *);
49
50 /*
51 * seed the random generator. Here we use the time of day and a supplied
52 * password for generating the seed.
53 */
54 static void
setseed(unsigned char * pass)55 setseed(unsigned char *pass)
56 {
57 int i;
58 int rseed;
59 struct timeval tv;
60
61 (void) gettimeofday(&tv, (struct timezone *)NULL);
62 rseed = tv.tv_sec + tv.tv_usec;
63
64 for (i = 0; i < 8; i++) {
65 rseed ^= (rseed << 8) | pass[i];
66 }
67 (void) srandom(rseed);
68 }
69
70 /*
71 * Adjust the input key so that it is 0-filled on the left and store
72 * the results in key out.
73 */
74 static void
adjust(char * keyout,char * keyin,int keylen)75 adjust(char *keyout, char *keyin, int keylen)
76 {
77 char *p;
78 char *s;
79 int hexkeybytes = (keylen+3)/4;
80
81 for (p = keyin; *p; p++);
82 for (s = keyout + hexkeybytes; p >= keyin; p--, s--) {
83 *s = *p;
84 }
85 while (s >= keyout) {
86 *s-- = '0';
87 }
88 }
89
90 /*
91 * __generic_gen_dhkeys: Classic Diffie-Hellman key pair generation.
92 * Generate a Diffie-Hellman key pair of a given key length using
93 * the supplied modulus and root. To calculate the pair we generate
94 * a random key of the appropriate key length modulo the modulus.
95 * This random key is the private key of the key pair. We now compute
96 * the public key as PublicKey = root^PrivateKey % modulus. This routine
97 * make use of libmp to do the multiprecision interger arithmetic.
98 */
99 void
__generic_gen_dhkeys(int keylen,char * xmodulus,int proot,char * public,char * secret,char * pass)100 __generic_gen_dhkeys(int keylen, /* Size of keys in bits */
101 char *xmodulus, /* The modulus */
102 int proot, /* The prime root */
103 char *public, /* Public key */
104 char *secret, /* Private key */
105 char *pass /* password to seed with for private key */)
106 {
107 int i, len;
108 MINT *pk = mp_itom(0); /* Initial public key */
109 MINT *sk = mp_itom(0); /* Initial private key */
110 MINT *tmp;
111 MINT *base = mp_itom(BASE); /* We shift by BASEBITS */
112 MINT *root = mp_itom(proot); /* We get the root as a MINT */
113 /* Convert the modulus from a hex string to a MINT */
114 MINT *modulus = mp_xtom(xmodulus);
115 unsigned char seed;
116 char *xkey;
117
118 /* Seed the random generate */
119 setseed((u_char *)pass);
120
121 /*
122 * We will break up the private key into groups of BASEBITS where
123 * BASEBITS is equal to the number of bits in an integer type.
124 * Curently, basebits is 8 so the integral type is a character.
125 * We will calculate the number of BASEBITS units that we need so
126 * that we have at least keylen bits.
127 */
128 len = ((keylen + BASEBITS - 1) / BASEBITS);
129
130 /*
131 * Now for each BASEBITS we calculate a new random number.
132 * Shift the private key by base bits and then add the
133 * generated random number.
134 */
135 for (i = 0; i < len; i++) {
136 /* get a random number */
137 seed = random() ^ pass[i % 8];
138 /* Convert it to a MINT */
139 tmp = mp_itom(seed);
140 /* Shift the private key */
141 mp_mult(sk, base, sk);
142 /* Add in the new low order bits */
143 mp_madd(sk, tmp, sk);
144 /* Free tmp */
145 mp_mfree(tmp);
146 }
147
148 /* Set timp to 0 */
149 tmp = mp_itom(0);
150 /* We get the private keys as private key modulo the modulus */
151 mp_mdiv(sk, modulus, tmp, sk);
152 /* Done with tmp */
153 mp_mfree(tmp);
154 /* The public key is root^sk % modulus */
155 mp_pow(root, sk, modulus, pk);
156 /* Convert the private key to a hex string */
157 xkey = mp_mtox(sk);
158 /* Set leading zeros if necessary and store in secret */
159 (void) adjust(secret, xkey, keylen);
160 /* Done with xkey */
161 free(xkey);
162 /* Now set xkey to the hex representation of the public key */
163 xkey = mp_mtox(pk);
164 /* Set leading zeros and store in public */
165 (void) adjust(public, xkey, keylen);
166
167 /* Free storage */
168 free(xkey);
169
170 mp_mfree(sk);
171 mp_mfree(base);
172 mp_mfree(pk);
173 mp_mfree(root);
174 mp_mfree(modulus);
175 }
176
177 /*
178 * Given a key extract keynum des keys
179 */
180 static void
extractdeskeys(MINT * ck,int keylen,des_block keys[],int keynum)181 extractdeskeys(MINT *ck, int keylen, des_block keys[], int keynum)
182 {
183 MINT *a;
184 short r;
185 int i;
186 short base = (1 << 8);
187 char *k;
188 /* len is the total number of bits we need for keynum des keys */
189 int len = 8 * sizeof (des_block) * keynum;
190 extern void _mp_move(MINT *, MINT *);
191
192 /* Create a MINT a to hold the common key */
193 a = mp_itom(0);
194 _mp_move(ck, a);
195
196
197 /*
198 * Calculate the middle byte in the key. We will simply extract
199 * the middle bits of the key for the bits in our DES keys.
200 */
201 for (i = 0; i < ((keylen - len)/2)/8; i++)
202 mp_sdiv(a, base, a, &r); /* Shift the key by one byte */
203
204 /*
205 * Now take our middle bits referenced by a and shove them
206 * into the array of DES keys.
207 */
208 k = (char *)keys;
209 for (i = 0; i < sizeof (des_block) * keynum; i++) {
210 mp_sdiv(a, base, a, &r);
211 *k++ = r;
212 }
213
214 /* We're done with a */
215 mp_mfree(a);
216
217 /* Set the DES parity for each key */
218 for (i = 0; i < keynum; i++)
219 if (keylen == 192) /* Old broken way for compatibility */
220 des_setparity((char *)&keys[i]);
221 else
222 des_setparity_g(&keys[i]);
223 }
224
225
226 /*
227 * __generic_common_dhkeys: Generate a set of DES keys based on
228 * the Diffie-Hellman common key derived from the supplied key pair
229 * of the given key length using the passed in modulus. The common key
230 * is calculated as:
231 *
232 * ck = pk ^ sk % modulus
233 *
234 * We will use the above routine to extract a set of DES keys for the
235 * caller.
236 */
237 void
__generic_common_dhkeys(char * pkey,char * skey,int keylen,char * xmodulus,des_block keys[],int keynum)238 __generic_common_dhkeys(char *pkey, /* Public key of remote */
239 char *skey, /* Our private key */
240 int keylen, /* All the keys have this many bits */
241 char *xmodulus, /* The modulus */
242 des_block keys[], /* DES keys to fill */
243 int keynum /* The number of DES keys to create */)
244 {
245 /* Convert hex string representations to MINTS */
246 MINT *pk = mp_xtom(pkey);
247 MINT *sk = mp_xtom(skey);
248 MINT *modulus = mp_xtom(xmodulus);
249 /* Create a MINT for the common key */
250 MINT *ck = mp_itom(0);
251
252 /* ck = pk ^ sk % modulus */
253 mp_pow(pk, sk, modulus, ck);
254
255 /* Set the DES keys */
256 extractdeskeys(ck, keylen, keys, keynum);
257
258 /* Clean up */
259 mp_mfree(pk);
260 mp_mfree(sk);
261 mp_mfree(modulus);
262 mp_mfree(ck);
263 }
264