113e3f4d6SMark Murray /*-
213e3f4d6SMark Murray  * Copyright (c) 1991, 1993
313e3f4d6SMark Murray  *	The Regents of the University of California.  All rights reserved.
413e3f4d6SMark Murray  *
513e3f4d6SMark Murray  * Redistribution and use in source and binary forms, with or without
613e3f4d6SMark Murray  * modification, are permitted provided that the following conditions
713e3f4d6SMark Murray  * are met:
813e3f4d6SMark Murray  * 1. Redistributions of source code must retain the above copyright
913e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer.
1013e3f4d6SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
1113e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer in the
1213e3f4d6SMark Murray  *    documentation and/or other materials provided with the distribution.
1313e3f4d6SMark Murray  * 3. All advertising materials mentioning features or use of this software
1413e3f4d6SMark Murray  *    must display the following acknowledgement:
1513e3f4d6SMark Murray  *	This product includes software developed by the University of
1613e3f4d6SMark Murray  *	California, Berkeley and its contributors.
1713e3f4d6SMark Murray  * 4. Neither the name of the University nor the names of its contributors
1813e3f4d6SMark Murray  *    may be used to endorse or promote products derived from this software
1913e3f4d6SMark Murray  *    without specific prior written permission.
2013e3f4d6SMark Murray  *
2113e3f4d6SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213e3f4d6SMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313e3f4d6SMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413e3f4d6SMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513e3f4d6SMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613e3f4d6SMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713e3f4d6SMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813e3f4d6SMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913e3f4d6SMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013e3f4d6SMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113e3f4d6SMark Murray  * SUCH DAMAGE.
3213e3f4d6SMark Murray  */
3313e3f4d6SMark Murray 
3413e3f4d6SMark Murray #include <config.h>
3513e3f4d6SMark Murray 
36c19800e8SDoug Rabson RCSID("$Id$");
3713e3f4d6SMark Murray 
3813e3f4d6SMark Murray #if	defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION)
3913e3f4d6SMark Murray #include <arpa/telnet.h>
4013e3f4d6SMark Murray #include <stdio.h>
4113e3f4d6SMark Murray #ifdef	__STDC__
4213e3f4d6SMark Murray #include <stdlib.h>
4313e3f4d6SMark Murray #include <string.h>
4413e3f4d6SMark Murray #endif
4513e3f4d6SMark Murray #include <roken.h>
4613e3f4d6SMark Murray #ifdef SOCKS
4713e3f4d6SMark Murray #include <socks.h>
4813e3f4d6SMark Murray #endif
4913e3f4d6SMark Murray 
5013e3f4d6SMark Murray #include "encrypt.h"
5113e3f4d6SMark Murray #include "misc-proto.h"
5213e3f4d6SMark Murray 
530cadf2f4SJacques Vidrine #include "crypto-headers.h"
5413e3f4d6SMark Murray 
5513e3f4d6SMark Murray extern int encrypt_debug_mode;
5613e3f4d6SMark Murray 
5713e3f4d6SMark Murray #define	CFB	0
5813e3f4d6SMark Murray #define	OFB	1
5913e3f4d6SMark Murray 
6013e3f4d6SMark Murray #define	NO_SEND_IV	1
6113e3f4d6SMark Murray #define	NO_RECV_IV	2
6213e3f4d6SMark Murray #define	NO_KEYID	4
6313e3f4d6SMark Murray #define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
6413e3f4d6SMark Murray #define	SUCCESS		0
6513e3f4d6SMark Murray #define	FAILED		-1
6613e3f4d6SMark Murray 
6713e3f4d6SMark Murray 
6813e3f4d6SMark Murray struct stinfo {
69c19800e8SDoug Rabson   DES_cblock	str_output;
70c19800e8SDoug Rabson   DES_cblock	str_feed;
71c19800e8SDoug Rabson   DES_cblock	str_iv;
72c19800e8SDoug Rabson   DES_cblock	str_ikey;
73c19800e8SDoug Rabson   DES_key_schedule str_sched;
7413e3f4d6SMark Murray   int		str_index;
7513e3f4d6SMark Murray   int		str_flagshift;
7613e3f4d6SMark Murray };
7713e3f4d6SMark Murray 
7813e3f4d6SMark Murray struct fb {
79c19800e8SDoug Rabson 	DES_cblock krbdes_key;
80c19800e8SDoug Rabson 	DES_key_schedule krbdes_sched;
81c19800e8SDoug Rabson 	DES_cblock temp_feed;
8213e3f4d6SMark Murray 	unsigned char fb_feed[64];
8313e3f4d6SMark Murray 	int need_start;
8413e3f4d6SMark Murray 	int state[2];
8513e3f4d6SMark Murray 	int keyid[2];
8613e3f4d6SMark Murray 	struct stinfo streams[2];
8713e3f4d6SMark Murray };
8813e3f4d6SMark Murray 
8913e3f4d6SMark Murray static struct fb fb[2];
9013e3f4d6SMark Murray 
9113e3f4d6SMark Murray struct keyidlist {
9213e3f4d6SMark Murray 	char	*keyid;
9313e3f4d6SMark Murray 	int	keyidlen;
9413e3f4d6SMark Murray 	char	*key;
9513e3f4d6SMark Murray 	int	keylen;
9613e3f4d6SMark Murray 	int	flags;
9713e3f4d6SMark Murray } keyidlist [] = {
9813e3f4d6SMark Murray 	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
9913e3f4d6SMark Murray 	{ 0, 0, 0, 0, 0 }
10013e3f4d6SMark Murray };
10113e3f4d6SMark Murray 
10213e3f4d6SMark Murray #define	KEYFLAG_MASK	03
10313e3f4d6SMark Murray 
10413e3f4d6SMark Murray #define	KEYFLAG_NOINIT	00
10513e3f4d6SMark Murray #define	KEYFLAG_INIT	01
10613e3f4d6SMark Murray #define	KEYFLAG_OK	02
10713e3f4d6SMark Murray #define	KEYFLAG_BAD	03
10813e3f4d6SMark Murray 
10913e3f4d6SMark Murray #define	KEYFLAG_SHIFT	2
11013e3f4d6SMark Murray 
11113e3f4d6SMark Murray #define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
11213e3f4d6SMark Murray 
11313e3f4d6SMark Murray #define	FB64_IV		1
11413e3f4d6SMark Murray #define	FB64_IV_OK	2
11513e3f4d6SMark Murray #define	FB64_IV_BAD	3
11613e3f4d6SMark Murray 
11713e3f4d6SMark Murray 
11813e3f4d6SMark Murray void fb64_stream_iv (DES_cblock, struct stinfo *);
119c19800e8SDoug Rabson void fb64_init (struct fb *);
12013e3f4d6SMark Murray static int fb64_start (struct fb *, int, int);
12113e3f4d6SMark Murray int fb64_is (unsigned char *, int, struct fb *);
12213e3f4d6SMark Murray int fb64_reply (unsigned char *, int, struct fb *);
12313e3f4d6SMark Murray static void fb64_session (Session_Key *, int, struct fb *);
12413e3f4d6SMark Murray void fb64_stream_key (DES_cblock, struct stinfo *);
125c19800e8SDoug Rabson int fb64_keyid (int, unsigned char *, int *, struct fb *);
12613e3f4d6SMark Murray void fb64_printsub(unsigned char *, size_t ,
1274137ff4cSJacques Vidrine 		   unsigned char *, size_t , char *);
1284137ff4cSJacques Vidrine 
cfb64_init(int server)12913e3f4d6SMark Murray void cfb64_init(int server)
13013e3f4d6SMark Murray {
13113e3f4d6SMark Murray 	fb64_init(&fb[CFB]);
13213e3f4d6SMark Murray 	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
13313e3f4d6SMark Murray 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
13413e3f4d6SMark Murray 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
13513e3f4d6SMark Murray }
13613e3f4d6SMark Murray 
13713e3f4d6SMark Murray 
ofb64_init(int server)13813e3f4d6SMark Murray void ofb64_init(int server)
13913e3f4d6SMark Murray {
14013e3f4d6SMark Murray 	fb64_init(&fb[OFB]);
14113e3f4d6SMark Murray 	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
14213e3f4d6SMark Murray 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
14313e3f4d6SMark Murray 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
14413e3f4d6SMark Murray }
14513e3f4d6SMark Murray 
fb64_init(struct fb * fbp)14613e3f4d6SMark Murray void fb64_init(struct fb *fbp)
14713e3f4d6SMark Murray {
14813e3f4d6SMark Murray 	memset(fbp,0, sizeof(*fbp));
14913e3f4d6SMark Murray 	fbp->state[0] = fbp->state[1] = FAILED;
15013e3f4d6SMark Murray 	fbp->fb_feed[0] = IAC;
15113e3f4d6SMark Murray 	fbp->fb_feed[1] = SB;
15213e3f4d6SMark Murray 	fbp->fb_feed[2] = TELOPT_ENCRYPT;
15313e3f4d6SMark Murray 	fbp->fb_feed[3] = ENCRYPT_IS;
15413e3f4d6SMark Murray }
15513e3f4d6SMark Murray 
15613e3f4d6SMark Murray /*
15713e3f4d6SMark Murray  * Returns:
15813e3f4d6SMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
15913e3f4d6SMark Murray  *	 0: Successful, initial negotiation all done.
16013e3f4d6SMark Murray  *	 1: successful, negotiation not done yet.
16113e3f4d6SMark Murray  *	 2: Not yet.  Other things (like getting the key from
16213e3f4d6SMark Murray  *	    Kerberos) have to happen before we can continue.
16313e3f4d6SMark Murray  */
cfb64_start(int dir,int server)16413e3f4d6SMark Murray int cfb64_start(int dir, int server)
16513e3f4d6SMark Murray {
16613e3f4d6SMark Murray 	return(fb64_start(&fb[CFB], dir, server));
16713e3f4d6SMark Murray }
16813e3f4d6SMark Murray 
ofb64_start(int dir,int server)16913e3f4d6SMark Murray int ofb64_start(int dir, int server)
17013e3f4d6SMark Murray {
17113e3f4d6SMark Murray 	return(fb64_start(&fb[OFB], dir, server));
17213e3f4d6SMark Murray }
17313e3f4d6SMark Murray 
fb64_start(struct fb * fbp,int dir,int server)17413e3f4d6SMark Murray static int fb64_start(struct fb *fbp, int dir, int server)
17513e3f4d6SMark Murray {
17613e3f4d6SMark Murray 	int x;
17713e3f4d6SMark Murray 	unsigned char *p;
17813e3f4d6SMark Murray 	int state;
17913e3f4d6SMark Murray 
18013e3f4d6SMark Murray 	switch (dir) {
18113e3f4d6SMark Murray 	case DIR_DECRYPT:
18213e3f4d6SMark Murray 		/*
18313e3f4d6SMark Murray 		 * This is simply a request to have the other side
18413e3f4d6SMark Murray 		 * start output (our input).  He will negotiate an
18513e3f4d6SMark Murray 		 * IV so we need not look for it.
18613e3f4d6SMark Murray 		 */
18713e3f4d6SMark Murray 		state = fbp->state[dir-1];
18813e3f4d6SMark Murray 		if (state == FAILED)
18913e3f4d6SMark Murray 			state = IN_PROGRESS;
19013e3f4d6SMark Murray 		break;
19113e3f4d6SMark Murray 
19213e3f4d6SMark Murray 	case DIR_ENCRYPT:
19313e3f4d6SMark Murray 		state = fbp->state[dir-1];
19413e3f4d6SMark Murray 		if (state == FAILED)
19513e3f4d6SMark Murray 			state = IN_PROGRESS;
19613e3f4d6SMark Murray 		else if ((state & NO_SEND_IV) == 0) {
19713e3f4d6SMark Murray 			break;
19813e3f4d6SMark Murray 		}
19913e3f4d6SMark Murray 
20013e3f4d6SMark Murray 		if (!VALIDKEY(fbp->krbdes_key)) {
20113e3f4d6SMark Murray 		        fbp->need_start = 1;
20213e3f4d6SMark Murray 			break;
20313e3f4d6SMark Murray 		}
20413e3f4d6SMark Murray 
20513e3f4d6SMark Murray 		state &= ~NO_SEND_IV;
20613e3f4d6SMark Murray 		state |= NO_RECV_IV;
20713e3f4d6SMark Murray 		if (encrypt_debug_mode)
20813e3f4d6SMark Murray 			printf("Creating new feed\r\n");
20913e3f4d6SMark Murray 		/*
21013e3f4d6SMark Murray 		 * Create a random feed and send it over.
21113e3f4d6SMark Murray 		 */
21213e3f4d6SMark Murray 		do {
21313e3f4d6SMark Murray 		    if (RAND_bytes(fbp->temp_feed,
214c19800e8SDoug Rabson 				   sizeof(*fbp->temp_feed)) != 1)
21513e3f4d6SMark Murray 			abort();
21613e3f4d6SMark Murray 		    DES_set_odd_parity(&fbp->temp_feed);
21713e3f4d6SMark Murray 		} while(DES_is_weak_key(&fbp->temp_feed));
21813e3f4d6SMark Murray 
21913e3f4d6SMark Murray 		p = fbp->fb_feed + 3;
22013e3f4d6SMark Murray 		*p++ = ENCRYPT_IS;
22113e3f4d6SMark Murray 		p++;
222c19800e8SDoug Rabson 		*p++ = FB64_IV;
223c19800e8SDoug Rabson 		for (x = 0; x < sizeof(DES_cblock); ++x) {
224c19800e8SDoug Rabson 			if ((*p++ = fbp->temp_feed[x]) == IAC)
22513e3f4d6SMark Murray 				*p++ = IAC;
226c19800e8SDoug Rabson 		}
22713e3f4d6SMark Murray 		*p++ = IAC;
228c19800e8SDoug Rabson 		*p++ = SE;
22913e3f4d6SMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
23013e3f4d6SMark Murray 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
23113e3f4d6SMark Murray 		break;
23213e3f4d6SMark Murray 	default:
233c19800e8SDoug Rabson 		return(FAILED);
23413e3f4d6SMark Murray 	}
23513e3f4d6SMark Murray 	return(fbp->state[dir-1] = state);
23613e3f4d6SMark Murray }
23713e3f4d6SMark Murray 
23813e3f4d6SMark Murray /*
23913e3f4d6SMark Murray  * Returns:
24013e3f4d6SMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
24113e3f4d6SMark Murray  *	 0: Successful, initial negotiation all done.
24213e3f4d6SMark Murray  *	 1: successful, negotiation not done yet.
24313e3f4d6SMark Murray  */
24413e3f4d6SMark Murray 
cfb64_is(unsigned char * data,int cnt)24513e3f4d6SMark Murray int cfb64_is(unsigned char *data, int cnt)
24613e3f4d6SMark Murray {
24713e3f4d6SMark Murray 	return(fb64_is(data, cnt, &fb[CFB]));
24813e3f4d6SMark Murray }
24913e3f4d6SMark Murray 
ofb64_is(unsigned char * data,int cnt)25013e3f4d6SMark Murray int ofb64_is(unsigned char *data, int cnt)
25113e3f4d6SMark Murray {
25213e3f4d6SMark Murray 	return(fb64_is(data, cnt, &fb[OFB]));
25313e3f4d6SMark Murray }
25413e3f4d6SMark Murray 
25513e3f4d6SMark Murray 
fb64_is(unsigned char * data,int cnt,struct fb * fbp)25613e3f4d6SMark Murray int fb64_is(unsigned char *data, int cnt, struct fb *fbp)
25713e3f4d6SMark Murray {
25813e3f4d6SMark Murray 	unsigned char *p;
25913e3f4d6SMark Murray 	int state = fbp->state[DIR_DECRYPT-1];
26013e3f4d6SMark Murray 
26113e3f4d6SMark Murray 	if (cnt-- < 1)
26213e3f4d6SMark Murray 		goto failure;
26313e3f4d6SMark Murray 
26413e3f4d6SMark Murray 	switch (*data++) {
26513e3f4d6SMark Murray 	case FB64_IV:
26613e3f4d6SMark Murray 		if (cnt != sizeof(DES_cblock)) {
26713e3f4d6SMark Murray 			if (encrypt_debug_mode)
26813e3f4d6SMark Murray 				printf("CFB64: initial vector failed on size\r\n");
26913e3f4d6SMark Murray 			state = FAILED;
27013e3f4d6SMark Murray 			goto failure;
27113e3f4d6SMark Murray 		}
27213e3f4d6SMark Murray 
27313e3f4d6SMark Murray 		if (encrypt_debug_mode)
27413e3f4d6SMark Murray 			printf("CFB64: initial vector received\r\n");
27513e3f4d6SMark Murray 
276c19800e8SDoug Rabson 		if (encrypt_debug_mode)
27713e3f4d6SMark Murray 			printf("Initializing Decrypt stream\r\n");
27813e3f4d6SMark Murray 
27913e3f4d6SMark Murray 		fb64_stream_iv(data, &fbp->streams[DIR_DECRYPT-1]);
28013e3f4d6SMark Murray 
28113e3f4d6SMark Murray 		p = fbp->fb_feed + 3;
28213e3f4d6SMark Murray 		*p++ = ENCRYPT_REPLY;
28313e3f4d6SMark Murray 		p++;
28413e3f4d6SMark Murray 		*p++ = FB64_IV_OK;
28513e3f4d6SMark Murray 		*p++ = IAC;
28613e3f4d6SMark Murray 		*p++ = SE;
28713e3f4d6SMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
28813e3f4d6SMark Murray 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
28913e3f4d6SMark Murray 
29013e3f4d6SMark Murray 		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
29113e3f4d6SMark Murray 		break;
29213e3f4d6SMark Murray 
29313e3f4d6SMark Murray 	default:
29413e3f4d6SMark Murray 		if (encrypt_debug_mode) {
29513e3f4d6SMark Murray 			printf("Unknown option type: %d\r\n", *(data-1));
29613e3f4d6SMark Murray 			printd(data, cnt);
29713e3f4d6SMark Murray 			printf("\r\n");
29813e3f4d6SMark Murray 		}
29913e3f4d6SMark Murray 		/* FALL THROUGH */
30013e3f4d6SMark Murray 	failure:
30113e3f4d6SMark Murray 		/*
30213e3f4d6SMark Murray 		 * We failed.  Send an FB64_IV_BAD option
30313e3f4d6SMark Murray 		 * to the other side so it will know that
30413e3f4d6SMark Murray 		 * things failed.
30513e3f4d6SMark Murray 		 */
30613e3f4d6SMark Murray 		p = fbp->fb_feed + 3;
30713e3f4d6SMark Murray 		*p++ = ENCRYPT_REPLY;
30813e3f4d6SMark Murray 		p++;
30913e3f4d6SMark Murray 		*p++ = FB64_IV_BAD;
31013e3f4d6SMark Murray 		*p++ = IAC;
31113e3f4d6SMark Murray 		*p++ = SE;
31213e3f4d6SMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
31313e3f4d6SMark Murray 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
31413e3f4d6SMark Murray 
31513e3f4d6SMark Murray 		break;
31613e3f4d6SMark Murray 	}
31713e3f4d6SMark Murray 	return(fbp->state[DIR_DECRYPT-1] = state);
31813e3f4d6SMark Murray }
31913e3f4d6SMark Murray 
32013e3f4d6SMark Murray /*
32113e3f4d6SMark Murray  * Returns:
32213e3f4d6SMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
32313e3f4d6SMark Murray  *	 0: Successful, initial negotiation all done.
32413e3f4d6SMark Murray  *	 1: successful, negotiation not done yet.
32513e3f4d6SMark Murray  */
32613e3f4d6SMark Murray 
cfb64_reply(unsigned char * data,int cnt)32713e3f4d6SMark Murray int cfb64_reply(unsigned char *data, int cnt)
32813e3f4d6SMark Murray {
32913e3f4d6SMark Murray 	return(fb64_reply(data, cnt, &fb[CFB]));
33013e3f4d6SMark Murray }
33113e3f4d6SMark Murray 
ofb64_reply(unsigned char * data,int cnt)33213e3f4d6SMark Murray int ofb64_reply(unsigned char *data, int cnt)
33313e3f4d6SMark Murray {
33413e3f4d6SMark Murray 	return(fb64_reply(data, cnt, &fb[OFB]));
33513e3f4d6SMark Murray }
33613e3f4d6SMark Murray 
33713e3f4d6SMark Murray 
fb64_reply(unsigned char * data,int cnt,struct fb * fbp)33813e3f4d6SMark Murray int fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
33913e3f4d6SMark Murray {
34013e3f4d6SMark Murray 	int state = fbp->state[DIR_ENCRYPT-1];
34113e3f4d6SMark Murray 
34213e3f4d6SMark Murray 	if (cnt-- < 1)
34313e3f4d6SMark Murray 		goto failure;
34413e3f4d6SMark Murray 
34513e3f4d6SMark Murray 	switch (*data++) {
34613e3f4d6SMark Murray 	case FB64_IV_OK:
34713e3f4d6SMark Murray 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
34813e3f4d6SMark Murray 		if (state == FAILED)
34913e3f4d6SMark Murray 			state = IN_PROGRESS;
35013e3f4d6SMark Murray 		state &= ~NO_RECV_IV;
35113e3f4d6SMark Murray 		encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
35213e3f4d6SMark Murray 		break;
35313e3f4d6SMark Murray 
35413e3f4d6SMark Murray 	case FB64_IV_BAD:
35513e3f4d6SMark Murray 		memset(fbp->temp_feed, 0, sizeof(DES_cblock));
35613e3f4d6SMark Murray 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
35713e3f4d6SMark Murray 		state = FAILED;
35813e3f4d6SMark Murray 		break;
35913e3f4d6SMark Murray 
36013e3f4d6SMark Murray 	default:
36113e3f4d6SMark Murray 		if (encrypt_debug_mode) {
36213e3f4d6SMark Murray 			printf("Unknown option type: %d\r\n", data[-1]);
36313e3f4d6SMark Murray 			printd(data, cnt);
36413e3f4d6SMark Murray 			printf("\r\n");
365c19800e8SDoug Rabson 		}
36613e3f4d6SMark Murray 		/* FALL THROUGH */
36713e3f4d6SMark Murray 	failure:
36813e3f4d6SMark Murray 		state = FAILED;
36913e3f4d6SMark Murray 		break;
37013e3f4d6SMark Murray 	}
37113e3f4d6SMark Murray 	return(fbp->state[DIR_ENCRYPT-1] = state);
37213e3f4d6SMark Murray }
37313e3f4d6SMark Murray 
cfb64_session(Session_Key * key,int server)37413e3f4d6SMark Murray void cfb64_session(Session_Key *key, int server)
37513e3f4d6SMark Murray {
37613e3f4d6SMark Murray 	fb64_session(key, server, &fb[CFB]);
37713e3f4d6SMark Murray }
37813e3f4d6SMark Murray 
ofb64_session(Session_Key * key,int server)37913e3f4d6SMark Murray void ofb64_session(Session_Key *key, int server)
38013e3f4d6SMark Murray {
38113e3f4d6SMark Murray 	fb64_session(key, server, &fb[OFB]);
38213e3f4d6SMark Murray }
38313e3f4d6SMark Murray 
fb64_session(Session_Key * key,int server,struct fb * fbp)38413e3f4d6SMark Murray static void fb64_session(Session_Key *key, int server, struct fb *fbp)
38513e3f4d6SMark Murray {
38613e3f4d6SMark Murray 
38713e3f4d6SMark Murray 	if (!key || key->type != SK_DES) {
38813e3f4d6SMark Murray 		if (encrypt_debug_mode)
38913e3f4d6SMark Murray 			printf("Can't set krbdes's session key (%d != %d)\r\n",
39013e3f4d6SMark Murray 				key ? key->type : -1, SK_DES);
39113e3f4d6SMark Murray 		return;
39213e3f4d6SMark Murray 	}
39313e3f4d6SMark Murray 	memcpy(fbp->krbdes_key, key->data, sizeof(DES_cblock));
39413e3f4d6SMark Murray 
39513e3f4d6SMark Murray 	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
39613e3f4d6SMark Murray 	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
39713e3f4d6SMark Murray 
39813e3f4d6SMark Murray 	RAND_seed(key->data, key->length);
39913e3f4d6SMark Murray 
40013e3f4d6SMark Murray 	DES_set_key_checked((DES_cblock *)&fbp->krbdes_key,
40113e3f4d6SMark Murray 			    &fbp->krbdes_sched);
40213e3f4d6SMark Murray 	/*
403c19800e8SDoug Rabson 	 * Now look to see if krbdes_start() was waiting for the key to
40413e3f4d6SMark Murray 	 * show up.  If so, go ahead an call it now that we have the key.
40513e3f4d6SMark Murray 	 */
40613e3f4d6SMark Murray 	if (fbp->need_start) {
40713e3f4d6SMark Murray 		fbp->need_start = 0;
40813e3f4d6SMark Murray 		fb64_start(fbp, DIR_ENCRYPT, server);
4094137ff4cSJacques Vidrine 	}
410c19800e8SDoug Rabson }
41113e3f4d6SMark Murray 
41213e3f4d6SMark Murray /*
41313e3f4d6SMark Murray  * We only accept a keyid of 0.  If we get a keyid of
414c19800e8SDoug Rabson  * 0, then mark the state as SUCCESS.
415c19800e8SDoug Rabson  */
41613e3f4d6SMark Murray 
cfb64_keyid(int dir,unsigned char * kp,int * lenp)41713e3f4d6SMark Murray int cfb64_keyid(int dir, unsigned char *kp, int *lenp)
41813e3f4d6SMark Murray {
41913e3f4d6SMark Murray 	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
42013e3f4d6SMark Murray }
42113e3f4d6SMark Murray 
ofb64_keyid(int dir,unsigned char * kp,int * lenp)42213e3f4d6SMark Murray int ofb64_keyid(int dir, unsigned char *kp, int *lenp)
42313e3f4d6SMark Murray {
42413e3f4d6SMark Murray 	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
42513e3f4d6SMark Murray }
42613e3f4d6SMark Murray 
fb64_keyid(int dir,unsigned char * kp,int * lenp,struct fb * fbp)42713e3f4d6SMark Murray int fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
42813e3f4d6SMark Murray {
42913e3f4d6SMark Murray 	int state = fbp->state[dir-1];
43013e3f4d6SMark Murray 
43113e3f4d6SMark Murray 	if (*lenp != 1 || (*kp != '\0')) {
43213e3f4d6SMark Murray 		*lenp = 0;
43313e3f4d6SMark Murray 		return(state);
43413e3f4d6SMark Murray 	}
43513e3f4d6SMark Murray 
43613e3f4d6SMark Murray 	if (state == FAILED)
43713e3f4d6SMark Murray 		state = IN_PROGRESS;
43813e3f4d6SMark Murray 
43913e3f4d6SMark Murray 	state &= ~NO_KEYID;
44013e3f4d6SMark Murray 
44113e3f4d6SMark Murray 	return(fbp->state[dir-1] = state);
44213e3f4d6SMark Murray }
44313e3f4d6SMark Murray 
fb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen,char * type)44413e3f4d6SMark Murray void fb64_printsub(unsigned char *data, size_t cnt,
44513e3f4d6SMark Murray 		   unsigned char *buf, size_t buflen, char *type)
44613e3f4d6SMark Murray {
44713e3f4d6SMark Murray 	char lbuf[32];
44813e3f4d6SMark Murray 	int i;
44913e3f4d6SMark Murray 	char *cp;
45013e3f4d6SMark Murray 
45113e3f4d6SMark Murray 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
45213e3f4d6SMark Murray 	buflen -= 1;
45313e3f4d6SMark Murray 
45413e3f4d6SMark Murray 	switch(data[2]) {
45513e3f4d6SMark Murray 	case FB64_IV:
45613e3f4d6SMark Murray 		snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
45713e3f4d6SMark Murray 		cp = lbuf;
45813e3f4d6SMark Murray 		goto common;
45913e3f4d6SMark Murray 
46013e3f4d6SMark Murray 	case FB64_IV_OK:
46113e3f4d6SMark Murray 		snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
46213e3f4d6SMark Murray 		cp = lbuf;
46313e3f4d6SMark Murray 		goto common;
46413e3f4d6SMark Murray 
46513e3f4d6SMark Murray 	case FB64_IV_BAD:
46613e3f4d6SMark Murray 		snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
46713e3f4d6SMark Murray 		cp = lbuf;
46813e3f4d6SMark Murray 		goto common;
46913e3f4d6SMark Murray 
47013e3f4d6SMark Murray 	default:
47113e3f4d6SMark Murray 		snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
47213e3f4d6SMark Murray 		cp = lbuf;
47313e3f4d6SMark Murray 	common:
47413e3f4d6SMark Murray 		for (; (buflen > 0) && (*buf = *cp++); buf++)
47513e3f4d6SMark Murray 			buflen--;
47613e3f4d6SMark Murray 		for (i = 3; i < cnt; i++) {
47713e3f4d6SMark Murray 			snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
47813e3f4d6SMark Murray 			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
47913e3f4d6SMark Murray 				buflen--;
48013e3f4d6SMark Murray 		}
48113e3f4d6SMark Murray 		break;
48213e3f4d6SMark Murray 	}
48313e3f4d6SMark Murray }
48413e3f4d6SMark Murray 
cfb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen)48513e3f4d6SMark Murray void cfb64_printsub(unsigned char *data, size_t cnt,
48613e3f4d6SMark Murray 		    unsigned char *buf, size_t buflen)
48713e3f4d6SMark Murray {
48813e3f4d6SMark Murray 	fb64_printsub(data, cnt, buf, buflen, "CFB64");
48913e3f4d6SMark Murray }
49013e3f4d6SMark Murray 
ofb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen)49113e3f4d6SMark Murray void ofb64_printsub(unsigned char *data, size_t cnt,
49213e3f4d6SMark Murray 		    unsigned char *buf, size_t buflen)
49313e3f4d6SMark Murray {
49413e3f4d6SMark Murray 	fb64_printsub(data, cnt, buf, buflen, "OFB64");
49513e3f4d6SMark Murray }
49613e3f4d6SMark Murray 
fb64_stream_iv(DES_cblock seed,struct stinfo * stp)49713e3f4d6SMark Murray void fb64_stream_iv(DES_cblock seed, struct stinfo *stp)
49813e3f4d6SMark Murray {
49913e3f4d6SMark Murray 
50013e3f4d6SMark Murray 	memcpy(stp->str_iv, seed,sizeof(DES_cblock));
50113e3f4d6SMark Murray 	memcpy(stp->str_output, seed, sizeof(DES_cblock));
50213e3f4d6SMark Murray 
50313e3f4d6SMark Murray 	DES_set_key_checked(&stp->str_ikey, &stp->str_sched);
50413e3f4d6SMark Murray 
50513e3f4d6SMark Murray 	stp->str_index = sizeof(DES_cblock);
50613e3f4d6SMark Murray }
50713e3f4d6SMark Murray 
fb64_stream_key(DES_cblock key,struct stinfo * stp)50813e3f4d6SMark Murray void fb64_stream_key(DES_cblock key, struct stinfo *stp)
50913e3f4d6SMark Murray {
51013e3f4d6SMark Murray 	memcpy(stp->str_ikey, key, sizeof(DES_cblock));
51113e3f4d6SMark Murray 	DES_set_key_checked((DES_cblock*)key, &stp->str_sched);
512c19800e8SDoug Rabson 
51313e3f4d6SMark Murray 	memcpy(stp->str_output, stp->str_iv, sizeof(DES_cblock));
51413e3f4d6SMark Murray 
515c19800e8SDoug Rabson 	stp->str_index = sizeof(DES_cblock);
516c19800e8SDoug Rabson }
51713e3f4d6SMark Murray 
518c19800e8SDoug Rabson /*
51913e3f4d6SMark Murray  * DES 64 bit Cipher Feedback
520c19800e8SDoug Rabson  *
52113e3f4d6SMark Murray  *     key --->+-----+
52213e3f4d6SMark Murray  *          +->| DES |--+
523c19800e8SDoug Rabson  *          |  +-----+  |
52413e3f4d6SMark Murray  *	    |           v
525c19800e8SDoug Rabson  *  INPUT --(--------->(+)+---> DATA
526c19800e8SDoug Rabson  *          |             |
52713e3f4d6SMark Murray  *	    +-------------+
528c19800e8SDoug Rabson  *
52913e3f4d6SMark Murray  *
530c19800e8SDoug Rabson  * Given:
53113e3f4d6SMark Murray  *	iV: Initial vector, 64 bits (8 bytes) long.
53213e3f4d6SMark Murray  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
53313e3f4d6SMark Murray  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
53413e3f4d6SMark Murray  *
53513e3f4d6SMark Murray  *	V0 = DES(iV, key)
53613e3f4d6SMark Murray  *	On = Dn ^ Vn
53713e3f4d6SMark Murray  *	V(n+1) = DES(On, key)
53813e3f4d6SMark Murray  */
53913e3f4d6SMark Murray 
cfb64_encrypt(unsigned char * s,int c)54013e3f4d6SMark Murray void cfb64_encrypt(unsigned char *s, int c)
54113e3f4d6SMark Murray {
54213e3f4d6SMark Murray 	struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
54313e3f4d6SMark Murray 	int index;
54413e3f4d6SMark Murray 
54513e3f4d6SMark Murray 	index = stp->str_index;
54613e3f4d6SMark Murray 	while (c-- > 0) {
54713e3f4d6SMark Murray 		if (index == sizeof(DES_cblock)) {
54813e3f4d6SMark Murray 			DES_cblock b;
54913e3f4d6SMark Murray 			DES_ecb_encrypt(&stp->str_output, &b,&stp->str_sched, 1);
55013e3f4d6SMark Murray 			memcpy(stp->str_feed, b, sizeof(DES_cblock));
55113e3f4d6SMark Murray 			index = 0;
55213e3f4d6SMark Murray 		}
55313e3f4d6SMark Murray 
55413e3f4d6SMark Murray 		/* On encryption, we store (feed ^ data) which is cypher */
55513e3f4d6SMark Murray 		*s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
55613e3f4d6SMark Murray 		s++;
55713e3f4d6SMark Murray 		index++;
55813e3f4d6SMark Murray 	}
55913e3f4d6SMark Murray 	stp->str_index = index;
56013e3f4d6SMark Murray }
56113e3f4d6SMark Murray 
cfb64_decrypt(int data)562c19800e8SDoug Rabson int cfb64_decrypt(int data)
563c19800e8SDoug Rabson {
564c19800e8SDoug Rabson 	struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
565c19800e8SDoug Rabson 	int index;
56613e3f4d6SMark Murray 
56713e3f4d6SMark Murray 	if (data == -1) {
56813e3f4d6SMark Murray 		/*
56913e3f4d6SMark Murray 		 * Back up one byte.  It is assumed that we will
57013e3f4d6SMark Murray 		 * never back up more than one byte.  If we do, this
57113e3f4d6SMark Murray 		 * may or may not work.
57213e3f4d6SMark Murray 		 */
57313e3f4d6SMark Murray 		if (stp->str_index)
57413e3f4d6SMark Murray 			--stp->str_index;
57513e3f4d6SMark Murray 		return(0);
57613e3f4d6SMark Murray 	}
57713e3f4d6SMark Murray 
57813e3f4d6SMark Murray 	index = stp->str_index++;
57913e3f4d6SMark Murray 	if (index == sizeof(DES_cblock)) {
58013e3f4d6SMark Murray 		DES_cblock b;
58113e3f4d6SMark Murray 		DES_ecb_encrypt(&stp->str_output,&b, &stp->str_sched, 1);
58213e3f4d6SMark Murray 		memcpy(stp->str_feed, b, sizeof(DES_cblock));
58313e3f4d6SMark Murray 		stp->str_index = 1;	/* Next time will be 1 */
58413e3f4d6SMark Murray 		index = 0;		/* But now use 0 */
58513e3f4d6SMark Murray 	}
58613e3f4d6SMark Murray 
58713e3f4d6SMark Murray 	/* On decryption we store (data) which is cypher. */
58813e3f4d6SMark Murray 	stp->str_output[index] = data;
58913e3f4d6SMark Murray 	return(data ^ stp->str_feed[index]);
59013e3f4d6SMark Murray }
59113e3f4d6SMark Murray 
59213e3f4d6SMark Murray /*
59313e3f4d6SMark Murray  * DES 64 bit Output Feedback
594c19800e8SDoug Rabson  *
595c19800e8SDoug Rabson  * key --->+-----+
596c19800e8SDoug Rabson  *	+->| DES |--+
597c19800e8SDoug Rabson  *	|  +-----+  |
59813e3f4d6SMark Murray  *	+-----------+
59913e3f4d6SMark Murray  *	            v
60013e3f4d6SMark Murray  *  INPUT -------->(+) ----> DATA
60113e3f4d6SMark Murray  *
60213e3f4d6SMark Murray  * Given:
60313e3f4d6SMark Murray  *	iV: Initial vector, 64 bits (8 bytes) long.
60413e3f4d6SMark Murray  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
60513e3f4d6SMark Murray  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
60613e3f4d6SMark Murray  *
60713e3f4d6SMark Murray  *	V0 = DES(iV, key)
60813e3f4d6SMark Murray  *	V(n+1) = DES(Vn, key)
60913e3f4d6SMark Murray  *	On = Dn ^ Vn
61013e3f4d6SMark Murray  */
61113e3f4d6SMark Murray 
ofb64_encrypt(unsigned char * s,int c)61213e3f4d6SMark Murray void ofb64_encrypt(unsigned char *s, int c)
61313e3f4d6SMark Murray {
61413e3f4d6SMark Murray 	struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
61513e3f4d6SMark Murray 	int index;
61613e3f4d6SMark Murray 
61713e3f4d6SMark Murray 	index = stp->str_index;
61813e3f4d6SMark Murray 	while (c-- > 0) {
61913e3f4d6SMark Murray 		if (index == sizeof(DES_cblock)) {
62013e3f4d6SMark Murray 			DES_cblock b;
62113e3f4d6SMark Murray 			DES_ecb_encrypt(&stp->str_feed,&b, &stp->str_sched, 1);
62213e3f4d6SMark Murray 			memcpy(stp->str_feed, b, sizeof(DES_cblock));
62313e3f4d6SMark Murray 			index = 0;
62413e3f4d6SMark Murray 		}
62513e3f4d6SMark Murray 		*s++ ^= stp->str_feed[index];
62613e3f4d6SMark Murray 		index++;
62713e3f4d6SMark Murray 	}
62813e3f4d6SMark Murray 	stp->str_index = index;
62913e3f4d6SMark Murray }
63013e3f4d6SMark Murray 
ofb64_decrypt(int data)63113e3f4d6SMark Murray int ofb64_decrypt(int data)
63213e3f4d6SMark Murray {
63313e3f4d6SMark Murray 	struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
634c19800e8SDoug Rabson 	int index;
635c19800e8SDoug Rabson 
636c19800e8SDoug Rabson 	if (data == -1) {
637c19800e8SDoug Rabson 		/*
63813e3f4d6SMark Murray 		 * Back up one byte.  It is assumed that we will
63913e3f4d6SMark Murray 		 * never back up more than one byte.  If we do, this
64013e3f4d6SMark Murray 		 * may or may not work.
64113e3f4d6SMark Murray 		 */
64213e3f4d6SMark Murray 		if (stp->str_index)
64313e3f4d6SMark Murray 			--stp->str_index;
64413e3f4d6SMark Murray 		return(0);
64513e3f4d6SMark Murray 	}
64613e3f4d6SMark Murray 
64713e3f4d6SMark Murray 	index = stp->str_index++;
64813e3f4d6SMark Murray 	if (index == sizeof(DES_cblock)) {
64913e3f4d6SMark Murray 		DES_cblock b;
65013e3f4d6SMark Murray 		DES_ecb_encrypt(&stp->str_feed,&b,&stp->str_sched, 1);
65113e3f4d6SMark Murray 		memcpy(stp->str_feed, b, sizeof(DES_cblock));
65213e3f4d6SMark Murray 		stp->str_index = 1;	/* Next time will be 1 */
65313e3f4d6SMark Murray 		index = 0;		/* But now use 0 */
65413e3f4d6SMark Murray 	}
65513e3f4d6SMark Murray 
65613e3f4d6SMark Murray 	return(data ^ stp->str_feed[index]);
65713e3f4d6SMark Murray }
65813e3f4d6SMark Murray #endif
65913e3f4d6SMark Murray 
66013e3f4d6SMark Murray