xref: /freebsd/contrib/telnet/libtelnet/pk.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /* public key routines */
2 /* $FreeBSD$ */
3 /* functions:
4 	genkeys(char *public, char *secret)
5 	common_key(char *secret, char *public, desData *deskey)
6         pk_encode(char *in, *out, DesData *deskey);
7         pk_decode(char *in, *out, DesData *deskey);
8       where
9 	char public[HEXKEYBYTES + 1];
10 	char secret[HEXKEYBYTES + 1];
11  */
12 
13 #include <stdio.h>
14 #include <sys/time.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <openssl/des.h>
18 #include "mp.h"
19 #include "pk.h"
20 #if defined(SOLARIS2) || defined(LINUX)
21 #include <stdlib.h>
22 #endif
23 
24 /*
25  * Choose top 128 bits of the common key to use as our idea key.
26  */
27 static
28 extractideakey(ck, ideakey)
29         MINT *ck;
30         IdeaData *ideakey;
31 {
32         MINT *a;
33         MINT *z;
34         short r;
35         int i;
36         short base = (1 << 8);
37         char *k;
38 
39         z = itom(0);
40         a = itom(0);
41         madd(ck, z, a);
42         for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
43                 sdiv(a, base, a, &r);
44         }
45         k = (char *)ideakey;
46         for (i = 0; i < 16; i++) {
47                 sdiv(a, base, a, &r);
48                 *k++ = r;
49         }
50 	mfree(z);
51         mfree(a);
52 }
53 
54 /*
55  * Choose middle 64 bits of the common key to use as our des key, possibly
56  * overwriting the lower order bits by setting parity.
57  */
58 static
59 extractdeskey(ck, deskey)
60         MINT *ck;
61         DesData *deskey;
62 {
63         MINT *a;
64         MINT *z;
65         short r;
66         int i;
67         short base = (1 << 8);
68         char *k;
69 
70         z = itom(0);
71         a = itom(0);
72         madd(ck, z, a);
73         for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
74                 sdiv(a, base, a, &r);
75         }
76         k = (char *)deskey;
77         for (i = 0; i < 8; i++) {
78                 sdiv(a, base, a, &r);
79                 *k++ = r;
80         }
81 	mfree(z);
82         mfree(a);
83 }
84 
85 /*
86  * get common key from my secret key and his public key
87  */
88 void common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
89 {
90         MINT *public;
91         MINT *secret;
92         MINT *common;
93 	MINT *modulus = xtom(HEXMODULUS);
94 
95         public = xtom(xpublic);
96         secret = xtom(xsecret);
97         common = itom(0);
98         pow(public, secret, modulus, common);
99         extractdeskey(common, deskey);
100         extractideakey(common, ideakey);
101 #if DES_OSTHOLM
102 	des_fixup_key_parity(deskey);
103 #else
104 	des_set_odd_parity(deskey);
105 #endif
106         mfree(common);
107         mfree(secret);
108         mfree(public);
109 	mfree(modulus);
110 }
111 
112 
113 /*
114  * Generate a seed
115  */
116 void getseed(seed, seedsize)
117         char *seed;
118         int seedsize;
119 {
120 #if 0
121         int i,f;
122         int rseed;
123         struct timeval tv;
124 	long devrand;
125 
126         (void)gettimeofday(&tv, (struct timezone *)NULL);
127         rseed = tv.tv_sec + tv.tv_usec;
128 /* XXX What the hell is this?! */
129         for (i = 0; i < 8; i++) {
130                 rseed ^= (rseed << 8);
131         }
132 
133 	f=open("/dev/random",O_NONBLOCK|O_RDONLY);
134 	if (f>=0)
135 	{
136 		read(f,&devrand,sizeof(devrand));
137 		close(f);
138 	}
139         srand48((long)rseed^devrand);
140 
141         for (i = 0; i < seedsize; i++) {
142                 seed[i] = (lrand48() & 0xff);
143         }
144 #else
145 	int i;
146 
147 	srandomdev();
148 	for (i = 0; i < seedsize; i++) {
149 		seed[i] = random() & 0xff;
150 	}
151 #endif
152 }
153 
154 
155 /*
156  * Generate a random public/secret key pair
157  */
158 void genkeys(public, secret)
159         char *public;
160         char *secret;
161 {
162         int i;
163 
164 #       define BASEBITS (8*sizeof(short) - 1)
165 #       define BASE (1 << BASEBITS)
166 
167         MINT *pk = itom(0);
168         MINT *sk = itom(0);
169         MINT *tmp;
170         MINT *base = itom(BASE);
171         MINT *root = itom(PROOT);
172         MINT *modulus = xtom(HEXMODULUS);
173         short r;
174         unsigned short seed[KEYSIZE/BASEBITS + 1];
175         char *xkey;
176 
177         getseed((char *)seed, sizeof(seed));
178         for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
179                 r = seed[i] % BASE;
180                 tmp = itom(r);
181                 mult(sk, base, sk);
182                 madd(sk, tmp, sk);
183                 mfree(tmp);
184         }
185         tmp = itom(0);
186         mdiv(sk, modulus, tmp, sk);
187         mfree(tmp);
188         pow(root, sk, modulus, pk);
189         xkey = mtox(sk);
190         adjust(secret, xkey);
191         xkey = mtox(pk);
192         adjust(public, xkey);
193         mfree(sk);
194         mfree(base);
195         mfree(pk);
196         mfree(root);
197         mfree(modulus);
198 }
199 
200 /*
201  * Adjust the input key so that it is 0-filled on the left
202  */
203 adjust(keyout, keyin)
204         char keyout[HEXKEYBYTES+1];
205         char *keyin;
206 {
207         char *p;
208         char *s;
209 
210         for (p = keyin; *p; p++)
211                 ;
212         for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
213                 *s = *p;
214         }
215         while (s >= keyout) {
216                 *s-- = '0';
217         }
218 }
219 
220 static char hextab[17] = "0123456789ABCDEF";
221 
222 /* given a DES key, cbc encrypt and translate input to terminated hex */
223 void pk_encode(in, out, key)
224 char *in,*out;
225 DesData *key;
226 {
227 	char buf[256];
228 	DesData i;
229 	des_key_schedule k;
230 	int l,op,deslen;
231 
232 	memset(&i,0,sizeof(i));
233 	memset(buf,0,sizeof(buf));
234 	deslen = ((strlen(in) + 7)/8)*8;
235 	des_key_sched(key, k);
236 	des_cbc_encrypt(in,buf,deslen, k,&i,DES_ENCRYPT);
237 	for (l=0,op=0;l<deslen;l++) {
238 		out[op++] = hextab[(buf[l] & 0xf0) >> 4];
239 		out[op++] = hextab[(buf[l] & 0x0f)];
240 	}
241 	out[op] = '\0';
242 }
243 
244 /* given a DES key, translate input from hex and decrypt */
245 void pk_decode(in, out, key)
246 char *in,*out;
247 DesData *key;
248 {
249 	char buf[256];
250 	DesData i;
251 	des_key_schedule k;
252 	int l,n1,n2,op;
253 
254 	memset(&i,0,sizeof(i));
255 	memset(buf,0,sizeof(buf));
256 	for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
257 		if(in[op] == '0' && in[op+1] == '0') {
258 			buf[l] = '\0';
259 			break;
260 		}
261 		if (in[op] > '9')
262 			n1 = in[op] - 'A' + 10;
263 		else
264 			n1 = in[op] - '0';
265 		if (in[op+1] > '9')
266 			n2 = in[op+1] - 'A' + 10;
267 		else
268 			n2 = in[op+1] - '0';
269 		buf[l] = n1*16 +n2;
270 	}
271 	des_key_sched(key, k);
272 	des_cbc_encrypt(buf,out,strlen(in)/2, k,&i,DES_DECRYPT);
273 	out[strlen(in)/2] = '\0';
274 }
275