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