xref: /freebsd/contrib/telnet/libtelnet/pk.c (revision cb166ce422ac2bc81f42c2a2e2cd68625c11478d)
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         int i,f;
121         int rseed;
122         struct timeval tv;
123 	long devrand;
124 
125         (void)gettimeofday(&tv, (struct timezone *)NULL);
126         rseed = tv.tv_sec + tv.tv_usec;
127 /* XXX What the hell is this?! */
128         for (i = 0; i < 8; i++) {
129                 rseed ^= (rseed << 8);
130         }
131 
132 	f=open("/dev/random",O_NONBLOCK|O_RDONLY);
133 	if (f>=0)
134 	{
135 		read(f,&devrand,sizeof(devrand));
136 		close(f);
137 	}
138         srand48((long)rseed^devrand);
139 
140         for (i = 0; i < seedsize; i++) {
141                 seed[i] = (lrand48() & 0xff);
142         }
143 }
144 
145 
146 /*
147  * Generate a random public/secret key pair
148  */
149 void genkeys(public, secret)
150         char *public;
151         char *secret;
152 {
153         int i;
154 
155 #       define BASEBITS (8*sizeof(short) - 1)
156 #       define BASE (1 << BASEBITS)
157 
158         MINT *pk = itom(0);
159         MINT *sk = itom(0);
160         MINT *tmp;
161         MINT *base = itom(BASE);
162         MINT *root = itom(PROOT);
163         MINT *modulus = xtom(HEXMODULUS);
164         short r;
165         unsigned short seed[KEYSIZE/BASEBITS + 1];
166         char *xkey;
167 
168         getseed((char *)seed, sizeof(seed));
169         for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
170                 r = seed[i] % BASE;
171                 tmp = itom(r);
172                 mult(sk, base, sk);
173                 madd(sk, tmp, sk);
174                 mfree(tmp);
175         }
176         tmp = itom(0);
177         mdiv(sk, modulus, tmp, sk);
178         mfree(tmp);
179         pow(root, sk, modulus, pk);
180         xkey = mtox(sk);
181         adjust(secret, xkey);
182         xkey = mtox(pk);
183         adjust(public, xkey);
184         mfree(sk);
185         mfree(base);
186         mfree(pk);
187         mfree(root);
188         mfree(modulus);
189 }
190 
191 /*
192  * Adjust the input key so that it is 0-filled on the left
193  */
194 adjust(keyout, keyin)
195         char keyout[HEXKEYBYTES+1];
196         char *keyin;
197 {
198         char *p;
199         char *s;
200 
201         for (p = keyin; *p; p++)
202                 ;
203         for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
204                 *s = *p;
205         }
206         while (s >= keyout) {
207                 *s-- = '0';
208         }
209 }
210 
211 static char hextab[17] = "0123456789ABCDEF";
212 
213 /* given a DES key, cbc encrypt and translate input to terminated hex */
214 void pk_encode(in, out, key)
215 char *in,*out;
216 DesData *key;
217 {
218 	char buf[256];
219 	DesData i;
220 	des_key_schedule k;
221 	int l,op,deslen;
222 
223 	memset(&i,0,sizeof(i));
224 	memset(buf,0,sizeof(buf));
225 	deslen = ((strlen(in) + 7)/8)*8;
226 	des_key_sched(key, k);
227 	des_cbc_encrypt((des_cblock *)in,(des_cblock *)buf,deslen,
228 		k,&i,DES_ENCRYPT);
229 	for (l=0,op=0;l<deslen;l++) {
230 		out[op++] = hextab[(buf[l] & 0xf0) >> 4];
231 		out[op++] = hextab[(buf[l] & 0x0f)];
232 	}
233 	out[op] = '\0';
234 }
235 
236 /* given a DES key, translate input from hex and decrypt */
237 void pk_decode(in, out, key)
238 char *in,*out;
239 DesData *key;
240 {
241 	char buf[256];
242 	DesData i;
243 	des_key_schedule k;
244 	int l,n1,n2,op;
245 
246 	memset(&i,0,sizeof(i));
247 	memset(buf,0,sizeof(buf));
248 	for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
249 		if(in[op] == '0' && in[op+1] == '0') {
250 			buf[l] = '\0';
251 			break;
252 		}
253 		if (in[op] > '9')
254 			n1 = in[op] - 'A' + 10;
255 		else
256 			n1 = in[op] - '0';
257 		if (in[op+1] > '9')
258 			n2 = in[op+1] - 'A' + 10;
259 		else
260 			n2 = in[op+1] - '0';
261 		buf[l] = n1*16 +n2;
262 	}
263 	des_key_sched(key, k);
264 	des_cbc_encrypt((des_cblock *)buf,(des_cblock *)out,strlen(in)/2,
265 		k,&i,DES_DECRYPT);
266 	out[strlen(in)/2] = '\0';
267 }
268