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