Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / telnet / libtelnet / pk.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      Dave Safford.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  * 
29  */
30
31 #include <sys/cdefs.h>
32
33 __FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/pk.c,v 1.2.2.4 2002/08/24 07:28:35 nsayer Exp $");
34
35 /* public key routines */
36 /* functions:
37         genkeys(char *public, char *secret)
38         common_key(char *secret, char *public, desData *deskey)
39         pk_encode(char *in, *out, DesData *deskey);
40         pk_decode(char *in, *out, DesData *deskey);
41       where
42         char public[HEXKEYBYTES + 1];
43         char secret[HEXKEYBYTES + 1];
44  */
45
46 #include <sys/time.h>
47 #include <openssl/des.h>
48 #include <fcntl.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include "mp.h"
54 #include "pk.h"
55  
56 static void adjust(char keyout[HEXKEYBYTES+1], char *keyin);
57
58 /*
59  * Choose top 128 bits of the common key to use as our idea key.
60  */
61 static void
62 extractideakey(MINT *ck, IdeaData *ideakey)
63 {
64         MINT *a;
65         MINT *z;
66         short r;
67         int i;
68         short base = (1 << 8);
69         char *k;
70
71         z = itom(0);
72         a = itom(0);
73         madd(ck, z, a);
74         for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
75                 sdiv(a, base, a, &r);
76         }
77         k = (char *)ideakey;
78         for (i = 0; i < 16; i++) {
79                 sdiv(a, base, a, &r);
80                 *k++ = r;
81         }
82         mfree(z);
83         mfree(a);
84 }
85
86 /*
87  * Choose middle 64 bits of the common key to use as our des key, possibly
88  * overwriting the lower order bits by setting parity. 
89  */
90 static void
91 extractdeskey(MINT *ck, DesData *deskey)
92 {
93         MINT *a;
94         MINT *z;
95         short r;
96         int i;
97         short base = (1 << 8);
98         char *k;
99
100         z = itom(0);
101         a = itom(0);
102         madd(ck, z, a);
103         for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
104                 sdiv(a, base, a, &r);
105         }
106         k = (char *)deskey;
107         for (i = 0; i < 8; i++) {
108                 sdiv(a, base, a, &r);
109                 *k++ = r;
110         }
111         mfree(z);
112         mfree(a);
113 }
114
115 /*
116  * get common key from my secret key and his public key
117  */
118 void
119 common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
120 {
121         MINT *public;
122         MINT *secret;
123         MINT *common;
124         MINT *modulus = xtom(HEXMODULUS);
125
126         public = xtom(xpublic);
127         secret = xtom(xsecret);
128         common = itom(0);
129         pow(public, secret, modulus, common);
130         extractdeskey(common, deskey);
131         extractideakey(common, ideakey);
132         des_set_odd_parity(deskey);
133         mfree(common);
134         mfree(secret);
135         mfree(public);
136         mfree(modulus);
137 }
138
139 /*
140  * Generate a seed
141  */
142 static void
143 getseed(char *seed, int seedsize)
144 {
145         int i;
146
147         srandomdev();
148         for (i = 0; i < seedsize; i++) {
149                 seed[i] = random() & 0xff;
150         }
151 }
152
153 /*
154  * Generate a random public/secret key pair
155  */
156 void
157 genkeys(char *public, char *secret)
158 {
159         size_t i;
160  
161 #       define BASEBITS (8*sizeof(short) - 1)
162 #       define BASE (1 << BASEBITS)
163  
164         MINT *pk = itom(0);
165         MINT *sk = itom(0);
166         MINT *tmp;
167         MINT *base = itom(BASE);
168         MINT *root = itom(PROOT);
169         MINT *modulus = xtom(HEXMODULUS);
170         short r;
171         unsigned short seed[KEYSIZE/BASEBITS + 1];
172         char *xkey;
173
174         getseed((char *)seed, sizeof(seed));    
175         for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
176                 r = seed[i] % BASE;
177                 tmp = itom(r);
178                 mult(sk, base, sk);
179                 madd(sk, tmp, sk);
180                 mfree(tmp);  
181         }
182         tmp = itom(0);
183         mdiv(sk, modulus, tmp, sk);
184         mfree(tmp);
185         pow(root, sk, modulus, pk); 
186         xkey = mtox(sk);   
187         adjust(secret, xkey);
188         xkey = mtox(pk);
189         adjust(public, xkey);
190         mfree(sk);
191         mfree(base);
192         mfree(pk);
193         mfree(root);
194         mfree(modulus);
195
196
197 /*
198  * Adjust the input key so that it is 0-filled on the left
199  */
200 static void
201 adjust(char keyout[HEXKEYBYTES+1], char *keyin)
202 {
203         char *p;
204         char *s;
205
206         for (p = keyin; *p; p++) 
207                 ;
208         for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
209                 *s = *p;
210         }
211         while (s >= keyout) {
212                 *s-- = '0';
213         }
214 }
215
216 static char hextab[17] = "0123456789ABCDEF";
217
218 /* given a DES key, cbc encrypt and translate input to terminated hex */
219 void
220 pk_encode(char *in, char *out, DesData *key)
221 {
222         char buf[256];
223         DesData i;
224         des_key_schedule k;
225         int l,op,deslen;
226
227         memset(&i,0,sizeof(i));
228         memset(buf,0,sizeof(buf));
229         deslen = ((strlen(in) + 7)/8)*8;
230         des_key_sched(key, k);
231         des_cbc_encrypt(in,buf,deslen, k,&i,DES_ENCRYPT);
232         for (l=0,op=0;l<deslen;l++) {
233                 out[op++] = hextab[(buf[l] & 0xf0) >> 4];
234                 out[op++] = hextab[(buf[l] & 0x0f)];
235         }
236         out[op] = '\0';
237 }
238
239 /* given a DES key, translate input from hex and decrypt */
240 void
241 pk_decode(char *in, char *out, DesData *key)
242 {
243         char buf[256];
244         DesData i;
245         des_key_schedule k;
246         int n1,n2,op;
247         size_t l;
248
249         memset(&i,0,sizeof(i));
250         memset(buf,0,sizeof(buf));
251         for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
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(buf,out,strlen(in)/2, k,&i,DES_DECRYPT);
264         out[strlen(in)/2] = '\0';
265 }