xref: /illumos-gate/usr/src/lib/libnsl/key/gen_dhkeys.c (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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 2003 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 #include "mt.h"
38 #include <stdlib.h>
39 #include <mp.h>
40 #include <rpc/key_prot.h>
41 #include <rpcsvc/nis_dhext.h>
42 #include <thread.h>
43 
44 extern long	random();
45 extern void	_mp_move(MINT *, MINT *);
46 extern void	des_setparity(char *);
47 static void	adjust();
48 void		__gen_dhkeys();
49 
50 static MINT	*MODULUS_192_0;
51 static mutex_t	mod_192_0_lck = DEFAULTMUTEX;
52 static bool_t	first_time = TRUE;
53 
54 /*
55  * symbol names for the entry points into the Diffie-Hellman
56  * GSS mech backend routines
57  */
58 static char	dl_gen_funcname[] = "__dl_gen_dhkeys";
59 static char	dl_gen_common_funcname[] = "__dl_gen_common_dhkeys";
60 
61 /*
62  * Generate a seed
63  */
64 static void
65 getseed(seed, seedsize, pass)
66 char *seed;
67 int seedsize;
68 unsigned char *pass;
69 {
70 	int i;
71 	int rseed;
72 	struct timeval tv;
73 
74 	(void) gettimeofday(&tv, (struct timezone *)NULL);
75 	rseed = tv.tv_sec + tv.tv_usec;
76 	for (i = 0; i < 8; i++) {
77 		rseed ^= (rseed << 8) | pass[i];
78 	}
79 	(void) srandom(rseed);
80 
81 	for (i = 0; i < seedsize; i++) {
82 		seed[i] = (random() & 0xff) ^ pass[i % 8];
83 	}
84 }
85 
86 /*
87  * Adjust the input key so that it is 0-filled on the left
88  */
89 static void
90 adjust(keyout, keyin)
91 char keyout[HEXKEYBYTES + 1];
92 char *keyin;
93 {
94 	char *p;
95 	char *s;
96 
97 	for (p = keyin; *p; p++)
98 		;
99 	for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
100 		*s = *p;
101 	}
102 	while (s >= keyout) {
103 		*s-- = '0';
104 	}
105 }
106 
107 /*
108  * generate a Diffie-Hellman key-pair based on the given password.
109  * public and secret are buffers of size HEXKEYBYTES + 1.
110  */
111 void
112 __gen_dhkeys(public, secret, pass)
113 char *public;
114 char *secret;
115 char *pass;
116 {
117 	int i;
118 
119 #define	BASEBITS	(8 * sizeof (short) - 1)
120 #define	BASE		(1 << BASEBITS)
121 
122 	MINT *pk = mp_itom(0);
123 	MINT *sk = mp_itom(0);
124 	MINT *tmp;
125 	MINT *base = mp_itom(BASE/2);	/* BASE won't fit in a short */
126 	MINT *root = mp_itom(PROOT);
127 	MINT *modulus = mp_xtom(HEXMODULUS);
128 	unsigned short r;
129 	unsigned short seed[KEYSIZE/BASEBITS + 1];
130 	char *xkey;
131 
132 	/* multiply base by 2 to get BASE */
133 	tmp = mp_itom(2);
134 	mp_mult(base, tmp, base);
135 	mp_mfree(tmp);
136 
137 	getseed((char *)seed, (int)sizeof (seed), (uchar_t *)pass);
138 	for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
139 		r = seed[i] % ((unsigned short)BASE);
140 		tmp = mp_itom(r);
141 		mp_mult(sk, base, sk);
142 		mp_madd(sk, tmp, sk);
143 		mp_mfree(tmp);
144 	}
145 	tmp = mp_itom(0);
146 	mp_mdiv(sk, modulus, tmp, sk);
147 	mp_mfree(tmp);
148 	mp_pow(root, sk, modulus, pk);
149 	xkey = mp_mtox(sk);
150 	(void) adjust(secret, xkey);
151 	xkey = mp_mtox(pk);
152 	(void) adjust(public, xkey);
153 	mp_mfree(sk);
154 	mp_mfree(base);
155 	mp_mfree(pk);
156 	mp_mfree(root);
157 	mp_mfree(modulus);
158 }
159 
160 
161 /*
162  * Generic key size Diffie-Hellman key pair generation routine.  For classic
163  * AUTH_DES, just call the current routine to handle it.  Else, call the
164  * one in the appro GSS mech backend.
165  *
166  */
167 int
168 __gen_dhkeys_g(char *pkey,	/* out */
169 	char *skey,		/* out */
170 	keylen_t keylen,	/* in  */
171 	algtype_t algtype,	/* in  */
172 	char *pass)		/* in  */
173 {
174 	const int classic_des = keylen == 192 && algtype == 0;
175 
176 	if (! pkey || ! skey || ! pass)
177 		return (0);
178 
179 	if (classic_des) {
180 		__gen_dhkeys(pkey, skey, pass);
181 		return (1);
182 	} else {
183 		int (*dlfp)(); /* func ptr to dynamic loaded lib */
184 
185 		if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen,
186 							algtype,
187 							dl_gen_funcname)) {
188 			(*dlfp)(pkey, skey, pass); /* void */
189 			return (1);
190 		}
191 	}
192 
193 	return (0);
194 }
195 
196 
197 /*
198  * Choose middle 64 bits of the common key to use as our des key, possibly
199  * overwriting the lower order bits by setting parity.
200  *
201  * (copied/moved) from keyserv's setkey.c for the DH extensions.
202  */
203 int
204 __extractdeskey(ck, deskey)
205 	MINT *ck;
206 	des_block *deskey;
207 {
208 	MINT *a;
209 	short r;
210 	int i;
211 	short base = (1 << 8);
212 	char *k;
213 
214 	a = mp_itom(0);
215 	_mp_move(ck, a);
216 	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
217 		mp_sdiv(a, base, a, &r);
218 	}
219 	k = deskey->c;
220 	for (i = 0; i < 8; i++) {
221 		mp_sdiv(a, base, a, &r);
222 		*k++ = r;
223 	}
224 	mp_mfree(a);
225 	des_setparity((char *)deskey);
226 	return (0);
227 }
228 
229 
230 /*
231  * Set the modulus for all our 192bit (algtype=0) Diffie-Hellman operations
232  */
233 static void
234 setmodulus_192_0(void)
235 {
236 	(void) mutex_lock(&mod_192_0_lck);
237 	if (first_time) {
238 		first_time = FALSE;
239 		MODULUS_192_0 = mp_xtom(HEXMODULUS);
240 	}
241 	(void) mutex_unlock(&mod_192_0_lck);
242 }
243 
244 /*
245  * Generic key size Diffie-Hellman common key generation routine.
246  * For classic AUTH_DES, do it inline like it's already done in several
247  * places (keyserv being one place).  For new long key sizes,
248  * call the appro GSS mech backend routine.
249  *
250  * Arg 'keynum' is the size of the 'deskeys' array.  It should be a 1
251  * classic AUTH_DES and a 3 for new long DH keys.
252  *
253  * Returns 1 on success and 0 on err.
254  */
255 int
256 __gen_common_dhkeys_g(char *xpublic,	/* in  */
257 		char *xsecret,		/* in  */
258 		keylen_t keylen,	/* in  */
259 		algtype_t algtype,	/* in  */
260 		des_block deskeys[],	/* out */
261 		keynum_t keynum)	/* in  */
262 {
263 	const int classic_des = keylen == 192 && algtype == 0;
264 
265 	if (! xpublic || ! xsecret || ! deskeys)
266 		return (0);
267 
268 	if (classic_des) {
269 		MINT *common;
270 		MINT *public;
271 		MINT *secret;
272 
273 		setmodulus_192_0();
274 
275 		public = mp_xtom(xpublic);
276 		secret = mp_xtom(xsecret);
277 		common = mp_itom(0);
278 		mp_pow(public, secret, MODULUS_192_0, common);
279 		(void) __extractdeskey(common, &deskeys[0]);
280 		return (1);
281 	} else {
282 		int (*dlfp)(); /* func ptr to dynamically loaded lib */
283 
284 		if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen,
285 						algtype,
286 						dl_gen_common_funcname)) {
287 			/* function called will have void return value */
288 			(*dlfp)(xpublic, xsecret, deskeys, keynum);
289 			return (1);
290 		}
291 	}
292 
293 	return (0);
294 }
295