pk.c revision 84305
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 <sys/cdefs.h>
13__FBSDID("$FreeBSD: head/contrib/telnet/libtelnet/pk.c 84305 2001-10-01 16:04:55Z markm $");
14
15#include <sys/time.h>
16#include <openssl/des.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <string.h>
20#include "mp.h"
21#include "pk.h"
22#if defined(SOLARIS2) || defined(LINUX) || defined(__FreeBSD__)
23#include <stdlib.h>
24#endif
25
26static void adjust(char keyout[HEXKEYBYTES+1], char *keyin);
27
28/*
29 * Choose top 128 bits of the common key to use as our idea key.
30 */
31static void
32extractideakey(MINT *ck, IdeaData *ideakey)
33{
34        MINT *a;
35        MINT *z;
36        short r;
37        int i;
38        short base = (1 << 8);
39        char *k;
40
41        z = itom(0);
42        a = itom(0);
43        madd(ck, z, a);
44        for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
45                sdiv(a, base, a, &r);
46        }
47        k = (char *)ideakey;
48        for (i = 0; i < 16; i++) {
49                sdiv(a, base, a, &r);
50                *k++ = r;
51        }
52	mfree(z);
53        mfree(a);
54}
55
56/*
57 * Choose middle 64 bits of the common key to use as our des key, possibly
58 * overwriting the lower order bits by setting parity.
59 */
60static void
61extractdeskey(MINT *ck, 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 */
88void
89common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
90{
91        MINT *public;
92        MINT *secret;
93        MINT *common;
94	MINT *modulus = xtom(HEXMODULUS);
95
96        public = xtom(xpublic);
97        secret = xtom(xsecret);
98        common = itom(0);
99        pow(public, secret, modulus, common);
100        extractdeskey(common, deskey);
101        extractideakey(common, ideakey);
102#if DES_OSTHOLM
103	des_fixup_key_parity(deskey);
104#else
105	des_set_odd_parity(deskey);
106#endif
107        mfree(common);
108        mfree(secret);
109        mfree(public);
110	mfree(modulus);
111}
112
113/*
114 * Generate a seed
115 */
116void
117getseed(char *seed, int seedsize)
118{
119	int i;
120
121	srandomdev();
122	for (i = 0; i < seedsize; i++) {
123		seed[i] = random() & 0xff;
124	}
125}
126
127/*
128 * Generate a random public/secret key pair
129 */
130void
131genkeys(char *public, char *secret)
132{
133        int i;
134
135#       define BASEBITS (8*sizeof(short) - 1)
136#       define BASE (1 << BASEBITS)
137
138        MINT *pk = itom(0);
139        MINT *sk = itom(0);
140        MINT *tmp;
141        MINT *base = itom(BASE);
142        MINT *root = itom(PROOT);
143        MINT *modulus = xtom(HEXMODULUS);
144        short r;
145        unsigned short seed[KEYSIZE/BASEBITS + 1];
146        char *xkey;
147
148        getseed((char *)seed, sizeof(seed));
149        for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
150                r = seed[i] % BASE;
151                tmp = itom(r);
152                mult(sk, base, sk);
153                madd(sk, tmp, sk);
154                mfree(tmp);
155        }
156        tmp = itom(0);
157        mdiv(sk, modulus, tmp, sk);
158        mfree(tmp);
159        pow(root, sk, modulus, pk);
160        xkey = mtox(sk);
161        adjust(secret, xkey);
162        xkey = mtox(pk);
163        adjust(public, xkey);
164        mfree(sk);
165        mfree(base);
166        mfree(pk);
167        mfree(root);
168        mfree(modulus);
169}
170
171/*
172 * Adjust the input key so that it is 0-filled on the left
173 */
174static void
175adjust(char keyout[HEXKEYBYTES+1], char *keyin)
176{
177        char *p;
178        char *s;
179
180        for (p = keyin; *p; p++)
181                ;
182        for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
183                *s = *p;
184        }
185        while (s >= keyout) {
186                *s-- = '0';
187        }
188}
189
190static char hextab[17] = "0123456789ABCDEF";
191
192/* given a DES key, cbc encrypt and translate input to terminated hex */
193void
194pk_encode(char *in, char *out, DesData *key)
195{
196	char buf[256];
197	DesData i;
198	des_key_schedule k;
199	int l,op,deslen;
200
201	memset(&i,0,sizeof(i));
202	memset(buf,0,sizeof(buf));
203	deslen = ((strlen(in) + 7)/8)*8;
204	des_key_sched(key, k);
205	des_cbc_encrypt(in,buf,deslen, k,&i,DES_ENCRYPT);
206	for (l=0,op=0;l<deslen;l++) {
207		out[op++] = hextab[(buf[l] & 0xf0) >> 4];
208		out[op++] = hextab[(buf[l] & 0x0f)];
209	}
210	out[op] = '\0';
211}
212
213/* given a DES key, translate input from hex and decrypt */
214void
215pk_decode(char *in, char *out, DesData *key)
216{
217	char buf[256];
218	DesData i;
219	des_key_schedule k;
220	int l,n1,n2,op;
221
222	memset(&i,0,sizeof(i));
223	memset(buf,0,sizeof(buf));
224	for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
225		if(in[op] == '0' && in[op+1] == '0') {
226			buf[l] = '\0';
227			break;
228		}
229		if (in[op] > '9')
230			n1 = in[op] - 'A' + 10;
231		else
232			n1 = in[op] - '0';
233		if (in[op+1] > '9')
234			n2 = in[op+1] - 'A' + 10;
235		else
236			n2 = in[op+1] - '0';
237		buf[l] = n1*16 +n2;
238	}
239	des_key_sched(key, k);
240	des_cbc_encrypt(buf,out,strlen(in)/2, k,&i,DES_DECRYPT);
241	out[strlen(in)/2] = '\0';
242}
243