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