xref: /freebsd/contrib/telnet/libtelnet/enc_des.c (revision 21f083c0a6fd6751b7da98cf93e1adad535309be)
181cb6ddcSMark Murray /*-
281cb6ddcSMark Murray  * Copyright (c) 1991, 1993
381cb6ddcSMark Murray  *	The Regents of the University of California.  All rights reserved.
481cb6ddcSMark Murray  *
581cb6ddcSMark Murray  * Redistribution and use in source and binary forms, with or without
681cb6ddcSMark Murray  * modification, are permitted provided that the following conditions
781cb6ddcSMark Murray  * are met:
881cb6ddcSMark Murray  * 1. Redistributions of source code must retain the above copyright
981cb6ddcSMark Murray  *    notice, this list of conditions and the following disclaimer.
1081cb6ddcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
1181cb6ddcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
1281cb6ddcSMark Murray  *    documentation and/or other materials provided with the distribution.
1381cb6ddcSMark Murray  * 3. All advertising materials mentioning features or use of this software
1481cb6ddcSMark Murray  *    must display the following acknowledgement:
1581cb6ddcSMark Murray  *	This product includes software developed by the University of
1681cb6ddcSMark Murray  *	California, Berkeley and its contributors.
1781cb6ddcSMark Murray  * 4. Neither the name of the University nor the names of its contributors
1881cb6ddcSMark Murray  *    may be used to endorse or promote products derived from this software
1981cb6ddcSMark Murray  *    without specific prior written permission.
2081cb6ddcSMark Murray  *
2181cb6ddcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2281cb6ddcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2381cb6ddcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2481cb6ddcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2581cb6ddcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2681cb6ddcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2781cb6ddcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2881cb6ddcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2981cb6ddcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3081cb6ddcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3181cb6ddcSMark Murray  * SUCH DAMAGE.
32bf4f84d4SMark Murray  *
33bf4f84d4SMark Murray  * $FreeBSD$
3481cb6ddcSMark Murray  */
3581cb6ddcSMark Murray 
3681cb6ddcSMark Murray #ifndef lint
3704c426ccSMark Murray static const char sccsid[] = "@(#)enc_des.c	8.3 (Berkeley) 5/30/95";
3881cb6ddcSMark Murray #endif /* not lint */
3981cb6ddcSMark Murray 
4081cb6ddcSMark Murray #ifdef	ENCRYPTION
4181cb6ddcSMark Murray # ifdef	AUTHENTICATION
4281cb6ddcSMark Murray #  ifdef DES_ENCRYPTION
4381cb6ddcSMark Murray #include <arpa/telnet.h>
4481cb6ddcSMark Murray #include <stdio.h>
4581cb6ddcSMark Murray #ifdef	__STDC__
4681cb6ddcSMark Murray #include <stdlib.h>
4781cb6ddcSMark Murray #endif
4881cb6ddcSMark Murray 
49bf4f84d4SMark Murray #include <openssl/des.h>
5004c426ccSMark Murray #include <string.h>
5181cb6ddcSMark Murray #include "encrypt.h"
5281cb6ddcSMark Murray #include "key-proto.h"
5381cb6ddcSMark Murray #include "misc-proto.h"
5481cb6ddcSMark Murray 
5521f083c0SMark Murray extern int encrypt_debug_mode;
5621f083c0SMark Murray void des_set_random_generator_seed(des_cblock *); /* XXX */
5781cb6ddcSMark Murray 
5881cb6ddcSMark Murray #define	CFB	0
5981cb6ddcSMark Murray #define	OFB	1
6081cb6ddcSMark Murray 
6181cb6ddcSMark Murray #define	NO_SEND_IV	1
6281cb6ddcSMark Murray #define	NO_RECV_IV	2
6381cb6ddcSMark Murray #define	NO_KEYID	4
6481cb6ddcSMark Murray #define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
6581cb6ddcSMark Murray #define	SUCCESS		0
6681cb6ddcSMark Murray #define	FAILED		-1
6781cb6ddcSMark Murray 
6881cb6ddcSMark Murray 
6981cb6ddcSMark Murray struct fb {
7081cb6ddcSMark Murray 	Block krbdes_key;
7181cb6ddcSMark Murray 	Schedule krbdes_sched;
7281cb6ddcSMark Murray 	Block temp_feed;
7381cb6ddcSMark Murray 	unsigned char fb_feed[64];
7481cb6ddcSMark Murray 	int need_start;
7581cb6ddcSMark Murray 	int state[2];
7681cb6ddcSMark Murray 	int keyid[2];
7781cb6ddcSMark Murray 	int once;
7881cb6ddcSMark Murray 	struct stinfo {
7981cb6ddcSMark Murray 		Block		str_output;
8081cb6ddcSMark Murray 		Block		str_feed;
8181cb6ddcSMark Murray 		Block		str_iv;
8281cb6ddcSMark Murray 		Block		str_ikey;
8381cb6ddcSMark Murray 		Schedule	str_sched;
8481cb6ddcSMark Murray 		int		str_index;
8581cb6ddcSMark Murray 		int		str_flagshift;
8681cb6ddcSMark Murray 	} streams[2];
8781cb6ddcSMark Murray };
8881cb6ddcSMark Murray 
8981cb6ddcSMark Murray static struct fb fb[2];
9081cb6ddcSMark Murray 
9181cb6ddcSMark Murray struct keyidlist {
9281cb6ddcSMark Murray 	char	*keyid;
9381cb6ddcSMark Murray 	int	keyidlen;
9481cb6ddcSMark Murray 	char	*key;
9581cb6ddcSMark Murray 	int	keylen;
9681cb6ddcSMark Murray 	int	flags;
9781cb6ddcSMark Murray } keyidlist [] = {
9881cb6ddcSMark Murray 	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
9981cb6ddcSMark Murray 	{ 0, 0, 0, 0, 0 }
10081cb6ddcSMark Murray };
10181cb6ddcSMark Murray 
10281cb6ddcSMark Murray #define	KEYFLAG_MASK	03
10381cb6ddcSMark Murray 
10481cb6ddcSMark Murray #define	KEYFLAG_NOINIT	00
10581cb6ddcSMark Murray #define	KEYFLAG_INIT	01
10681cb6ddcSMark Murray #define	KEYFLAG_OK	02
10781cb6ddcSMark Murray #define	KEYFLAG_BAD	03
10881cb6ddcSMark Murray 
10981cb6ddcSMark Murray #define	KEYFLAG_SHIFT	2
11081cb6ddcSMark Murray 
11181cb6ddcSMark Murray #define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
11281cb6ddcSMark Murray 
11381cb6ddcSMark Murray #define	FB64_IV		1
11481cb6ddcSMark Murray #define	FB64_IV_OK	2
11581cb6ddcSMark Murray #define	FB64_IV_BAD	3
11681cb6ddcSMark Murray 
11781cb6ddcSMark Murray 
11881cb6ddcSMark Murray void fb64_stream_iv P((Block, struct stinfo *));
11981cb6ddcSMark Murray void fb64_init P((struct fb *));
12081cb6ddcSMark Murray static int fb64_start P((struct fb *, int, int));
12181cb6ddcSMark Murray int fb64_is P((unsigned char *, int, struct fb *));
12281cb6ddcSMark Murray int fb64_reply P((unsigned char *, int, struct fb *));
12381cb6ddcSMark Murray static void fb64_session P((Session_Key *, int, struct fb *));
12481cb6ddcSMark Murray void fb64_stream_key P((Block, struct stinfo *));
12581cb6ddcSMark Murray int fb64_keyid P((int, unsigned char *, int *, struct fb *));
12681cb6ddcSMark Murray 
12781cb6ddcSMark Murray 	void
12881cb6ddcSMark Murray cfb64_init(server)
12981cb6ddcSMark Murray 	int server;
13081cb6ddcSMark Murray {
13181cb6ddcSMark Murray 	fb64_init(&fb[CFB]);
13281cb6ddcSMark Murray 	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
13381cb6ddcSMark Murray 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
13481cb6ddcSMark Murray 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
13581cb6ddcSMark Murray }
13681cb6ddcSMark Murray 
13781cb6ddcSMark Murray 	void
13881cb6ddcSMark Murray ofb64_init(server)
13981cb6ddcSMark Murray 	int server;
14081cb6ddcSMark Murray {
14181cb6ddcSMark Murray 	fb64_init(&fb[OFB]);
14281cb6ddcSMark Murray 	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
14381cb6ddcSMark Murray 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
14481cb6ddcSMark Murray 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
14581cb6ddcSMark Murray }
14681cb6ddcSMark Murray 
14781cb6ddcSMark Murray 	void
14881cb6ddcSMark Murray fb64_init(fbp)
14981cb6ddcSMark Murray 	register struct fb *fbp;
15081cb6ddcSMark Murray {
15181cb6ddcSMark Murray 	memset((void *)fbp, 0, sizeof(*fbp));
15281cb6ddcSMark Murray 	fbp->state[0] = fbp->state[1] = FAILED;
15381cb6ddcSMark Murray 	fbp->fb_feed[0] = IAC;
15481cb6ddcSMark Murray 	fbp->fb_feed[1] = SB;
15581cb6ddcSMark Murray 	fbp->fb_feed[2] = TELOPT_ENCRYPT;
15681cb6ddcSMark Murray 	fbp->fb_feed[3] = ENCRYPT_IS;
15781cb6ddcSMark Murray }
15881cb6ddcSMark Murray 
15981cb6ddcSMark Murray /*
16081cb6ddcSMark Murray  * Returns:
16181cb6ddcSMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
16281cb6ddcSMark Murray  *	 0: Successful, initial negotiation all done.
16381cb6ddcSMark Murray  *	 1: successful, negotiation not done yet.
16481cb6ddcSMark Murray  *	 2: Not yet.  Other things (like getting the key from
16581cb6ddcSMark Murray  *	    Kerberos) have to happen before we can continue.
16681cb6ddcSMark Murray  */
16781cb6ddcSMark Murray 	int
16881cb6ddcSMark Murray cfb64_start(dir, server)
16981cb6ddcSMark Murray 	int dir;
17081cb6ddcSMark Murray 	int server;
17181cb6ddcSMark Murray {
17281cb6ddcSMark Murray 	return(fb64_start(&fb[CFB], dir, server));
17381cb6ddcSMark Murray }
17481cb6ddcSMark Murray 	int
17581cb6ddcSMark Murray ofb64_start(dir, server)
17681cb6ddcSMark Murray 	int dir;
17781cb6ddcSMark Murray 	int server;
17881cb6ddcSMark Murray {
17981cb6ddcSMark Murray 	return(fb64_start(&fb[OFB], dir, server));
18081cb6ddcSMark Murray }
18181cb6ddcSMark Murray 
18281cb6ddcSMark Murray 	static int
18381cb6ddcSMark Murray fb64_start(fbp, dir, server)
18481cb6ddcSMark Murray 	struct fb *fbp;
18581cb6ddcSMark Murray 	int dir;
18681cb6ddcSMark Murray 	int server;
18781cb6ddcSMark Murray {
18881cb6ddcSMark Murray 	int x;
18981cb6ddcSMark Murray 	unsigned char *p;
19081cb6ddcSMark Murray 	register int state;
19181cb6ddcSMark Murray 
19281cb6ddcSMark Murray 	switch (dir) {
19381cb6ddcSMark Murray 	case DIR_DECRYPT:
19481cb6ddcSMark Murray 		/*
19581cb6ddcSMark Murray 		 * This is simply a request to have the other side
19681cb6ddcSMark Murray 		 * start output (our input).  He will negotiate an
19781cb6ddcSMark Murray 		 * IV so we need not look for it.
19881cb6ddcSMark Murray 		 */
19981cb6ddcSMark Murray 		state = fbp->state[dir-1];
20081cb6ddcSMark Murray 		if (state == FAILED)
20181cb6ddcSMark Murray 			state = IN_PROGRESS;
20281cb6ddcSMark Murray 		break;
20381cb6ddcSMark Murray 
20481cb6ddcSMark Murray 	case DIR_ENCRYPT:
20581cb6ddcSMark Murray 		state = fbp->state[dir-1];
20681cb6ddcSMark Murray 		if (state == FAILED)
20781cb6ddcSMark Murray 			state = IN_PROGRESS;
20881cb6ddcSMark Murray 		else if ((state & NO_SEND_IV) == 0)
20981cb6ddcSMark Murray 			break;
21081cb6ddcSMark Murray 
21181cb6ddcSMark Murray 		if (!VALIDKEY(fbp->krbdes_key)) {
21281cb6ddcSMark Murray 			fbp->need_start = 1;
21381cb6ddcSMark Murray 			break;
21481cb6ddcSMark Murray 		}
21581cb6ddcSMark Murray 		state &= ~NO_SEND_IV;
21681cb6ddcSMark Murray 		state |= NO_RECV_IV;
21781cb6ddcSMark Murray 		if (encrypt_debug_mode)
21881cb6ddcSMark Murray 			printf("Creating new feed\r\n");
21981cb6ddcSMark Murray 		/*
22081cb6ddcSMark Murray 		 * Create a random feed and send it over.
22181cb6ddcSMark Murray 		 */
22204c426ccSMark Murray 		des_new_random_key((Block *)fbp->temp_feed);
22304c426ccSMark Murray 		des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed,
22481cb6ddcSMark Murray 				fbp->krbdes_sched, 1);
22581cb6ddcSMark Murray 		p = fbp->fb_feed + 3;
22681cb6ddcSMark Murray 		*p++ = ENCRYPT_IS;
22781cb6ddcSMark Murray 		p++;
22881cb6ddcSMark Murray 		*p++ = FB64_IV;
22981cb6ddcSMark Murray 		for (x = 0; x < sizeof(Block); ++x) {
23081cb6ddcSMark Murray 			if ((*p++ = fbp->temp_feed[x]) == IAC)
23181cb6ddcSMark Murray 				*p++ = IAC;
23281cb6ddcSMark Murray 		}
23381cb6ddcSMark Murray 		*p++ = IAC;
23481cb6ddcSMark Murray 		*p++ = SE;
23581cb6ddcSMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
23681cb6ddcSMark Murray 		net_write(fbp->fb_feed, p - fbp->fb_feed);
23781cb6ddcSMark Murray 		break;
23881cb6ddcSMark Murray 	default:
23981cb6ddcSMark Murray 		return(FAILED);
24081cb6ddcSMark Murray 	}
24181cb6ddcSMark Murray 	return(fbp->state[dir-1] = state);
24281cb6ddcSMark Murray }
24381cb6ddcSMark Murray 
24481cb6ddcSMark Murray /*
24581cb6ddcSMark Murray  * Returns:
24681cb6ddcSMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
24781cb6ddcSMark Murray  *	 0: Successful, initial negotiation all done.
24881cb6ddcSMark Murray  *	 1: successful, negotiation not done yet.
24981cb6ddcSMark Murray  */
25081cb6ddcSMark Murray 	int
25181cb6ddcSMark Murray cfb64_is(data, cnt)
25281cb6ddcSMark Murray 	unsigned char *data;
25381cb6ddcSMark Murray 	int cnt;
25481cb6ddcSMark Murray {
25581cb6ddcSMark Murray 	return(fb64_is(data, cnt, &fb[CFB]));
25681cb6ddcSMark Murray }
25781cb6ddcSMark Murray 	int
25881cb6ddcSMark Murray ofb64_is(data, cnt)
25981cb6ddcSMark Murray 	unsigned char *data;
26081cb6ddcSMark Murray 	int cnt;
26181cb6ddcSMark Murray {
26281cb6ddcSMark Murray 	return(fb64_is(data, cnt, &fb[OFB]));
26381cb6ddcSMark Murray }
26481cb6ddcSMark Murray 
26581cb6ddcSMark Murray 	int
26681cb6ddcSMark Murray fb64_is(data, cnt, fbp)
26781cb6ddcSMark Murray 	unsigned char *data;
26881cb6ddcSMark Murray 	int cnt;
26981cb6ddcSMark Murray 	struct fb *fbp;
27081cb6ddcSMark Murray {
27181cb6ddcSMark Murray 	unsigned char *p;
27281cb6ddcSMark Murray 	register int state = fbp->state[DIR_DECRYPT-1];
27381cb6ddcSMark Murray 
27481cb6ddcSMark Murray 	if (cnt-- < 1)
27581cb6ddcSMark Murray 		goto failure;
27681cb6ddcSMark Murray 
27781cb6ddcSMark Murray 	switch (*data++) {
27881cb6ddcSMark Murray 	case FB64_IV:
27981cb6ddcSMark Murray 		if (cnt != sizeof(Block)) {
28081cb6ddcSMark Murray 			if (encrypt_debug_mode)
28181cb6ddcSMark Murray 				printf("CFB64: initial vector failed on size\r\n");
28281cb6ddcSMark Murray 			state = FAILED;
28381cb6ddcSMark Murray 			goto failure;
28481cb6ddcSMark Murray 		}
28581cb6ddcSMark Murray 
28681cb6ddcSMark Murray 		if (encrypt_debug_mode)
28781cb6ddcSMark Murray 			printf("CFB64: initial vector received\r\n");
28881cb6ddcSMark Murray 
28981cb6ddcSMark Murray 		if (encrypt_debug_mode)
29081cb6ddcSMark Murray 			printf("Initializing Decrypt stream\r\n");
29181cb6ddcSMark Murray 
29281cb6ddcSMark Murray 		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
29381cb6ddcSMark Murray 
29481cb6ddcSMark Murray 		p = fbp->fb_feed + 3;
29581cb6ddcSMark Murray 		*p++ = ENCRYPT_REPLY;
29681cb6ddcSMark Murray 		p++;
29781cb6ddcSMark Murray 		*p++ = FB64_IV_OK;
29881cb6ddcSMark Murray 		*p++ = IAC;
29981cb6ddcSMark Murray 		*p++ = SE;
30081cb6ddcSMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
30181cb6ddcSMark Murray 		net_write(fbp->fb_feed, p - fbp->fb_feed);
30281cb6ddcSMark Murray 
30381cb6ddcSMark Murray 		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
30481cb6ddcSMark Murray 		break;
30581cb6ddcSMark Murray 
30681cb6ddcSMark Murray 	default:
30781cb6ddcSMark Murray 		if (encrypt_debug_mode) {
30881cb6ddcSMark Murray 			printf("Unknown option type: %d\r\n", *(data-1));
30981cb6ddcSMark Murray 			printd(data, cnt);
31081cb6ddcSMark Murray 			printf("\r\n");
31181cb6ddcSMark Murray 		}
31281cb6ddcSMark Murray 		/* FALL THROUGH */
31381cb6ddcSMark Murray 	failure:
31481cb6ddcSMark Murray 		/*
31581cb6ddcSMark Murray 		 * We failed.  Send an FB64_IV_BAD option
31681cb6ddcSMark Murray 		 * to the other side so it will know that
31781cb6ddcSMark Murray 		 * things failed.
31881cb6ddcSMark Murray 		 */
31981cb6ddcSMark Murray 		p = fbp->fb_feed + 3;
32081cb6ddcSMark Murray 		*p++ = ENCRYPT_REPLY;
32181cb6ddcSMark Murray 		p++;
32281cb6ddcSMark Murray 		*p++ = FB64_IV_BAD;
32381cb6ddcSMark Murray 		*p++ = IAC;
32481cb6ddcSMark Murray 		*p++ = SE;
32581cb6ddcSMark Murray 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
32681cb6ddcSMark Murray 		net_write(fbp->fb_feed, p - fbp->fb_feed);
32781cb6ddcSMark Murray 
32881cb6ddcSMark Murray 		break;
32981cb6ddcSMark Murray 	}
33081cb6ddcSMark Murray 	return(fbp->state[DIR_DECRYPT-1] = state);
33181cb6ddcSMark Murray }
33281cb6ddcSMark Murray 
33381cb6ddcSMark Murray /*
33481cb6ddcSMark Murray  * Returns:
33581cb6ddcSMark Murray  *	-1: some error.  Negotiation is done, encryption not ready.
33681cb6ddcSMark Murray  *	 0: Successful, initial negotiation all done.
33781cb6ddcSMark Murray  *	 1: successful, negotiation not done yet.
33881cb6ddcSMark Murray  */
33981cb6ddcSMark Murray 	int
34081cb6ddcSMark Murray cfb64_reply(data, cnt)
34181cb6ddcSMark Murray 	unsigned char *data;
34281cb6ddcSMark Murray 	int cnt;
34381cb6ddcSMark Murray {
34481cb6ddcSMark Murray 	return(fb64_reply(data, cnt, &fb[CFB]));
34581cb6ddcSMark Murray }
34681cb6ddcSMark Murray 	int
34781cb6ddcSMark Murray ofb64_reply(data, cnt)
34881cb6ddcSMark Murray 	unsigned char *data;
34981cb6ddcSMark Murray 	int cnt;
35081cb6ddcSMark Murray {
35181cb6ddcSMark Murray 	return(fb64_reply(data, cnt, &fb[OFB]));
35281cb6ddcSMark Murray }
35381cb6ddcSMark Murray 
35481cb6ddcSMark Murray 
35581cb6ddcSMark Murray 	int
35681cb6ddcSMark Murray fb64_reply(data, cnt, fbp)
35781cb6ddcSMark Murray 	unsigned char *data;
35881cb6ddcSMark Murray 	int cnt;
35981cb6ddcSMark Murray 	struct fb *fbp;
36081cb6ddcSMark Murray {
36181cb6ddcSMark Murray 	register int state = fbp->state[DIR_ENCRYPT-1];
36281cb6ddcSMark Murray 
36381cb6ddcSMark Murray 	if (cnt-- < 1)
36481cb6ddcSMark Murray 		goto failure;
36581cb6ddcSMark Murray 
36681cb6ddcSMark Murray 	switch (*data++) {
36781cb6ddcSMark Murray 	case FB64_IV_OK:
36881cb6ddcSMark Murray 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
36981cb6ddcSMark Murray 		if (state == FAILED)
37081cb6ddcSMark Murray 			state = IN_PROGRESS;
37181cb6ddcSMark Murray 		state &= ~NO_RECV_IV;
37281cb6ddcSMark Murray 		encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
37381cb6ddcSMark Murray 		break;
37481cb6ddcSMark Murray 
37581cb6ddcSMark Murray 	case FB64_IV_BAD:
37681cb6ddcSMark Murray 		memset(fbp->temp_feed, 0, sizeof(Block));
37781cb6ddcSMark Murray 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
37881cb6ddcSMark Murray 		state = FAILED;
37981cb6ddcSMark Murray 		break;
38081cb6ddcSMark Murray 
38181cb6ddcSMark Murray 	default:
38281cb6ddcSMark Murray 		if (encrypt_debug_mode) {
38381cb6ddcSMark Murray 			printf("Unknown option type: %d\r\n", data[-1]);
38481cb6ddcSMark Murray 			printd(data, cnt);
38581cb6ddcSMark Murray 			printf("\r\n");
38681cb6ddcSMark Murray 		}
38781cb6ddcSMark Murray 		/* FALL THROUGH */
38881cb6ddcSMark Murray 	failure:
38981cb6ddcSMark Murray 		state = FAILED;
39081cb6ddcSMark Murray 		break;
39181cb6ddcSMark Murray 	}
39281cb6ddcSMark Murray 	return(fbp->state[DIR_ENCRYPT-1] = state);
39381cb6ddcSMark Murray }
39481cb6ddcSMark Murray 
39581cb6ddcSMark Murray 	void
39681cb6ddcSMark Murray cfb64_session(key, server)
39781cb6ddcSMark Murray 	Session_Key *key;
39881cb6ddcSMark Murray 	int server;
39981cb6ddcSMark Murray {
40081cb6ddcSMark Murray 	fb64_session(key, server, &fb[CFB]);
40181cb6ddcSMark Murray }
40281cb6ddcSMark Murray 
40381cb6ddcSMark Murray 	void
40481cb6ddcSMark Murray ofb64_session(key, server)
40581cb6ddcSMark Murray 	Session_Key *key;
40681cb6ddcSMark Murray 	int server;
40781cb6ddcSMark Murray {
40881cb6ddcSMark Murray 	fb64_session(key, server, &fb[OFB]);
40981cb6ddcSMark Murray }
41081cb6ddcSMark Murray 
41181cb6ddcSMark Murray 	static void
41281cb6ddcSMark Murray fb64_session(key, server, fbp)
41381cb6ddcSMark Murray 	Session_Key *key;
41481cb6ddcSMark Murray 	int server;
41581cb6ddcSMark Murray 	struct fb *fbp;
41681cb6ddcSMark Murray {
41781cb6ddcSMark Murray 
41881cb6ddcSMark Murray 	if (!key || key->type != SK_DES) {
41981cb6ddcSMark Murray 		if (encrypt_debug_mode)
42081cb6ddcSMark Murray 			printf("Can't set krbdes's session key (%d != %d)\r\n",
42181cb6ddcSMark Murray 				key ? key->type : -1, SK_DES);
42281cb6ddcSMark Murray 		return;
42381cb6ddcSMark Murray 	}
42481cb6ddcSMark Murray 	memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
42581cb6ddcSMark Murray 
42681cb6ddcSMark Murray 	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
42781cb6ddcSMark Murray 	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
42881cb6ddcSMark Murray 
42981cb6ddcSMark Murray 	if (fbp->once == 0) {
43004c426ccSMark Murray 		des_set_random_generator_seed((Block *)fbp->krbdes_key);
43181cb6ddcSMark Murray 		fbp->once = 1;
43281cb6ddcSMark Murray 	}
43304c426ccSMark Murray 	des_key_sched((Block *)fbp->krbdes_key, fbp->krbdes_sched);
43481cb6ddcSMark Murray 	/*
43581cb6ddcSMark Murray 	 * Now look to see if krbdes_start() was was waiting for
43681cb6ddcSMark Murray 	 * the key to show up.  If so, go ahead an call it now
43781cb6ddcSMark Murray 	 * that we have the key.
43881cb6ddcSMark Murray 	 */
43981cb6ddcSMark Murray 	if (fbp->need_start) {
44081cb6ddcSMark Murray 		fbp->need_start = 0;
44181cb6ddcSMark Murray 		fb64_start(fbp, DIR_ENCRYPT, server);
44281cb6ddcSMark Murray 	}
44381cb6ddcSMark Murray }
44481cb6ddcSMark Murray 
44581cb6ddcSMark Murray /*
44681cb6ddcSMark Murray  * We only accept a keyid of 0.  If we get a keyid of
44781cb6ddcSMark Murray  * 0, then mark the state as SUCCESS.
44881cb6ddcSMark Murray  */
44981cb6ddcSMark Murray 	int
45081cb6ddcSMark Murray cfb64_keyid(dir, kp, lenp)
45181cb6ddcSMark Murray 	int dir, *lenp;
45281cb6ddcSMark Murray 	unsigned char *kp;
45381cb6ddcSMark Murray {
45481cb6ddcSMark Murray 	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
45581cb6ddcSMark Murray }
45681cb6ddcSMark Murray 
45781cb6ddcSMark Murray 	int
45881cb6ddcSMark Murray ofb64_keyid(dir, kp, lenp)
45981cb6ddcSMark Murray 	int dir, *lenp;
46081cb6ddcSMark Murray 	unsigned char *kp;
46181cb6ddcSMark Murray {
46281cb6ddcSMark Murray 	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
46381cb6ddcSMark Murray }
46481cb6ddcSMark Murray 
46581cb6ddcSMark Murray 	int
46681cb6ddcSMark Murray fb64_keyid(dir, kp, lenp, fbp)
46781cb6ddcSMark Murray 	int dir, *lenp;
46881cb6ddcSMark Murray 	unsigned char *kp;
46981cb6ddcSMark Murray 	struct fb *fbp;
47081cb6ddcSMark Murray {
47181cb6ddcSMark Murray 	register int state = fbp->state[dir-1];
47281cb6ddcSMark Murray 
47381cb6ddcSMark Murray 	if (*lenp != 1 || (*kp != '\0')) {
47481cb6ddcSMark Murray 		*lenp = 0;
47581cb6ddcSMark Murray 		return(state);
47681cb6ddcSMark Murray 	}
47781cb6ddcSMark Murray 
47881cb6ddcSMark Murray 	if (state == FAILED)
47981cb6ddcSMark Murray 		state = IN_PROGRESS;
48081cb6ddcSMark Murray 
48181cb6ddcSMark Murray 	state &= ~NO_KEYID;
48281cb6ddcSMark Murray 
48381cb6ddcSMark Murray 	return(fbp->state[dir-1] = state);
48481cb6ddcSMark Murray }
48581cb6ddcSMark Murray 
48681cb6ddcSMark Murray 	void
48781cb6ddcSMark Murray fb64_printsub(data, cnt, buf, buflen, type)
48881cb6ddcSMark Murray 	unsigned char *data, *buf, *type;
48981cb6ddcSMark Murray 	int cnt, buflen;
49081cb6ddcSMark Murray {
49181cb6ddcSMark Murray 	char lbuf[32];
49281cb6ddcSMark Murray 	register int i;
49381cb6ddcSMark Murray 	char *cp;
49481cb6ddcSMark Murray 
49581cb6ddcSMark Murray 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
49681cb6ddcSMark Murray 	buflen -= 1;
49781cb6ddcSMark Murray 
49881cb6ddcSMark Murray 	switch(data[2]) {
49981cb6ddcSMark Murray 	case FB64_IV:
50081cb6ddcSMark Murray 		sprintf(lbuf, "%s_IV", type);
50181cb6ddcSMark Murray 		cp = lbuf;
50281cb6ddcSMark Murray 		goto common;
50381cb6ddcSMark Murray 
50481cb6ddcSMark Murray 	case FB64_IV_OK:
50581cb6ddcSMark Murray 		sprintf(lbuf, "%s_IV_OK", type);
50681cb6ddcSMark Murray 		cp = lbuf;
50781cb6ddcSMark Murray 		goto common;
50881cb6ddcSMark Murray 
50981cb6ddcSMark Murray 	case FB64_IV_BAD:
51081cb6ddcSMark Murray 		sprintf(lbuf, "%s_IV_BAD", type);
51181cb6ddcSMark Murray 		cp = lbuf;
51281cb6ddcSMark Murray 		goto common;
51381cb6ddcSMark Murray 
51481cb6ddcSMark Murray 	default:
51581cb6ddcSMark Murray 		sprintf(lbuf, " %d (unknown)", data[2]);
51681cb6ddcSMark Murray 		cp = lbuf;
51781cb6ddcSMark Murray 	common:
51881cb6ddcSMark Murray 		for (; (buflen > 0) && (*buf = *cp++); buf++)
51981cb6ddcSMark Murray 			buflen--;
52081cb6ddcSMark Murray 		for (i = 3; i < cnt; i++) {
52181cb6ddcSMark Murray 			sprintf(lbuf, " %d", data[i]);
52281cb6ddcSMark Murray 			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
52381cb6ddcSMark Murray 				buflen--;
52481cb6ddcSMark Murray 		}
52581cb6ddcSMark Murray 		break;
52681cb6ddcSMark Murray 	}
52781cb6ddcSMark Murray }
52881cb6ddcSMark Murray 
52981cb6ddcSMark Murray 	void
53081cb6ddcSMark Murray cfb64_printsub(data, cnt, buf, buflen)
53181cb6ddcSMark Murray 	unsigned char *data, *buf;
53281cb6ddcSMark Murray 	int cnt, buflen;
53381cb6ddcSMark Murray {
53481cb6ddcSMark Murray 	fb64_printsub(data, cnt, buf, buflen, "CFB64");
53581cb6ddcSMark Murray }
53681cb6ddcSMark Murray 
53781cb6ddcSMark Murray 	void
53881cb6ddcSMark Murray ofb64_printsub(data, cnt, buf, buflen)
53981cb6ddcSMark Murray 	unsigned char *data, *buf;
54081cb6ddcSMark Murray 	int cnt, buflen;
54181cb6ddcSMark Murray {
54281cb6ddcSMark Murray 	fb64_printsub(data, cnt, buf, buflen, "OFB64");
54381cb6ddcSMark Murray }
54481cb6ddcSMark Murray 
54581cb6ddcSMark Murray 	void
54681cb6ddcSMark Murray fb64_stream_iv(seed, stp)
54781cb6ddcSMark Murray 	Block seed;
54881cb6ddcSMark Murray 	register struct stinfo *stp;
54981cb6ddcSMark Murray {
55081cb6ddcSMark Murray 
55181cb6ddcSMark Murray 	memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
55281cb6ddcSMark Murray 	memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
55381cb6ddcSMark Murray 
55404c426ccSMark Murray 	des_key_sched((Block *)stp->str_ikey, stp->str_sched);
55581cb6ddcSMark Murray 
55681cb6ddcSMark Murray 	stp->str_index = sizeof(Block);
55781cb6ddcSMark Murray }
55881cb6ddcSMark Murray 
55981cb6ddcSMark Murray 	void
56081cb6ddcSMark Murray fb64_stream_key(key, stp)
56181cb6ddcSMark Murray 	Block key;
56281cb6ddcSMark Murray 	register struct stinfo *stp;
56381cb6ddcSMark Murray {
56481cb6ddcSMark Murray 	memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
56504c426ccSMark Murray 	des_key_sched((Block *)key, stp->str_sched);
56681cb6ddcSMark Murray 
56781cb6ddcSMark Murray 	memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
56881cb6ddcSMark Murray 
56981cb6ddcSMark Murray 	stp->str_index = sizeof(Block);
57081cb6ddcSMark Murray }
57181cb6ddcSMark Murray 
57281cb6ddcSMark Murray /*
57381cb6ddcSMark Murray  * DES 64 bit Cipher Feedback
57481cb6ddcSMark Murray  *
57581cb6ddcSMark Murray  *     key --->+-----+
57681cb6ddcSMark Murray  *          +->| DES |--+
57781cb6ddcSMark Murray  *          |  +-----+  |
57881cb6ddcSMark Murray  *	    |           v
57981cb6ddcSMark Murray  *  INPUT --(--------->(+)+---> DATA
58081cb6ddcSMark Murray  *          |             |
58181cb6ddcSMark Murray  *	    +-------------+
58281cb6ddcSMark Murray  *
58381cb6ddcSMark Murray  *
58481cb6ddcSMark Murray  * Given:
58581cb6ddcSMark Murray  *	iV: Initial vector, 64 bits (8 bytes) long.
58681cb6ddcSMark Murray  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
58781cb6ddcSMark Murray  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
58881cb6ddcSMark Murray  *
58981cb6ddcSMark Murray  *	V0 = DES(iV, key)
59081cb6ddcSMark Murray  *	On = Dn ^ Vn
59181cb6ddcSMark Murray  *	V(n+1) = DES(On, key)
59281cb6ddcSMark Murray  */
59381cb6ddcSMark Murray 
59481cb6ddcSMark Murray 	void
59581cb6ddcSMark Murray cfb64_encrypt(s, c)
59681cb6ddcSMark Murray 	register unsigned char *s;
59781cb6ddcSMark Murray 	int c;
59881cb6ddcSMark Murray {
59981cb6ddcSMark Murray 	register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
60081cb6ddcSMark Murray 	register int index;
60181cb6ddcSMark Murray 
60281cb6ddcSMark Murray 	index = stp->str_index;
60381cb6ddcSMark Murray 	while (c-- > 0) {
60481cb6ddcSMark Murray 		if (index == sizeof(Block)) {
60581cb6ddcSMark Murray 			Block b;
60604c426ccSMark Murray 			des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
60781cb6ddcSMark Murray 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
60881cb6ddcSMark Murray 			index = 0;
60981cb6ddcSMark Murray 		}
61081cb6ddcSMark Murray 
61181cb6ddcSMark Murray 		/* On encryption, we store (feed ^ data) which is cypher */
61281cb6ddcSMark Murray 		*s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
61381cb6ddcSMark Murray 		s++;
61481cb6ddcSMark Murray 		index++;
61581cb6ddcSMark Murray 	}
61681cb6ddcSMark Murray 	stp->str_index = index;
61781cb6ddcSMark Murray }
61881cb6ddcSMark Murray 
61981cb6ddcSMark Murray 	int
62081cb6ddcSMark Murray cfb64_decrypt(data)
62181cb6ddcSMark Murray 	int data;
62281cb6ddcSMark Murray {
62381cb6ddcSMark Murray 	register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
62481cb6ddcSMark Murray 	int index;
62581cb6ddcSMark Murray 
62681cb6ddcSMark Murray 	if (data == -1) {
62781cb6ddcSMark Murray 		/*
62881cb6ddcSMark Murray 		 * Back up one byte.  It is assumed that we will
62981cb6ddcSMark Murray 		 * never back up more than one byte.  If we do, this
63081cb6ddcSMark Murray 		 * may or may not work.
63181cb6ddcSMark Murray 		 */
63281cb6ddcSMark Murray 		if (stp->str_index)
63381cb6ddcSMark Murray 			--stp->str_index;
63481cb6ddcSMark Murray 		return(0);
63581cb6ddcSMark Murray 	}
63681cb6ddcSMark Murray 
63781cb6ddcSMark Murray 	index = stp->str_index++;
63881cb6ddcSMark Murray 	if (index == sizeof(Block)) {
63981cb6ddcSMark Murray 		Block b;
64004c426ccSMark Murray 		des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
64181cb6ddcSMark Murray 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
64281cb6ddcSMark Murray 		stp->str_index = 1;	/* Next time will be 1 */
64381cb6ddcSMark Murray 		index = 0;		/* But now use 0 */
64481cb6ddcSMark Murray 	}
64581cb6ddcSMark Murray 
64681cb6ddcSMark Murray 	/* On decryption we store (data) which is cypher. */
64781cb6ddcSMark Murray 	stp->str_output[index] = data;
64881cb6ddcSMark Murray 	return(data ^ stp->str_feed[index]);
64981cb6ddcSMark Murray }
65081cb6ddcSMark Murray 
65181cb6ddcSMark Murray /*
65281cb6ddcSMark Murray  * DES 64 bit Output Feedback
65381cb6ddcSMark Murray  *
65481cb6ddcSMark Murray  * key --->+-----+
65581cb6ddcSMark Murray  *	+->| DES |--+
65681cb6ddcSMark Murray  *	|  +-----+  |
65781cb6ddcSMark Murray  *	+-----------+
65881cb6ddcSMark Murray  *	            v
65981cb6ddcSMark Murray  *  INPUT -------->(+) ----> DATA
66081cb6ddcSMark Murray  *
66181cb6ddcSMark Murray  * Given:
66281cb6ddcSMark Murray  *	iV: Initial vector, 64 bits (8 bytes) long.
66381cb6ddcSMark Murray  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
66481cb6ddcSMark Murray  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
66581cb6ddcSMark Murray  *
66681cb6ddcSMark Murray  *	V0 = DES(iV, key)
66781cb6ddcSMark Murray  *	V(n+1) = DES(Vn, key)
66881cb6ddcSMark Murray  *	On = Dn ^ Vn
66981cb6ddcSMark Murray  */
67081cb6ddcSMark Murray 	void
67181cb6ddcSMark Murray ofb64_encrypt(s, c)
67281cb6ddcSMark Murray 	register unsigned char *s;
67381cb6ddcSMark Murray 	int c;
67481cb6ddcSMark Murray {
67581cb6ddcSMark Murray 	register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
67681cb6ddcSMark Murray 	register int index;
67781cb6ddcSMark Murray 
67881cb6ddcSMark Murray 	index = stp->str_index;
67981cb6ddcSMark Murray 	while (c-- > 0) {
68081cb6ddcSMark Murray 		if (index == sizeof(Block)) {
68181cb6ddcSMark Murray 			Block b;
68204c426ccSMark Murray 			des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
68381cb6ddcSMark Murray 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
68481cb6ddcSMark Murray 			index = 0;
68581cb6ddcSMark Murray 		}
68681cb6ddcSMark Murray 		*s++ ^= stp->str_feed[index];
68781cb6ddcSMark Murray 		index++;
68881cb6ddcSMark Murray 	}
68981cb6ddcSMark Murray 	stp->str_index = index;
69081cb6ddcSMark Murray }
69181cb6ddcSMark Murray 
69281cb6ddcSMark Murray 	int
69381cb6ddcSMark Murray ofb64_decrypt(data)
69481cb6ddcSMark Murray 	int data;
69581cb6ddcSMark Murray {
69681cb6ddcSMark Murray 	register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
69781cb6ddcSMark Murray 	int index;
69881cb6ddcSMark Murray 
69981cb6ddcSMark Murray 	if (data == -1) {
70081cb6ddcSMark Murray 		/*
70181cb6ddcSMark Murray 		 * Back up one byte.  It is assumed that we will
70281cb6ddcSMark Murray 		 * never back up more than one byte.  If we do, this
70381cb6ddcSMark Murray 		 * may or may not work.
70481cb6ddcSMark Murray 		 */
70581cb6ddcSMark Murray 		if (stp->str_index)
70681cb6ddcSMark Murray 			--stp->str_index;
70781cb6ddcSMark Murray 		return(0);
70881cb6ddcSMark Murray 	}
70981cb6ddcSMark Murray 
71081cb6ddcSMark Murray 	index = stp->str_index++;
71181cb6ddcSMark Murray 	if (index == sizeof(Block)) {
71281cb6ddcSMark Murray 		Block b;
71304c426ccSMark Murray 		des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
71481cb6ddcSMark Murray 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
71581cb6ddcSMark Murray 		stp->str_index = 1;	/* Next time will be 1 */
71681cb6ddcSMark Murray 		index = 0;		/* But now use 0 */
71781cb6ddcSMark Murray 	}
71881cb6ddcSMark Murray 
71981cb6ddcSMark Murray 	return(data ^ stp->str_feed[index]);
72081cb6ddcSMark Murray }
72181cb6ddcSMark Murray #  endif /* DES_ENCRYPTION */
72281cb6ddcSMark Murray # endif	/* AUTHENTICATION */
72381cb6ddcSMark Murray #endif	/* ENCRYPTION */
724