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