129088Smarkm/*-
229088Smarkm * Copyright (c) 1991, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
34114630Sobrien#if 0
3529088Smarkm#ifndef lint
3629181Smarkmstatic const char sccsid[] = "@(#)enc_des.c	8.3 (Berkeley) 5/30/95";
3729088Smarkm#endif /* not lint */
38114630Sobrien#endif
39114630Sobrien#include <sys/cdefs.h>
40114630Sobrien__FBSDID("$FreeBSD$");
4129088Smarkm
4229088Smarkm#ifdef	ENCRYPTION
4329088Smarkm# ifdef	AUTHENTICATION
4429088Smarkm#include <arpa/telnet.h>
4587139Smarkm#include <openssl/des.h>
4629088Smarkm#include <stdio.h>
4729088Smarkm#include <stdlib.h>
4887139Smarkm#include <string.h>
4929088Smarkm
5029088Smarkm#include "encrypt.h"
5129088Smarkm#include "key-proto.h"
5229088Smarkm#include "misc-proto.h"
5329088Smarkm
5481965Smarkmextern int encrypt_debug_mode;
5529088Smarkm
5629088Smarkm#define	CFB	0
5729088Smarkm#define	OFB	1
5829088Smarkm
5929088Smarkm#define	NO_SEND_IV	1
6029088Smarkm#define	NO_RECV_IV	2
6129088Smarkm#define	NO_KEYID	4
6229088Smarkm#define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
6329088Smarkm#define	SUCCESS		0
6429088Smarkm#define	FAILED		-1
6529088Smarkm
6629088Smarkm
6729088Smarkmstruct fb {
6829088Smarkm	Block krbdes_key;
6929088Smarkm	Schedule krbdes_sched;
7029088Smarkm	Block temp_feed;
7129088Smarkm	unsigned char fb_feed[64];
7229088Smarkm	int need_start;
7329088Smarkm	int state[2];
7429088Smarkm	int keyid[2];
7529088Smarkm	struct stinfo {
7629088Smarkm		Block		str_output;
7729088Smarkm		Block		str_feed;
7829088Smarkm		Block		str_iv;
7929088Smarkm		Block		str_ikey;
8029088Smarkm		Schedule	str_sched;
8129088Smarkm		int		str_index;
8229088Smarkm		int		str_flagshift;
8329088Smarkm	} streams[2];
8429088Smarkm};
8529088Smarkm
8629088Smarkmstatic struct fb fb[2];
8729088Smarkm
8829088Smarkmstruct keyidlist {
8987139Smarkm	const char *keyid;
9029088Smarkm	int	keyidlen;
9129088Smarkm	char	*key;
9229088Smarkm	int	keylen;
9329088Smarkm	int	flags;
9429088Smarkm} keyidlist [] = {
9529088Smarkm	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
9629088Smarkm	{ 0, 0, 0, 0, 0 }
9729088Smarkm};
9829088Smarkm
9929088Smarkm#define	KEYFLAG_MASK	03
10029088Smarkm
10129088Smarkm#define	KEYFLAG_NOINIT	00
10229088Smarkm#define	KEYFLAG_INIT	01
10329088Smarkm#define	KEYFLAG_OK	02
10429088Smarkm#define	KEYFLAG_BAD	03
10529088Smarkm
10629088Smarkm#define	KEYFLAG_SHIFT	2
10729088Smarkm
10829088Smarkm#define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
10929088Smarkm
11029088Smarkm#define	FB64_IV		1
11129088Smarkm#define	FB64_IV_OK	2
11229088Smarkm#define	FB64_IV_BAD	3
11329088Smarkm
11429088Smarkm
11587155Smarkmvoid fb64_stream_iv(Block, struct stinfo *);
11687155Smarkmvoid fb64_init(struct fb *);
11787155Smarkmstatic int fb64_start(struct fb *, int, int);
11887155Smarkmint fb64_is(unsigned char *, int, struct fb *);
11987155Smarkmint fb64_reply(unsigned char *, int, struct fb *);
12087155Smarkmstatic void fb64_session(Session_Key *, int, struct fb *);
12187155Smarkmvoid fb64_stream_key(Block, struct stinfo *);
12287155Smarkmint fb64_keyid(int, unsigned char *, int *, struct fb *);
12329088Smarkm
12487139Smarkmvoid
12587139Smarkmcfb64_init(int server __unused)
12629088Smarkm{
12729088Smarkm	fb64_init(&fb[CFB]);
12829088Smarkm	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
12929088Smarkm	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
13029088Smarkm	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
13129088Smarkm}
13229088Smarkm
13387139Smarkmvoid
13487139Smarkmofb64_init(int server __unused)
13529088Smarkm{
13629088Smarkm	fb64_init(&fb[OFB]);
13729088Smarkm	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
13829088Smarkm	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
13929088Smarkm	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
14029088Smarkm}
14129088Smarkm
14287139Smarkmvoid
14387139Smarkmfb64_init(struct fb *fbp)
14429088Smarkm{
14529088Smarkm	memset((void *)fbp, 0, sizeof(*fbp));
14629088Smarkm	fbp->state[0] = fbp->state[1] = FAILED;
14729088Smarkm	fbp->fb_feed[0] = IAC;
14829088Smarkm	fbp->fb_feed[1] = SB;
14929088Smarkm	fbp->fb_feed[2] = TELOPT_ENCRYPT;
15029088Smarkm	fbp->fb_feed[3] = ENCRYPT_IS;
15129088Smarkm}
15229088Smarkm
15329088Smarkm/*
15429088Smarkm * Returns:
15529088Smarkm *	-1: some error.  Negotiation is done, encryption not ready.
15629088Smarkm *	 0: Successful, initial negotiation all done.
15729088Smarkm *	 1: successful, negotiation not done yet.
15829088Smarkm *	 2: Not yet.  Other things (like getting the key from
15929088Smarkm *	    Kerberos) have to happen before we can continue.
16029088Smarkm */
16187139Smarkmint
16287139Smarkmcfb64_start(int dir, int server)
16329088Smarkm{
16429088Smarkm	return(fb64_start(&fb[CFB], dir, server));
16529088Smarkm}
16687139Smarkm
16787139Smarkmint
16887139Smarkmofb64_start(int dir, int server)
16929088Smarkm{
17029088Smarkm	return(fb64_start(&fb[OFB], dir, server));
17129088Smarkm}
17229088Smarkm
17387139Smarkmstatic int
17487139Smarkmfb64_start(struct fb *fbp, int dir, int server __unused)
17529088Smarkm{
17687139Smarkm	size_t x;
17729088Smarkm	unsigned char *p;
17887139Smarkm	int state;
17929088Smarkm
18029088Smarkm	switch (dir) {
18129088Smarkm	case DIR_DECRYPT:
18229088Smarkm		/*
18329088Smarkm		 * This is simply a request to have the other side
18429088Smarkm		 * start output (our input).  He will negotiate an
18529088Smarkm		 * IV so we need not look for it.
18629088Smarkm		 */
18729088Smarkm		state = fbp->state[dir-1];
18829088Smarkm		if (state == FAILED)
18929088Smarkm			state = IN_PROGRESS;
19029088Smarkm		break;
19129088Smarkm
19229088Smarkm	case DIR_ENCRYPT:
19329088Smarkm		state = fbp->state[dir-1];
19429088Smarkm		if (state == FAILED)
19529088Smarkm			state = IN_PROGRESS;
19629088Smarkm		else if ((state & NO_SEND_IV) == 0)
19729088Smarkm			break;
19829088Smarkm
19929088Smarkm		if (!VALIDKEY(fbp->krbdes_key)) {
20029088Smarkm			fbp->need_start = 1;
20129088Smarkm			break;
20229088Smarkm		}
20329088Smarkm		state &= ~NO_SEND_IV;
20429088Smarkm		state |= NO_RECV_IV;
20529088Smarkm		if (encrypt_debug_mode)
20629088Smarkm			printf("Creating new feed\r\n");
20729088Smarkm		/*
20829088Smarkm		 * Create a random feed and send it over.
20929088Smarkm		 */
210110049Snectar		des_random_key((Block *)fbp->temp_feed);
21129181Smarkm		des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed,
21229088Smarkm				fbp->krbdes_sched, 1);
21329088Smarkm		p = fbp->fb_feed + 3;
21429088Smarkm		*p++ = ENCRYPT_IS;
21529088Smarkm		p++;
21629088Smarkm		*p++ = FB64_IV;
21729088Smarkm		for (x = 0; x < sizeof(Block); ++x) {
21829088Smarkm			if ((*p++ = fbp->temp_feed[x]) == IAC)
21929088Smarkm				*p++ = IAC;
22029088Smarkm		}
22129088Smarkm		*p++ = IAC;
22229088Smarkm		*p++ = SE;
22329088Smarkm		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
22429088Smarkm		net_write(fbp->fb_feed, p - fbp->fb_feed);
22529088Smarkm		break;
22629088Smarkm	default:
22729088Smarkm		return(FAILED);
22829088Smarkm	}
22929088Smarkm	return(fbp->state[dir-1] = state);
23029088Smarkm}
23129088Smarkm
23229088Smarkm/*
23329088Smarkm * Returns:
23429088Smarkm *	-1: some error.  Negotiation is done, encryption not ready.
23529088Smarkm *	 0: Successful, initial negotiation all done.
23629088Smarkm *	 1: successful, negotiation not done yet.
23729088Smarkm */
23887139Smarkmint
23987139Smarkmcfb64_is(unsigned char *data, int cnt)
24029088Smarkm{
24129088Smarkm	return(fb64_is(data, cnt, &fb[CFB]));
24229088Smarkm}
24387139Smarkm
24487139Smarkmint
24587139Smarkmofb64_is(unsigned char *data, int cnt)
24629088Smarkm{
24729088Smarkm	return(fb64_is(data, cnt, &fb[OFB]));
24829088Smarkm}
24929088Smarkm
25087139Smarkmint
25187139Smarkmfb64_is(unsigned char *data, int cnt, struct fb *fbp)
25229088Smarkm{
25329088Smarkm	unsigned char *p;
25487139Smarkm	int state = fbp->state[DIR_DECRYPT-1];
25529088Smarkm
25629088Smarkm	if (cnt-- < 1)
25729088Smarkm		goto failure;
25829088Smarkm
25929088Smarkm	switch (*data++) {
26029088Smarkm	case FB64_IV:
26129088Smarkm		if (cnt != sizeof(Block)) {
26229088Smarkm			if (encrypt_debug_mode)
26329088Smarkm				printf("CFB64: initial vector failed on size\r\n");
26429088Smarkm			state = FAILED;
26529088Smarkm			goto failure;
26629088Smarkm		}
26729088Smarkm
26829088Smarkm		if (encrypt_debug_mode)
26929088Smarkm			printf("CFB64: initial vector received\r\n");
27029088Smarkm
27129088Smarkm		if (encrypt_debug_mode)
27229088Smarkm			printf("Initializing Decrypt stream\r\n");
27329088Smarkm
27429088Smarkm		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
27529088Smarkm
27629088Smarkm		p = fbp->fb_feed + 3;
27729088Smarkm		*p++ = ENCRYPT_REPLY;
27829088Smarkm		p++;
27929088Smarkm		*p++ = FB64_IV_OK;
28029088Smarkm		*p++ = IAC;
28129088Smarkm		*p++ = SE;
28229088Smarkm		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
28329088Smarkm		net_write(fbp->fb_feed, p - fbp->fb_feed);
28429088Smarkm
28529088Smarkm		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
28629088Smarkm		break;
28729088Smarkm
28829088Smarkm	default:
28929088Smarkm		if (encrypt_debug_mode) {
29029088Smarkm			printf("Unknown option type: %d\r\n", *(data-1));
29129088Smarkm			printd(data, cnt);
29229088Smarkm			printf("\r\n");
29329088Smarkm		}
29429088Smarkm		/* FALL THROUGH */
29529088Smarkm	failure:
29629088Smarkm		/*
29729088Smarkm		 * We failed.  Send an FB64_IV_BAD option
29829088Smarkm		 * to the other side so it will know that
29929088Smarkm		 * things failed.
30029088Smarkm		 */
30129088Smarkm		p = fbp->fb_feed + 3;
30229088Smarkm		*p++ = ENCRYPT_REPLY;
30329088Smarkm		p++;
30429088Smarkm		*p++ = FB64_IV_BAD;
30529088Smarkm		*p++ = IAC;
30629088Smarkm		*p++ = SE;
30729088Smarkm		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
30829088Smarkm		net_write(fbp->fb_feed, p - fbp->fb_feed);
30929088Smarkm
31029088Smarkm		break;
31129088Smarkm	}
31229088Smarkm	return(fbp->state[DIR_DECRYPT-1] = state);
31329088Smarkm}
31429088Smarkm
31529088Smarkm/*
31629088Smarkm * Returns:
31729088Smarkm *	-1: some error.  Negotiation is done, encryption not ready.
31829088Smarkm *	 0: Successful, initial negotiation all done.
31929088Smarkm *	 1: successful, negotiation not done yet.
32029088Smarkm */
32187139Smarkmint
32287139Smarkmcfb64_reply(unsigned char *data, int cnt)
32329088Smarkm{
32429088Smarkm	return(fb64_reply(data, cnt, &fb[CFB]));
32529088Smarkm}
32687139Smarkm
32787139Smarkmint
32887139Smarkmofb64_reply(unsigned char *data, int cnt)
32929088Smarkm{
33029088Smarkm	return(fb64_reply(data, cnt, &fb[OFB]));
33129088Smarkm}
33229088Smarkm
33387139Smarkmint
33487139Smarkmfb64_reply(unsigned char *data, int cnt, struct fb *fbp)
33529088Smarkm{
33687139Smarkm	int state = fbp->state[DIR_ENCRYPT-1];
33729088Smarkm
33829088Smarkm	if (cnt-- < 1)
33929088Smarkm		goto failure;
34029088Smarkm
34129088Smarkm	switch (*data++) {
34229088Smarkm	case FB64_IV_OK:
34329088Smarkm		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
34429088Smarkm		if (state == FAILED)
34529088Smarkm			state = IN_PROGRESS;
34629088Smarkm		state &= ~NO_RECV_IV;
34787139Smarkm		encrypt_send_keyid(DIR_ENCRYPT, "\0", 1, 1);
34829088Smarkm		break;
34929088Smarkm
35029088Smarkm	case FB64_IV_BAD:
35129088Smarkm		memset(fbp->temp_feed, 0, sizeof(Block));
35229088Smarkm		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
35329088Smarkm		state = FAILED;
35429088Smarkm		break;
35529088Smarkm
35629088Smarkm	default:
35729088Smarkm		if (encrypt_debug_mode) {
35829088Smarkm			printf("Unknown option type: %d\r\n", data[-1]);
35929088Smarkm			printd(data, cnt);
36029088Smarkm			printf("\r\n");
36129088Smarkm		}
36229088Smarkm		/* FALL THROUGH */
36329088Smarkm	failure:
36429088Smarkm		state = FAILED;
36529088Smarkm		break;
36629088Smarkm	}
36729088Smarkm	return(fbp->state[DIR_ENCRYPT-1] = state);
36829088Smarkm}
36929088Smarkm
37087139Smarkmvoid
37187139Smarkmcfb64_session(Session_Key *key, int server)
37229088Smarkm{
37329088Smarkm	fb64_session(key, server, &fb[CFB]);
37429088Smarkm}
37529088Smarkm
37687139Smarkmvoid
37787139Smarkmofb64_session(Session_Key *key, int server)
37829088Smarkm{
37929088Smarkm	fb64_session(key, server, &fb[OFB]);
38029088Smarkm}
38129088Smarkm
38287139Smarkmstatic void
38387139Smarkmfb64_session(Session_Key *key, int server, struct fb *fbp)
38429088Smarkm{
38529088Smarkm	if (!key || key->type != SK_DES) {
38629088Smarkm		if (encrypt_debug_mode)
38729088Smarkm			printf("Can't set krbdes's session key (%d != %d)\r\n",
38829088Smarkm				key ? key->type : -1, SK_DES);
38929088Smarkm		return;
39029088Smarkm	}
39129088Smarkm	memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
39229088Smarkm
39329088Smarkm	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
39429088Smarkm	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
39529088Smarkm
39629181Smarkm	des_key_sched((Block *)fbp->krbdes_key, fbp->krbdes_sched);
39729088Smarkm	/*
39829088Smarkm	 * Now look to see if krbdes_start() was was waiting for
39929088Smarkm	 * the key to show up.  If so, go ahead an call it now
40029088Smarkm	 * that we have the key.
40129088Smarkm	 */
40229088Smarkm	if (fbp->need_start) {
40329088Smarkm		fbp->need_start = 0;
40429088Smarkm		fb64_start(fbp, DIR_ENCRYPT, server);
40529088Smarkm	}
40629088Smarkm}
40729088Smarkm
40829088Smarkm/*
40929088Smarkm * We only accept a keyid of 0.  If we get a keyid of
41029088Smarkm * 0, then mark the state as SUCCESS.
41129088Smarkm */
41287139Smarkmint
41387139Smarkmcfb64_keyid(int dir, unsigned char *kp, int *lenp)
41429088Smarkm{
41529088Smarkm	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
41629088Smarkm}
41729088Smarkm
41887139Smarkmint
41987139Smarkmofb64_keyid(int dir, unsigned char *kp, int *lenp)
42029088Smarkm{
42129088Smarkm	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
42229088Smarkm}
42329088Smarkm
42487139Smarkmint
42587139Smarkmfb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
42629088Smarkm{
42787139Smarkm	int state = fbp->state[dir-1];
42829088Smarkm
42929088Smarkm	if (*lenp != 1 || (*kp != '\0')) {
43029088Smarkm		*lenp = 0;
43129088Smarkm		return(state);
43229088Smarkm	}
43329088Smarkm
43429088Smarkm	if (state == FAILED)
43529088Smarkm		state = IN_PROGRESS;
43629088Smarkm
43729088Smarkm	state &= ~NO_KEYID;
43829088Smarkm
43929088Smarkm	return(fbp->state[dir-1] = state);
44029088Smarkm}
44129088Smarkm
44287139Smarkmvoid
44387139Smarkmfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen, const char *type)
44429088Smarkm{
44529088Smarkm	char lbuf[32];
44687139Smarkm	int i;
44729088Smarkm	char *cp;
44829088Smarkm
44929088Smarkm	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
45029088Smarkm	buflen -= 1;
45129088Smarkm
45229088Smarkm	switch(data[2]) {
45329088Smarkm	case FB64_IV:
45429088Smarkm		sprintf(lbuf, "%s_IV", type);
45529088Smarkm		cp = lbuf;
45629088Smarkm		goto common;
45729088Smarkm
45829088Smarkm	case FB64_IV_OK:
45929088Smarkm		sprintf(lbuf, "%s_IV_OK", type);
46029088Smarkm		cp = lbuf;
46129088Smarkm		goto common;
46229088Smarkm
46329088Smarkm	case FB64_IV_BAD:
46429088Smarkm		sprintf(lbuf, "%s_IV_BAD", type);
46529088Smarkm		cp = lbuf;
46629088Smarkm		goto common;
46729088Smarkm
46829088Smarkm	default:
46929088Smarkm		sprintf(lbuf, " %d (unknown)", data[2]);
47029088Smarkm		cp = lbuf;
47129088Smarkm	common:
47229088Smarkm		for (; (buflen > 0) && (*buf = *cp++); buf++)
47329088Smarkm			buflen--;
47429088Smarkm		for (i = 3; i < cnt; i++) {
47529088Smarkm			sprintf(lbuf, " %d", data[i]);
47629088Smarkm			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
47729088Smarkm				buflen--;
47829088Smarkm		}
47929088Smarkm		break;
48029088Smarkm	}
48129088Smarkm}
48229088Smarkm
48387139Smarkmvoid
48487139Smarkmcfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
48529088Smarkm{
48629088Smarkm	fb64_printsub(data, cnt, buf, buflen, "CFB64");
48729088Smarkm}
48829088Smarkm
48987139Smarkmvoid
49087139Smarkmofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
49129088Smarkm{
49229088Smarkm	fb64_printsub(data, cnt, buf, buflen, "OFB64");
49329088Smarkm}
49429088Smarkm
49587139Smarkmvoid
49687139Smarkmfb64_stream_iv(Block seed, struct stinfo *stp)
49729088Smarkm{
49829088Smarkm
49929088Smarkm	memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
50029088Smarkm	memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
50129088Smarkm
50229181Smarkm	des_key_sched((Block *)stp->str_ikey, stp->str_sched);
50329088Smarkm
50429088Smarkm	stp->str_index = sizeof(Block);
50529088Smarkm}
50629088Smarkm
50787139Smarkmvoid
50887139Smarkmfb64_stream_key(Block key, struct stinfo *stp)
50929088Smarkm{
51029088Smarkm	memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
51129181Smarkm	des_key_sched((Block *)key, stp->str_sched);
51229088Smarkm
51329088Smarkm	memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
51429088Smarkm
51529088Smarkm	stp->str_index = sizeof(Block);
51629088Smarkm}
51729088Smarkm
51829088Smarkm/*
51929088Smarkm * DES 64 bit Cipher Feedback
52029088Smarkm *
52129088Smarkm *     key --->+-----+
52229088Smarkm *          +->| DES |--+
52329088Smarkm *          |  +-----+  |
52429088Smarkm *	    |           v
52529088Smarkm *  INPUT --(--------->(+)+---> DATA
52629088Smarkm *          |             |
52729088Smarkm *	    +-------------+
52829088Smarkm *
52929088Smarkm *
53029088Smarkm * Given:
53129088Smarkm *	iV: Initial vector, 64 bits (8 bytes) long.
53229088Smarkm *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
53329088Smarkm *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
53429088Smarkm *
53529088Smarkm *	V0 = DES(iV, key)
53629088Smarkm *	On = Dn ^ Vn
53729088Smarkm *	V(n+1) = DES(On, key)
53829088Smarkm */
53929088Smarkm
54087139Smarkmvoid
54187139Smarkmcfb64_encrypt(unsigned char *s, int c)
54229088Smarkm{
54387139Smarkm	struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
54487139Smarkm	int idx;
54529088Smarkm
54687139Smarkm	idx = stp->str_index;
54729088Smarkm	while (c-- > 0) {
54887139Smarkm		if (idx == sizeof(Block)) {
54929088Smarkm			Block b;
55029181Smarkm			des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
55129088Smarkm			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
55287139Smarkm			idx = 0;
55329088Smarkm		}
55429088Smarkm
55529088Smarkm		/* On encryption, we store (feed ^ data) which is cypher */
55687139Smarkm		*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
55729088Smarkm		s++;
55887139Smarkm		idx++;
55929088Smarkm	}
56087139Smarkm	stp->str_index = idx;
56129088Smarkm}
56229088Smarkm
56387139Smarkmint
56487139Smarkmcfb64_decrypt(int data)
56529088Smarkm{
56687139Smarkm	struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
56787139Smarkm	int idx;
56829088Smarkm
56929088Smarkm	if (data == -1) {
57029088Smarkm		/*
57129088Smarkm		 * Back up one byte.  It is assumed that we will
57229088Smarkm		 * never back up more than one byte.  If we do, this
57329088Smarkm		 * may or may not work.
57429088Smarkm		 */
57529088Smarkm		if (stp->str_index)
57629088Smarkm			--stp->str_index;
57729088Smarkm		return(0);
57829088Smarkm	}
57929088Smarkm
58087139Smarkm	idx = stp->str_index++;
58187139Smarkm	if (idx == sizeof(Block)) {
58229088Smarkm		Block b;
58329181Smarkm		des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
58429088Smarkm		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
58529088Smarkm		stp->str_index = 1;	/* Next time will be 1 */
58687139Smarkm		idx = 0;		/* But now use 0 */
58729088Smarkm	}
58829088Smarkm
58929088Smarkm	/* On decryption we store (data) which is cypher. */
59087139Smarkm	stp->str_output[idx] = data;
59187139Smarkm	return(data ^ stp->str_feed[idx]);
59229088Smarkm}
59329088Smarkm
59429088Smarkm/*
59529088Smarkm * DES 64 bit Output Feedback
59629088Smarkm *
59729088Smarkm * key --->+-----+
59829088Smarkm *	+->| DES |--+
59929088Smarkm *	|  +-----+  |
60029088Smarkm *	+-----------+
60129088Smarkm *	            v
60229088Smarkm *  INPUT -------->(+) ----> DATA
60329088Smarkm *
60429088Smarkm * Given:
60529088Smarkm *	iV: Initial vector, 64 bits (8 bytes) long.
60629088Smarkm *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
60729088Smarkm *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
60829088Smarkm *
60929088Smarkm *	V0 = DES(iV, key)
61029088Smarkm *	V(n+1) = DES(Vn, key)
61129088Smarkm *	On = Dn ^ Vn
61229088Smarkm */
61387139Smarkmvoid
61487139Smarkmofb64_encrypt(unsigned char *s, int c)
61529088Smarkm{
61687139Smarkm	struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
61787139Smarkm	int idx;
61829088Smarkm
61987139Smarkm	idx = stp->str_index;
62029088Smarkm	while (c-- > 0) {
62187139Smarkm		if (idx == sizeof(Block)) {
62229088Smarkm			Block b;
62329181Smarkm			des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
62429088Smarkm			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
62587139Smarkm			idx = 0;
62629088Smarkm		}
62787139Smarkm		*s++ ^= stp->str_feed[idx];
62887139Smarkm		idx++;
62929088Smarkm	}
63087139Smarkm	stp->str_index = idx;
63129088Smarkm}
63229088Smarkm
63387139Smarkmint
63487139Smarkmofb64_decrypt(int data)
63529088Smarkm{
63687139Smarkm	struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
63787139Smarkm	int idx;
63829088Smarkm
63929088Smarkm	if (data == -1) {
64029088Smarkm		/*
64129088Smarkm		 * Back up one byte.  It is assumed that we will
64229088Smarkm		 * never back up more than one byte.  If we do, this
64329088Smarkm		 * may or may not work.
64429088Smarkm		 */
64529088Smarkm		if (stp->str_index)
64629088Smarkm			--stp->str_index;
64729088Smarkm		return(0);
64829088Smarkm	}
64929088Smarkm
65087139Smarkm	idx = stp->str_index++;
65187139Smarkm	if (idx == sizeof(Block)) {
65229088Smarkm		Block b;
65329181Smarkm		des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
65429088Smarkm		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
65529088Smarkm		stp->str_index = 1;	/* Next time will be 1 */
65687139Smarkm		idx = 0;		/* But now use 0 */
65729088Smarkm	}
65829088Smarkm
65987139Smarkm	return(data ^ stp->str_feed[idx]);
66029088Smarkm}
66129088Smarkm# endif	/* AUTHENTICATION */
66229088Smarkm#endif	/* ENCRYPTION */
663