xref: /dflybsd-src/lib/libtelnet/pk.c (revision ed183f8c2f9bb14cbccb8377f3cdd29e0971d8a0)
1068e7061SPeter Avalos /*-
2068e7061SPeter Avalos  * Copyright (c) 1991, 1993
3068e7061SPeter Avalos  *      Dave Safford.  All rights reserved.
4068e7061SPeter Avalos  *
5068e7061SPeter Avalos  * Redistribution and use in source and binary forms, with or without
6068e7061SPeter Avalos  * modification, are permitted provided that the following conditions
7068e7061SPeter Avalos  * are met:
8068e7061SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
9068e7061SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
10068e7061SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
11068e7061SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
12068e7061SPeter Avalos  *    documentation and/or other materials provided with the distribution.
13068e7061SPeter Avalos  * 3. Neither the name of the University nor the names of its contributors
14068e7061SPeter Avalos  *    may be used to endorse or promote products derived from this software
15068e7061SPeter Avalos  *    without specific prior written permission.
16068e7061SPeter Avalos  *
17068e7061SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18068e7061SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19068e7061SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20068e7061SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21068e7061SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22068e7061SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23068e7061SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24068e7061SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25068e7061SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26068e7061SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27068e7061SPeter Avalos  * SUCH DAMAGE.
28068e7061SPeter Avalos  *
29068e7061SPeter Avalos  *
30068e7061SPeter Avalos  * $FreeBSD: src/crypto/telnet/libtelnet/pk.c,v 1.2.2.4 2002/08/24 07:28:35 nsayer Exp $
31068e7061SPeter Avalos  */
32068e7061SPeter Avalos 
33068e7061SPeter Avalos /* public key routines */
34068e7061SPeter Avalos /* functions:
35068e7061SPeter Avalos 	genkeys(char *public, char *secret)
36068e7061SPeter Avalos 	common_key(char *secret, char *public, desData *deskey)
37068e7061SPeter Avalos         pk_encode(char *in, *out, DesData *deskey);
38068e7061SPeter Avalos         pk_decode(char *in, *out, DesData *deskey);
39068e7061SPeter Avalos       where
40068e7061SPeter Avalos 	char public[HEXKEYBYTES + 1];
41068e7061SPeter Avalos 	char secret[HEXKEYBYTES + 1];
42068e7061SPeter Avalos  */
43068e7061SPeter Avalos 
44*ed183f8cSSascha Wildner #include <sys/param.h>
45068e7061SPeter Avalos #include <sys/time.h>
46068e7061SPeter Avalos #include <err.h>
47068e7061SPeter Avalos #include <fcntl.h>
48068e7061SPeter Avalos #include <stdio.h>
49068e7061SPeter Avalos #include <stdlib.h>
50068e7061SPeter Avalos #include <string.h>
51068e7061SPeter Avalos 
52068e7061SPeter Avalos #include <openssl/bn.h>
53068e7061SPeter Avalos #include <openssl/crypto.h>
54068e7061SPeter Avalos #include <openssl/des.h>
55068e7061SPeter Avalos #include <openssl/err.h>
56068e7061SPeter Avalos 
57068e7061SPeter Avalos #include "pk.h"
58068e7061SPeter Avalos 
59068e7061SPeter Avalos static void adjust(char keyout[HEXKEYBYTES+1], char *keyin);
60068e7061SPeter Avalos 
61068e7061SPeter Avalos /*
62068e7061SPeter Avalos  * Choose top 128 bits of the common key to use as our idea key.
63068e7061SPeter Avalos  */
64068e7061SPeter Avalos static void
extractideakey(BIGNUM * ck,IdeaData * ideakey)65068e7061SPeter Avalos extractideakey(BIGNUM *ck, IdeaData *ideakey)
66068e7061SPeter Avalos {
67068e7061SPeter Avalos         BIGNUM *a, *z;
68068e7061SPeter Avalos         int i;
69068e7061SPeter Avalos         BN_ULONG r, base = (1 << 8);
70068e7061SPeter Avalos         char *k;
71068e7061SPeter Avalos 
72068e7061SPeter Avalos 	if ((z = BN_new()) == NULL)
73068e7061SPeter Avalos 		errx(1, "could not create BIGNUM");
74068e7061SPeter Avalos 	BN_zero(z);
75068e7061SPeter Avalos 	if ((a = BN_new()) == NULL)
76068e7061SPeter Avalos 		errx(1, "could not create BIGNUM");
77068e7061SPeter Avalos 	BN_zero(a);
78068e7061SPeter Avalos 	BN_add(a, ck, z);
79068e7061SPeter Avalos         for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
80068e7061SPeter Avalos 		r = BN_div_word(a, base);
81068e7061SPeter Avalos         }
82068e7061SPeter Avalos         k = (char *)ideakey;
83068e7061SPeter Avalos         for (i = 0; i < 16; i++) {
84068e7061SPeter Avalos                 r = BN_div_word(a, base);
85068e7061SPeter Avalos                 *k++ = r;
86068e7061SPeter Avalos         }
87068e7061SPeter Avalos 	BN_free(z);
88068e7061SPeter Avalos 	BN_free(a);
89068e7061SPeter Avalos }
90068e7061SPeter Avalos 
91068e7061SPeter Avalos /*
92068e7061SPeter Avalos  * Choose middle 64 bits of the common key to use as our des key, possibly
93068e7061SPeter Avalos  * overwriting the lower order bits by setting parity.
94068e7061SPeter Avalos  */
95068e7061SPeter Avalos static void
extractdeskey(BIGNUM * ck,DesData * deskey)96068e7061SPeter Avalos extractdeskey(BIGNUM *ck, DesData *deskey)
97068e7061SPeter Avalos {
98068e7061SPeter Avalos         BIGNUM *a, *z;
99068e7061SPeter Avalos         int i;
100068e7061SPeter Avalos         BN_ULONG r, base = (1 << 8);
101068e7061SPeter Avalos         char *k;
102068e7061SPeter Avalos 
103068e7061SPeter Avalos 	if ((z = BN_new()) == NULL)
104068e7061SPeter Avalos 		errx(1, "could not create BIGNUM");
105068e7061SPeter Avalos 	BN_zero(z);
106068e7061SPeter Avalos 	if ((a = BN_new()) == NULL)
107068e7061SPeter Avalos 		errx(1, "could not create BIGNUM");
108068e7061SPeter Avalos 	BN_zero(a);
109068e7061SPeter Avalos 	BN_add(a, ck, z);
110068e7061SPeter Avalos         for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
111068e7061SPeter Avalos 		r = BN_div_word(a, base);
112068e7061SPeter Avalos         }
113068e7061SPeter Avalos         k = (char *)deskey;
114068e7061SPeter Avalos         for (i = 0; i < 8; i++) {
115068e7061SPeter Avalos 		r = BN_div_word(a, base);
116068e7061SPeter Avalos                 *k++ = r;
117068e7061SPeter Avalos         }
118068e7061SPeter Avalos 	BN_free(z);
119068e7061SPeter Avalos 	BN_free(a);
120068e7061SPeter Avalos }
121068e7061SPeter Avalos 
122068e7061SPeter Avalos /*
123068e7061SPeter Avalos  * get common key from my secret key and his public key
124068e7061SPeter Avalos  */
125068e7061SPeter Avalos void
common_key(char * xsecret,char * xpublic,IdeaData * ideakey,DesData * deskey)126068e7061SPeter Avalos common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
127068e7061SPeter Avalos {
128068e7061SPeter Avalos         BIGNUM *public, *secret, *common, *modulus;
129068e7061SPeter Avalos 	BN_CTX *ctx;
130068e7061SPeter Avalos 
131068e7061SPeter Avalos 	if ((ctx = BN_CTX_new()) == NULL)
132068e7061SPeter Avalos 		errx(1, "could not create BN_CTX");
133068e7061SPeter Avalos 	modulus = NULL;
13417bc2c97SSascha Wildner 	if (BN_hex2bn(&modulus, HEXMODULUS) == 0)
135068e7061SPeter Avalos 		errx(1, "could not convert modulus");
136068e7061SPeter Avalos 	public = NULL;
13717bc2c97SSascha Wildner 	if (BN_hex2bn(&public, xpublic) == 0)
138068e7061SPeter Avalos 		errx(1, "could not convert public");
139068e7061SPeter Avalos 	secret = NULL;
14017bc2c97SSascha Wildner 	if (BN_hex2bn(&secret, xsecret) == 0)
141068e7061SPeter Avalos 		errx(1, "could not convert secret");
142068e7061SPeter Avalos 
143068e7061SPeter Avalos 	if ((common = BN_new()) == NULL)
144068e7061SPeter Avalos 		errx(1, "could not create BIGNUM");
145068e7061SPeter Avalos 	BN_zero(common);
146068e7061SPeter Avalos 	BN_mod_exp(common, public, secret, modulus, ctx);
147068e7061SPeter Avalos         extractdeskey(common, deskey);
148068e7061SPeter Avalos         extractideakey(common, ideakey);
14982ae7067SJohn Marino 	DES_set_odd_parity(deskey);
150068e7061SPeter Avalos 	BN_free(common);
151068e7061SPeter Avalos 	BN_free(secret);
152068e7061SPeter Avalos 	BN_free(public);
153068e7061SPeter Avalos 	BN_free(modulus);
154068e7061SPeter Avalos 	BN_CTX_free(ctx);
155068e7061SPeter Avalos }
156068e7061SPeter Avalos 
157068e7061SPeter Avalos /*
158068e7061SPeter Avalos  * Generate a seed
159068e7061SPeter Avalos  */
160068e7061SPeter Avalos static void
getseed(char * seed,int seedsize)161068e7061SPeter Avalos getseed(char *seed, int seedsize)
162068e7061SPeter Avalos {
163068e7061SPeter Avalos 	int i;
164068e7061SPeter Avalos 
165068e7061SPeter Avalos 	for (i = 0; i < seedsize; i++) {
166068e7061SPeter Avalos 		seed[i] = arc4random() & 0xff;
167068e7061SPeter Avalos 	}
168068e7061SPeter Avalos }
169068e7061SPeter Avalos 
170068e7061SPeter Avalos static BIGNUM *
itobn(long i)171068e7061SPeter Avalos itobn(long i)
172068e7061SPeter Avalos {
173678e8cc6SSascha Wildner 	BIGNUM *n = NULL;
174068e7061SPeter Avalos 
175068e7061SPeter Avalos 	if ((n = BN_new()) == NULL)
176068e7061SPeter Avalos 		errx(1, "could not create BIGNUM: %s",
177068e7061SPeter Avalos 		     ERR_error_string(ERR_get_error(), 0));
178068e7061SPeter Avalos 	BN_init(n);
179068e7061SPeter Avalos 	if (i > 0)
180068e7061SPeter Avalos 		BN_add_word(n, (u_long)i);
181068e7061SPeter Avalos 	else
182068e7061SPeter Avalos 		BN_sub_word(n, (u_long)(-i));
183068e7061SPeter Avalos 	return(n);
184068e7061SPeter Avalos }
185068e7061SPeter Avalos 
186068e7061SPeter Avalos /*
187068e7061SPeter Avalos  * Generate a random public/secret key pair
188068e7061SPeter Avalos  */
189068e7061SPeter Avalos void
genkeys(char * public,char * secret)190068e7061SPeter Avalos genkeys(char *public, char *secret)
191068e7061SPeter Avalos {
192068e7061SPeter Avalos #define	BASEBITS (8*sizeof (short) - 1)
193068e7061SPeter Avalos #define	BASE (short)(1 << BASEBITS)
194068e7061SPeter Avalos 
195068e7061SPeter Avalos 	unsigned int i;
196068e7061SPeter Avalos 	short r;
197068e7061SPeter Avalos 	unsigned short seed[KEYSIZE/BASEBITS + 1];
198068e7061SPeter Avalos 	char *xkey;
199068e7061SPeter Avalos 
200068e7061SPeter Avalos 	BN_CTX *ctx;
201068e7061SPeter Avalos 	BIGNUM *pk, *sk, *tmp, *base, *root, *modulus;
202068e7061SPeter Avalos 
203068e7061SPeter Avalos 	pk = itobn(0);
204068e7061SPeter Avalos 	sk = itobn(0);
205068e7061SPeter Avalos 	tmp = itobn(0);
206068e7061SPeter Avalos 	base = itobn(BASE);
207068e7061SPeter Avalos 	root = itobn(PROOT);
208068e7061SPeter Avalos 	modulus = NULL;
20917bc2c97SSascha Wildner 	if (BN_hex2bn(&modulus, HEXMODULUS) == 0)
210068e7061SPeter Avalos 		errx(1, "could not convert modulus to BIGNUM: %s",
211068e7061SPeter Avalos 		     ERR_error_string(ERR_get_error(), 0));
212068e7061SPeter Avalos 
213068e7061SPeter Avalos 	if ((ctx = BN_CTX_new()) == NULL)
214068e7061SPeter Avalos 		errx(1, "could not create BN_CTX: %s",
215068e7061SPeter Avalos 		     ERR_error_string(ERR_get_error(), 0));
216068e7061SPeter Avalos 
217068e7061SPeter Avalos 	getseed((char *)seed, sizeof (seed));
218068e7061SPeter Avalos 	for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
219068e7061SPeter Avalos 		r = seed[i] % BASE;
220068e7061SPeter Avalos 		BN_zero(tmp);
221068e7061SPeter Avalos 		BN_add_word(tmp, r);
222068e7061SPeter Avalos 		BN_mul(sk, base, sk, ctx);
223068e7061SPeter Avalos 		BN_add(sk, tmp, sk);
224068e7061SPeter Avalos 	}
225068e7061SPeter Avalos 	BN_zero(tmp);
226068e7061SPeter Avalos 	BN_div(tmp, sk, sk, modulus, ctx);
227068e7061SPeter Avalos 	BN_mod_exp(pk, root, sk, modulus, ctx);
228068e7061SPeter Avalos 
229068e7061SPeter Avalos 	if ((xkey = BN_bn2hex(sk)) == NULL)
230068e7061SPeter Avalos 		errx(1, "could convert sk to hex: %s",
231068e7061SPeter Avalos 		     ERR_error_string(ERR_get_error(), 0));
232068e7061SPeter Avalos 	adjust(secret, xkey);
233068e7061SPeter Avalos 	OPENSSL_free(xkey);
234068e7061SPeter Avalos 
235068e7061SPeter Avalos 	if ((xkey = BN_bn2hex(pk)) == NULL)
236068e7061SPeter Avalos 		errx(1, "could convert pk to hex: %s",
237068e7061SPeter Avalos 		     ERR_error_string(ERR_get_error(), 0));
238068e7061SPeter Avalos 	adjust(public, xkey);
239068e7061SPeter Avalos 	OPENSSL_free(xkey);
240068e7061SPeter Avalos 
241068e7061SPeter Avalos 	BN_free(base);
242068e7061SPeter Avalos 	BN_free(modulus);
243068e7061SPeter Avalos 	BN_free(pk);
244068e7061SPeter Avalos 	BN_free(sk);
245068e7061SPeter Avalos 	BN_free(root);
246068e7061SPeter Avalos 	BN_free(tmp);
247068e7061SPeter Avalos }
248068e7061SPeter Avalos 
249068e7061SPeter Avalos /*
250068e7061SPeter Avalos  * Adjust the input key so that it is 0-filled on the left
251068e7061SPeter Avalos  */
252068e7061SPeter Avalos static void
adjust(char keyout[HEXKEYBYTES+1],char * keyin)253068e7061SPeter Avalos adjust(char keyout[HEXKEYBYTES+1], char *keyin)
254068e7061SPeter Avalos {
255068e7061SPeter Avalos         char *p;
256068e7061SPeter Avalos         char *s;
257068e7061SPeter Avalos 
258068e7061SPeter Avalos         for (p = keyin; *p; p++)
259068e7061SPeter Avalos                 ;
260068e7061SPeter Avalos         for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
261068e7061SPeter Avalos                 *s = *p;
262068e7061SPeter Avalos         }
263068e7061SPeter Avalos         while (s >= keyout) {
264068e7061SPeter Avalos                 *s-- = '0';
265068e7061SPeter Avalos         }
266068e7061SPeter Avalos }
267068e7061SPeter Avalos 
268068e7061SPeter Avalos static char hextab[17] = "0123456789ABCDEF";
269068e7061SPeter Avalos 
270068e7061SPeter Avalos /* given a DES key, cbc encrypt and translate input to terminated hex */
271068e7061SPeter Avalos void
pk_encode(char * in,char * out,DesData * key)272068e7061SPeter Avalos pk_encode(char *in, char *out, DesData *key)
273068e7061SPeter Avalos {
274068e7061SPeter Avalos 	char buf[256];
275068e7061SPeter Avalos 	DesData i;
27682ae7067SJohn Marino 	DES_key_schedule k;
277068e7061SPeter Avalos 	int l,op,deslen;
278068e7061SPeter Avalos 
279068e7061SPeter Avalos 	memset(&i,0,sizeof(i));
280068e7061SPeter Avalos 	memset(buf,0,sizeof(buf));
281*ed183f8cSSascha Wildner 	deslen = rounddown(strlen(in) + 7, 8);
28282ae7067SJohn Marino 	DES_key_sched(key, &k);
28382ae7067SJohn Marino 	DES_cbc_encrypt(in,buf,deslen, &k,&i,DES_ENCRYPT);
284068e7061SPeter Avalos 	for (l=0,op=0;l<deslen;l++) {
285068e7061SPeter Avalos 		out[op++] = hextab[(buf[l] & 0xf0) >> 4];
286068e7061SPeter Avalos 		out[op++] = hextab[(buf[l] & 0x0f)];
287068e7061SPeter Avalos 	}
288068e7061SPeter Avalos 	out[op] = '\0';
289068e7061SPeter Avalos }
290068e7061SPeter Avalos 
291068e7061SPeter Avalos /* given a DES key, translate input from hex and decrypt */
292068e7061SPeter Avalos void
pk_decode(char * in,char * out,DesData * key)293068e7061SPeter Avalos pk_decode(char *in, char *out, DesData *key)
294068e7061SPeter Avalos {
295068e7061SPeter Avalos 	char buf[256];
296068e7061SPeter Avalos 	DesData i;
29782ae7067SJohn Marino 	DES_key_schedule k;
298068e7061SPeter Avalos 	int n1,n2,op;
299068e7061SPeter Avalos 	size_t l;
300068e7061SPeter Avalos 
301068e7061SPeter Avalos 	memset(&i,0,sizeof(i));
302068e7061SPeter Avalos 	memset(buf,0,sizeof(buf));
303068e7061SPeter Avalos 	for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
304068e7061SPeter Avalos 		if (in[op] > '9')
305068e7061SPeter Avalos 			n1 = in[op] - 'A' + 10;
306068e7061SPeter Avalos 		else
307068e7061SPeter Avalos 			n1 = in[op] - '0';
308068e7061SPeter Avalos 		if (in[op+1] > '9')
309068e7061SPeter Avalos 			n2 = in[op+1] - 'A' + 10;
310068e7061SPeter Avalos 		else
311068e7061SPeter Avalos 			n2 = in[op+1] - '0';
312068e7061SPeter Avalos 		buf[l] = n1*16 +n2;
313068e7061SPeter Avalos 	}
31482ae7067SJohn Marino 	DES_key_sched(key, &k);
31582ae7067SJohn Marino 	DES_cbc_encrypt(buf,out,strlen(in)/2, &k,&i,DES_DECRYPT);
316068e7061SPeter Avalos 	out[strlen(in)/2] = '\0';
317068e7061SPeter Avalos }
318