xref: /netbsd-src/lib/libtelnet/enc_des.c (revision ce3ee7a75dbe33dc592c5cfef2b2d1fa72e60515)
1*ce3ee7a7Skre /*	$NetBSD: enc_des.c,v 1.18 2024/10/29 13:10:06 kre Exp $	*/
25c099b14Sthorpej 
35c099b14Sthorpej /*-
45c099b14Sthorpej  * Copyright (c) 1991, 1993
55c099b14Sthorpej  *	The Regents of the University of California.  All rights reserved.
65c099b14Sthorpej  *
75c099b14Sthorpej  * Redistribution and use in source and binary forms, with or without
85c099b14Sthorpej  * modification, are permitted provided that the following conditions
95c099b14Sthorpej  * are met:
105c099b14Sthorpej  * 1. Redistributions of source code must retain the above copyright
115c099b14Sthorpej  *    notice, this list of conditions and the following disclaimer.
125c099b14Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
135c099b14Sthorpej  *    notice, this list of conditions and the following disclaimer in the
145c099b14Sthorpej  *    documentation and/or other materials provided with the distribution.
15eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
165c099b14Sthorpej  *    may be used to endorse or promote products derived from this software
175c099b14Sthorpej  *    without specific prior written permission.
185c099b14Sthorpej  *
195c099b14Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
205c099b14Sthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
215c099b14Sthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
225c099b14Sthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
235c099b14Sthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
245c099b14Sthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
255c099b14Sthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
265c099b14Sthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
275c099b14Sthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
285c099b14Sthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
295c099b14Sthorpej  * SUCH DAMAGE.
305c099b14Sthorpej  */
315c099b14Sthorpej 
325c099b14Sthorpej #include <sys/cdefs.h>
335c099b14Sthorpej #ifndef lint
345c099b14Sthorpej #if 0
355c099b14Sthorpej static char sccsid[] = "@(#)enc_des.c	8.3 (Berkeley) 5/30/95"; */
365c099b14Sthorpej #else
37*ce3ee7a7Skre __RCSID("$NetBSD: enc_des.c,v 1.18 2024/10/29 13:10:06 kre Exp $");
385c099b14Sthorpej #endif
395c099b14Sthorpej #endif /* not lint */
405c099b14Sthorpej 
415c099b14Sthorpej #ifdef	ENCRYPTION
425c099b14Sthorpej # ifdef	AUTHENTICATION
435c099b14Sthorpej #  ifdef DES_ENCRYPTION
445c099b14Sthorpej #include <arpa/telnet.h>
455c099b14Sthorpej #include <stdio.h>
465c099b14Sthorpej #include <string.h>
475c099b14Sthorpej #include <stdlib.h>
485c099b14Sthorpej 
499ee65722Sitojun #include <des.h>
505c099b14Sthorpej #include "encrypt.h"
515c099b14Sthorpej #include "key-proto.h"
525c099b14Sthorpej #include "misc-proto.h"
535c099b14Sthorpej 
545c099b14Sthorpej #define	CFB	0
555c099b14Sthorpej #define	OFB	1
565c099b14Sthorpej 
575c099b14Sthorpej #define	NO_SEND_IV	1
585c099b14Sthorpej #define	NO_RECV_IV	2
595c099b14Sthorpej #define	NO_KEYID	4
605c099b14Sthorpej #define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
615c099b14Sthorpej #define	SUCCESS		0
625c099b14Sthorpej #define	FAILED		-1
635c099b14Sthorpej 
645c099b14Sthorpej 
655c099b14Sthorpej struct fb {
665c099b14Sthorpej 	Block krbdes_key;
675c099b14Sthorpej 	Schedule krbdes_sched;
685c099b14Sthorpej 	Block temp_feed;
695c099b14Sthorpej 	unsigned char fb_feed[64];
705c099b14Sthorpej 	int need_start;
715c099b14Sthorpej 	int state[2];
725c099b14Sthorpej 	int keyid[2];
735c099b14Sthorpej 	int once;
745c099b14Sthorpej 	struct stinfo {
755c099b14Sthorpej 		Block		str_output;
765c099b14Sthorpej 		Block		str_feed;
775c099b14Sthorpej 		Block		str_iv;
785c099b14Sthorpej 		Block		str_ikey;
795c099b14Sthorpej 		Schedule	str_sched;
805c099b14Sthorpej 		int		str_index;
815c099b14Sthorpej 		int		str_flagshift;
825c099b14Sthorpej 	} streams[2];
835c099b14Sthorpej };
845c099b14Sthorpej 
855c099b14Sthorpej static struct fb fb[2];
865c099b14Sthorpej 
875c099b14Sthorpej struct keyidlist {
886a6c8f61Schristos 	const char	*keyid;
895c099b14Sthorpej 	int	keyidlen;
905c099b14Sthorpej 	char	*key;
915c099b14Sthorpej 	int	keylen;
925c099b14Sthorpej 	int	flags;
935c099b14Sthorpej } keyidlist [] = {
945c099b14Sthorpej 	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
955c099b14Sthorpej 	{ 0, 0, 0, 0, 0 }
965c099b14Sthorpej };
975c099b14Sthorpej 
985c099b14Sthorpej #define	KEYFLAG_MASK	03
995c099b14Sthorpej 
1005c099b14Sthorpej #define	KEYFLAG_NOINIT	00
1015c099b14Sthorpej #define	KEYFLAG_INIT	01
1025c099b14Sthorpej #define	KEYFLAG_OK	02
1035c099b14Sthorpej #define	KEYFLAG_BAD	03
1045c099b14Sthorpej 
1055c099b14Sthorpej #define	KEYFLAG_SHIFT	2
1065c099b14Sthorpej 
1075c099b14Sthorpej #define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
1085c099b14Sthorpej 
1095c099b14Sthorpej #define	FB64_IV		1
1105c099b14Sthorpej #define	FB64_IV_OK	2
1115c099b14Sthorpej #define	FB64_IV_BAD	3
1125c099b14Sthorpej 
1135c099b14Sthorpej 
1144fcf8685Sperry void fb64_stream_iv(Block, struct stinfo *);
1154fcf8685Sperry void fb64_init(struct fb *);
1164fcf8685Sperry static int fb64_start(struct fb *, int, int);
1174fcf8685Sperry int fb64_is(unsigned char *, int, struct fb *);
1184fcf8685Sperry int fb64_reply(unsigned char *, int, struct fb *);
1194fcf8685Sperry static void fb64_session(Session_Key *, int, struct fb *);
1204fcf8685Sperry void fb64_stream_key(Block *, struct stinfo *);
1214fcf8685Sperry int fb64_keyid(int, unsigned char *, int *, struct fb *);
1225c099b14Sthorpej 
1235c099b14Sthorpej void
124f9113d00Smatt cfb64_init(int server)
1255c099b14Sthorpej {
1265c099b14Sthorpej 	fb64_init(&fb[CFB]);
1275c099b14Sthorpej 	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
1285c099b14Sthorpej 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
1295c099b14Sthorpej 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
1305c099b14Sthorpej }
1315c099b14Sthorpej 
1325c099b14Sthorpej void
133f9113d00Smatt ofb64_init(int server)
1345c099b14Sthorpej {
1355c099b14Sthorpej 	fb64_init(&fb[OFB]);
1365c099b14Sthorpej 	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
1375c099b14Sthorpej 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
1385c099b14Sthorpej 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
1395c099b14Sthorpej }
1405c099b14Sthorpej 
1415c099b14Sthorpej void
142f9113d00Smatt fb64_init(register struct fb *fbp)
1435c099b14Sthorpej {
1445c099b14Sthorpej 	memset((void *)fbp, 0, sizeof(*fbp));
1455c099b14Sthorpej 	fbp->state[0] = fbp->state[1] = FAILED;
1465c099b14Sthorpej 	fbp->fb_feed[0] = IAC;
1475c099b14Sthorpej 	fbp->fb_feed[1] = SB;
1485c099b14Sthorpej 	fbp->fb_feed[2] = TELOPT_ENCRYPT;
1495c099b14Sthorpej 	fbp->fb_feed[3] = ENCRYPT_IS;
1505c099b14Sthorpej }
1515c099b14Sthorpej 
1525c099b14Sthorpej /*
1535c099b14Sthorpej  * Returns:
1545c099b14Sthorpej  *	-1: some error.  Negotiation is done, encryption not ready.
1555c099b14Sthorpej  *	 0: Successful, initial negotiation all done.
1565c099b14Sthorpej  *	 1: successful, negotiation not done yet.
1575c099b14Sthorpej  *	 2: Not yet.  Other things (like getting the key from
1585c099b14Sthorpej  *	    Kerberos) have to happen before we can continue.
1595c099b14Sthorpej  */
1605c099b14Sthorpej int
161f9113d00Smatt cfb64_start(int dir, int server)
1625c099b14Sthorpej {
1635c099b14Sthorpej 	return(fb64_start(&fb[CFB], dir, server));
1645c099b14Sthorpej }
165f9113d00Smatt 
1665c099b14Sthorpej int
167f9113d00Smatt ofb64_start(int dir, int server)
1685c099b14Sthorpej {
1695c099b14Sthorpej 	return(fb64_start(&fb[OFB], dir, server));
1705c099b14Sthorpej }
1715c099b14Sthorpej 
1725c099b14Sthorpej static int
173f9113d00Smatt fb64_start(struct fb *fbp, int dir, int server)
1745c099b14Sthorpej {
1756a6c8f61Schristos 	size_t x;
1765c099b14Sthorpej 	unsigned char *p;
1775c099b14Sthorpej 	register int state;
1785c099b14Sthorpej 
1795c099b14Sthorpej 	switch (dir) {
1805c099b14Sthorpej 	case DIR_DECRYPT:
1815c099b14Sthorpej 		/*
1825c099b14Sthorpej 		 * This is simply a request to have the other side
1835c099b14Sthorpej 		 * start output (our input).  He will negotiate an
1845c099b14Sthorpej 		 * IV so we need not look for it.
1855c099b14Sthorpej 		 */
1865c099b14Sthorpej 		state = fbp->state[dir-1];
1875c099b14Sthorpej 		if (state == FAILED)
1885c099b14Sthorpej 			state = IN_PROGRESS;
1895c099b14Sthorpej 		break;
1905c099b14Sthorpej 
1915c099b14Sthorpej 	case DIR_ENCRYPT:
1925c099b14Sthorpej 		state = fbp->state[dir-1];
1935c099b14Sthorpej 		if (state == FAILED)
1945c099b14Sthorpej 			state = IN_PROGRESS;
1955c099b14Sthorpej 		else if ((state & NO_SEND_IV) == 0)
1965c099b14Sthorpej 			break;
1975c099b14Sthorpej 
1985c099b14Sthorpej 		if (!VALIDKEY(fbp->krbdes_key)) {
1995c099b14Sthorpej 			fbp->need_start = 1;
2005c099b14Sthorpej 			break;
2015c099b14Sthorpej 		}
2025c099b14Sthorpej 		state &= ~NO_SEND_IV;
2035c099b14Sthorpej 		state |= NO_RECV_IV;
204*ce3ee7a7Skre 		if (encrypt_debug())
2055c099b14Sthorpej 			printf("Creating new feed\r\n");
2065c099b14Sthorpej 		/*
2075c099b14Sthorpej 		 * Create a random feed and send it over.
2085c099b14Sthorpej 		 */
2095c099b14Sthorpej 		des_new_random_key(&fbp->temp_feed);
2105c099b14Sthorpej 		des_ecb_encrypt(&fbp->temp_feed, &fbp->temp_feed,
2115c099b14Sthorpej 				fbp->krbdes_sched, 1);
2125c099b14Sthorpej 		p = fbp->fb_feed + 3;
2135c099b14Sthorpej 		*p++ = ENCRYPT_IS;
2145c099b14Sthorpej 		p++;
2155c099b14Sthorpej 		*p++ = FB64_IV;
2165c099b14Sthorpej 		for (x = 0; x < sizeof(Block); ++x) {
2175c099b14Sthorpej 			if ((*p++ = fbp->temp_feed[x]) == IAC)
2185c099b14Sthorpej 				*p++ = IAC;
2195c099b14Sthorpej 		}
2205c099b14Sthorpej 		*p++ = IAC;
2215c099b14Sthorpej 		*p++ = SE;
2225c099b14Sthorpej 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
2235c099b14Sthorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
2245c099b14Sthorpej 		break;
2255c099b14Sthorpej 	default:
2265c099b14Sthorpej 		return(FAILED);
2275c099b14Sthorpej 	}
2285c099b14Sthorpej 	return(fbp->state[dir-1] = state);
2295c099b14Sthorpej }
2305c099b14Sthorpej 
2315c099b14Sthorpej /*
2325c099b14Sthorpej  * Returns:
2335c099b14Sthorpej  *	-1: some error.  Negotiation is done, encryption not ready.
2345c099b14Sthorpej  *	 0: Successful, initial negotiation all done.
2355c099b14Sthorpej  *	 1: successful, negotiation not done yet.
2365c099b14Sthorpej  */
2375c099b14Sthorpej int
238f9113d00Smatt cfb64_is(unsigned char *data, int cnt)
2395c099b14Sthorpej {
2405c099b14Sthorpej 	return(fb64_is(data, cnt, &fb[CFB]));
2415c099b14Sthorpej }
2425c099b14Sthorpej int
243f9113d00Smatt ofb64_is(unsigned char *data, int cnt)
2445c099b14Sthorpej {
2455c099b14Sthorpej 	return(fb64_is(data, cnt, &fb[OFB]));
2465c099b14Sthorpej }
2475c099b14Sthorpej 
2485c099b14Sthorpej int
249f9113d00Smatt fb64_is(unsigned char *data, int cnt, struct fb *fbp)
2505c099b14Sthorpej {
2515c099b14Sthorpej 	unsigned char *p;
2525c099b14Sthorpej 	register int state = fbp->state[DIR_DECRYPT-1];
2535c099b14Sthorpej 
2545c099b14Sthorpej 	if (cnt-- < 1)
2555c099b14Sthorpej 		goto failure;
2565c099b14Sthorpej 
2575c099b14Sthorpej 	switch (*data++) {
2585c099b14Sthorpej 	case FB64_IV:
2595c099b14Sthorpej 		if (cnt != sizeof(Block)) {
260*ce3ee7a7Skre 			if (encrypt_debug())
2615c099b14Sthorpej 				printf("CFB64: initial vector failed on size\r\n");
2625c099b14Sthorpej 			state = FAILED;
2635c099b14Sthorpej 			goto failure;
2645c099b14Sthorpej 		}
2655c099b14Sthorpej 
266*ce3ee7a7Skre 		if (encrypt_debug())
2675c099b14Sthorpej 			printf("CFB64: initial vector received\r\n");
2685c099b14Sthorpej 
269*ce3ee7a7Skre 		if (encrypt_debug())
2705c099b14Sthorpej 			printf("Initializing Decrypt stream\r\n");
2715c099b14Sthorpej 
2725c099b14Sthorpej 		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
2735c099b14Sthorpej 
2745c099b14Sthorpej 		p = fbp->fb_feed + 3;
2755c099b14Sthorpej 		*p++ = ENCRYPT_REPLY;
2765c099b14Sthorpej 		p++;
2775c099b14Sthorpej 		*p++ = FB64_IV_OK;
2785c099b14Sthorpej 		*p++ = IAC;
2795c099b14Sthorpej 		*p++ = SE;
2805c099b14Sthorpej 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
2815c099b14Sthorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
2825c099b14Sthorpej 
2835c099b14Sthorpej 		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
2845c099b14Sthorpej 		break;
2855c099b14Sthorpej 
2865c099b14Sthorpej 	default:
287*ce3ee7a7Skre 		if (encrypt_debug()) {
2885c099b14Sthorpej 			printf("Unknown option type: %d\r\n", *(data-1));
2895c099b14Sthorpej 			printd(data, cnt);
2905c099b14Sthorpej 			printf("\r\n");
2915c099b14Sthorpej 		}
2925c099b14Sthorpej 		/* FALL THROUGH */
2935c099b14Sthorpej 	failure:
2945c099b14Sthorpej 		/*
2955c099b14Sthorpej 		 * We failed.  Send an FB64_IV_BAD option
2965c099b14Sthorpej 		 * to the other side so it will know that
2975c099b14Sthorpej 		 * things failed.
2985c099b14Sthorpej 		 */
2995c099b14Sthorpej 		p = fbp->fb_feed + 3;
3005c099b14Sthorpej 		*p++ = ENCRYPT_REPLY;
3015c099b14Sthorpej 		p++;
3025c099b14Sthorpej 		*p++ = FB64_IV_BAD;
3035c099b14Sthorpej 		*p++ = IAC;
3045c099b14Sthorpej 		*p++ = SE;
3055c099b14Sthorpej 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
3065c099b14Sthorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
3075c099b14Sthorpej 
3085c099b14Sthorpej 		break;
3095c099b14Sthorpej 	}
3105c099b14Sthorpej 	return(fbp->state[DIR_DECRYPT-1] = state);
3115c099b14Sthorpej }
3125c099b14Sthorpej 
3135c099b14Sthorpej /*
3145c099b14Sthorpej  * Returns:
3155c099b14Sthorpej  *	-1: some error.  Negotiation is done, encryption not ready.
3165c099b14Sthorpej  *	 0: Successful, initial negotiation all done.
3175c099b14Sthorpej  *	 1: successful, negotiation not done yet.
3185c099b14Sthorpej  */
3195c099b14Sthorpej int
320f9113d00Smatt cfb64_reply(unsigned char *data, int cnt)
3215c099b14Sthorpej {
3225c099b14Sthorpej 	return(fb64_reply(data, cnt, &fb[CFB]));
3235c099b14Sthorpej }
3245c099b14Sthorpej int
325f9113d00Smatt ofb64_reply(unsigned char *data, int cnt)
3265c099b14Sthorpej {
3275c099b14Sthorpej 	return(fb64_reply(data, cnt, &fb[OFB]));
3285c099b14Sthorpej }
3295c099b14Sthorpej 
3305c099b14Sthorpej int
331f9113d00Smatt fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
3325c099b14Sthorpej {
3335c099b14Sthorpej 	register int state = fbp->state[DIR_ENCRYPT-1];
3345c099b14Sthorpej 
3355c099b14Sthorpej 	if (cnt-- < 1)
3365c099b14Sthorpej 		goto failure;
3375c099b14Sthorpej 
3385c099b14Sthorpej 	switch (*data++) {
3395c099b14Sthorpej 	case FB64_IV_OK:
3405c099b14Sthorpej 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
3415c099b14Sthorpej 		if (state == FAILED)
3425c099b14Sthorpej 			state = IN_PROGRESS;
3435c099b14Sthorpej 		state &= ~NO_RECV_IV;
3446a6c8f61Schristos 		encrypt_send_keyid(DIR_ENCRYPT, (const unsigned char *)"\0", 1, 1);
3455c099b14Sthorpej 		break;
3465c099b14Sthorpej 
3475c099b14Sthorpej 	case FB64_IV_BAD:
3485c099b14Sthorpej 		memset(fbp->temp_feed, 0, sizeof(Block));
3495c099b14Sthorpej 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
3505c099b14Sthorpej 		state = FAILED;
3515c099b14Sthorpej 		break;
3525c099b14Sthorpej 
3535c099b14Sthorpej 	default:
354*ce3ee7a7Skre 		if (encrypt_debug()) {
3555c099b14Sthorpej 			printf("Unknown option type: %d\r\n", data[-1]);
3565c099b14Sthorpej 			printd(data, cnt);
3575c099b14Sthorpej 			printf("\r\n");
3585c099b14Sthorpej 		}
3595c099b14Sthorpej 		/* FALL THROUGH */
3605c099b14Sthorpej 	failure:
3615c099b14Sthorpej 		state = FAILED;
3625c099b14Sthorpej 		break;
3635c099b14Sthorpej 	}
3645c099b14Sthorpej 	return(fbp->state[DIR_ENCRYPT-1] = state);
3655c099b14Sthorpej }
3665c099b14Sthorpej 
3675c099b14Sthorpej void
368f9113d00Smatt cfb64_session(Session_Key *key, int server)
3695c099b14Sthorpej {
3705c099b14Sthorpej 	fb64_session(key, server, &fb[CFB]);
3715c099b14Sthorpej }
3725c099b14Sthorpej 
3735c099b14Sthorpej void
374f9113d00Smatt ofb64_session( Session_Key *key, int server)
3755c099b14Sthorpej {
3765c099b14Sthorpej 	fb64_session(key, server, &fb[OFB]);
3775c099b14Sthorpej }
3785c099b14Sthorpej 
3795c099b14Sthorpej static void
380f9113d00Smatt fb64_session(Session_Key *key, int server, struct fb *fbp)
3815c099b14Sthorpej {
3825c099b14Sthorpej 
3835c099b14Sthorpej 	if (!key || key->type != SK_DES) {
384*ce3ee7a7Skre 		if (encrypt_debug())
3855c099b14Sthorpej 			printf("Can't set krbdes's session key (%d != %d)\r\n",
3865c099b14Sthorpej 				key ? key->type : -1, SK_DES);
3875c099b14Sthorpej 		return;
3885c099b14Sthorpej 	}
3895c099b14Sthorpej 	memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
3905c099b14Sthorpej 
3915c099b14Sthorpej 	fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
3925c099b14Sthorpej 	fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
3935c099b14Sthorpej 
3945c099b14Sthorpej 	if (fbp->once == 0) {
3955c099b14Sthorpej 		des_init_random_number_generator(&fbp->krbdes_key);
3965c099b14Sthorpej 		fbp->once = 1;
3975c099b14Sthorpej 	}
3985c099b14Sthorpej 	des_key_sched(&fbp->krbdes_key, fbp->krbdes_sched);
3995c099b14Sthorpej 	/*
4008e2a0ad6Smbalmer 	 * Now look to see if krbdes_start() was waiting for the key to
4015b28f239Srillig 	 * show up.  If so, go ahead and call it now that we have the key.
4025c099b14Sthorpej 	 */
4035c099b14Sthorpej 	if (fbp->need_start) {
4045c099b14Sthorpej 		fbp->need_start = 0;
4055c099b14Sthorpej 		fb64_start(fbp, DIR_ENCRYPT, server);
4065c099b14Sthorpej 	}
4075c099b14Sthorpej }
4085c099b14Sthorpej 
4095c099b14Sthorpej /*
4105c099b14Sthorpej  * We only accept a keyid of 0.  If we get a keyid of
4115c099b14Sthorpej  * 0, then mark the state as SUCCESS.
4125c099b14Sthorpej  */
4135c099b14Sthorpej int
414f9113d00Smatt cfb64_keyid(int dir, unsigned char *kp, int *lenp)
4155c099b14Sthorpej {
4165c099b14Sthorpej 	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
4175c099b14Sthorpej }
4185c099b14Sthorpej 
4195c099b14Sthorpej 	int
420f9113d00Smatt ofb64_keyid(int dir, unsigned char *kp, int *lenp)
4215c099b14Sthorpej {
4225c099b14Sthorpej 	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
4235c099b14Sthorpej }
4245c099b14Sthorpej 
4255c099b14Sthorpej int
426f9113d00Smatt fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
4275c099b14Sthorpej {
4285c099b14Sthorpej 	register int state = fbp->state[dir-1];
4295c099b14Sthorpej 
4305c099b14Sthorpej 	if (*lenp != 1 || (*kp != '\0')) {
4315c099b14Sthorpej 		*lenp = 0;
4325c099b14Sthorpej 		return(state);
4335c099b14Sthorpej 	}
4345c099b14Sthorpej 
4355c099b14Sthorpej 	if (state == FAILED)
4365c099b14Sthorpej 		state = IN_PROGRESS;
4375c099b14Sthorpej 
4385c099b14Sthorpej 	state &= ~NO_KEYID;
4395c099b14Sthorpej 
4405c099b14Sthorpej 	return(fbp->state[dir-1] = state);
4415c099b14Sthorpej }
4425c099b14Sthorpej 
4435c099b14Sthorpej void
4446a6c8f61Schristos fb64_printsub(const unsigned char *data, int cnt, unsigned char *buf,
4456a6c8f61Schristos     int buflen, const unsigned char *type)
4465c099b14Sthorpej {
4475c099b14Sthorpej 	char lbuf[32];
4485c099b14Sthorpej 	register int i;
4495c099b14Sthorpej 	char *cp;
4505c099b14Sthorpej 
4515c099b14Sthorpej 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
4525c099b14Sthorpej 	buflen -= 1;
4535c099b14Sthorpej 
4545c099b14Sthorpej 	switch(data[2]) {
4555c099b14Sthorpej 	case FB64_IV:
456fabed9f7Sitojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
4575c099b14Sthorpej 		cp = lbuf;
4585c099b14Sthorpej 		goto common;
4595c099b14Sthorpej 
4605c099b14Sthorpej 	case FB64_IV_OK:
461fabed9f7Sitojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
4625c099b14Sthorpej 		cp = lbuf;
4635c099b14Sthorpej 		goto common;
4645c099b14Sthorpej 
4655c099b14Sthorpej 	case FB64_IV_BAD:
466fabed9f7Sitojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
4675c099b14Sthorpej 		cp = lbuf;
4685c099b14Sthorpej 		goto common;
4695c099b14Sthorpej 
4705c099b14Sthorpej 	default:
471fabed9f7Sitojun 		snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
4725c099b14Sthorpej 		cp = lbuf;
4735c099b14Sthorpej 	common:
4745c099b14Sthorpej 		for (; (buflen > 0) && (*buf = *cp++); buf++)
4755c099b14Sthorpej 			buflen--;
4765c099b14Sthorpej 		for (i = 3; i < cnt; i++) {
477fabed9f7Sitojun 			snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
4785c099b14Sthorpej 			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
4795c099b14Sthorpej 				buflen--;
4805c099b14Sthorpej 		}
4815c099b14Sthorpej 		break;
4825c099b14Sthorpej 	}
4835c099b14Sthorpej }
4845c099b14Sthorpej 
4855c099b14Sthorpej void
486f9113d00Smatt cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
4875c099b14Sthorpej {
4885c099b14Sthorpej 	fb64_printsub(data, cnt, buf, buflen, "CFB64");
4895c099b14Sthorpej }
4905c099b14Sthorpej 
4915c099b14Sthorpej 	void
492f9113d00Smatt ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
4935c099b14Sthorpej {
4945c099b14Sthorpej 	fb64_printsub(data, cnt, buf, buflen, "OFB64");
4955c099b14Sthorpej }
4965c099b14Sthorpej 
4975c099b14Sthorpej void
498f9113d00Smatt fb64_stream_iv(Block seed, struct stinfo *stp)
4995c099b14Sthorpej {
5005c099b14Sthorpej 
5015c099b14Sthorpej 	memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
5025c099b14Sthorpej 	memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
5035c099b14Sthorpej 
5045c099b14Sthorpej 	des_key_sched(&stp->str_ikey, stp->str_sched);
5055c099b14Sthorpej 
5065c099b14Sthorpej 	stp->str_index = sizeof(Block);
5075c099b14Sthorpej }
5085c099b14Sthorpej 
5095c099b14Sthorpej void
510f9113d00Smatt fb64_stream_key(Block *key, struct stinfo *stp)
5115c099b14Sthorpej {
5125c099b14Sthorpej 	memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
5135c099b14Sthorpej 	des_key_sched(key, stp->str_sched);
5145c099b14Sthorpej 
5155c099b14Sthorpej 	memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
5165c099b14Sthorpej 
5175c099b14Sthorpej 	stp->str_index = sizeof(Block);
5185c099b14Sthorpej }
5195c099b14Sthorpej 
5205c099b14Sthorpej /*
5215c099b14Sthorpej  * DES 64 bit Cipher Feedback
5225c099b14Sthorpej  *
5235c099b14Sthorpej  *     key --->+-----+
5245c099b14Sthorpej  *          +->| DES |--+
5255c099b14Sthorpej  *          |  +-----+  |
5265c099b14Sthorpej  *	    |           v
5275c099b14Sthorpej  *  INPUT --(--------->(+)+---> DATA
5285c099b14Sthorpej  *          |             |
5295c099b14Sthorpej  *	    +-------------+
5305c099b14Sthorpej  *
5315c099b14Sthorpej  *
5325c099b14Sthorpej  * Given:
5335c099b14Sthorpej  *	iV: Initial vector, 64 bits (8 bytes) long.
5345c099b14Sthorpej  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
5355c099b14Sthorpej  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
5365c099b14Sthorpej  *
5375c099b14Sthorpej  *	V0 = DES(iV, key)
5385c099b14Sthorpej  *	On = Dn ^ Vn
5395c099b14Sthorpej  *	V(n+1) = DES(On, key)
5405c099b14Sthorpej  */
5415c099b14Sthorpej 
5425c099b14Sthorpej void
543f9113d00Smatt cfb64_encrypt(unsigned char *s, int c)
5445c099b14Sthorpej {
5455c099b14Sthorpej 	register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
5460878e1d3Slukem 	register int idx;
5475c099b14Sthorpej 
5480878e1d3Slukem 	idx = stp->str_index;
5495c099b14Sthorpej 	while (c-- > 0) {
5500878e1d3Slukem 		if (idx == sizeof(Block)) {
5515c099b14Sthorpej 			Block b;
5525c099b14Sthorpej 			des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
5535c099b14Sthorpej 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
5540878e1d3Slukem 			idx = 0;
5555c099b14Sthorpej 		}
5565c099b14Sthorpej 
5575c099b14Sthorpej 		/* On encryption, we store (feed ^ data) which is cypher */
5580878e1d3Slukem 		*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
5595c099b14Sthorpej 		s++;
5600878e1d3Slukem 		idx++;
5615c099b14Sthorpej 	}
5620878e1d3Slukem 	stp->str_index = idx;
5635c099b14Sthorpej }
5645c099b14Sthorpej 
5655c099b14Sthorpej int
566f9113d00Smatt cfb64_decrypt(int data)
5675c099b14Sthorpej {
5685c099b14Sthorpej 	register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
5690878e1d3Slukem 	int idx;
5705c099b14Sthorpej 
5715c099b14Sthorpej 	if (data == -1) {
5725c099b14Sthorpej 		/*
5735c099b14Sthorpej 		 * Back up one byte.  It is assumed that we will
5745c099b14Sthorpej 		 * never back up more than one byte.  If we do, this
5755c099b14Sthorpej 		 * may or may not work.
5765c099b14Sthorpej 		 */
5775c099b14Sthorpej 		if (stp->str_index)
5785c099b14Sthorpej 			--stp->str_index;
5795c099b14Sthorpej 		return(0);
5805c099b14Sthorpej 	}
5815c099b14Sthorpej 
5820878e1d3Slukem 	idx = stp->str_index++;
5830878e1d3Slukem 	if (idx == sizeof(Block)) {
5845c099b14Sthorpej 		Block b;
5855c099b14Sthorpej 		des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
5865c099b14Sthorpej 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
5875c099b14Sthorpej 		stp->str_index = 1;	/* Next time will be 1 */
5880878e1d3Slukem 		idx = 0;		/* But now use 0 */
5895c099b14Sthorpej 	}
5905c099b14Sthorpej 
5915c099b14Sthorpej 	/* On decryption we store (data) which is cypher. */
5920878e1d3Slukem 	stp->str_output[idx] = data;
5930878e1d3Slukem 	return(data ^ stp->str_feed[idx]);
5945c099b14Sthorpej }
5955c099b14Sthorpej 
5965c099b14Sthorpej /*
5975c099b14Sthorpej  * DES 64 bit Output Feedback
5985c099b14Sthorpej  *
5995c099b14Sthorpej  * key --->+-----+
6005c099b14Sthorpej  *	+->| DES |--+
6015c099b14Sthorpej  *	|  +-----+  |
6025c099b14Sthorpej  *	+-----------+
6035c099b14Sthorpej  *	            v
6045c099b14Sthorpej  *  INPUT -------->(+) ----> DATA
6055c099b14Sthorpej  *
6065c099b14Sthorpej  * Given:
6075c099b14Sthorpej  *	iV: Initial vector, 64 bits (8 bytes) long.
6085c099b14Sthorpej  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
6095c099b14Sthorpej  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
6105c099b14Sthorpej  *
6115c099b14Sthorpej  *	V0 = DES(iV, key)
6125c099b14Sthorpej  *	V(n+1) = DES(Vn, key)
6135c099b14Sthorpej  *	On = Dn ^ Vn
6145c099b14Sthorpej  */
6155c099b14Sthorpej void
616f9113d00Smatt ofb64_encrypt(unsigned char *s, int c)
6175c099b14Sthorpej {
6185c099b14Sthorpej 	register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
6190878e1d3Slukem 	register int idx;
6205c099b14Sthorpej 
6210878e1d3Slukem 	idx = stp->str_index;
6225c099b14Sthorpej 	while (c-- > 0) {
6230878e1d3Slukem 		if (idx == sizeof(Block)) {
6245c099b14Sthorpej 			Block b;
6255c099b14Sthorpej 			des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
6265c099b14Sthorpej 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
6270878e1d3Slukem 			idx = 0;
6285c099b14Sthorpej 		}
6290878e1d3Slukem 		*s++ ^= stp->str_feed[idx];
6300878e1d3Slukem 		idx++;
6315c099b14Sthorpej 	}
6320878e1d3Slukem 	stp->str_index = idx;
6335c099b14Sthorpej }
6345c099b14Sthorpej 
6355c099b14Sthorpej int
636f9113d00Smatt ofb64_decrypt(int data)
6375c099b14Sthorpej {
6385c099b14Sthorpej 	register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
6390878e1d3Slukem 	int idx;
6405c099b14Sthorpej 
6415c099b14Sthorpej 	if (data == -1) {
6425c099b14Sthorpej 		/*
6435c099b14Sthorpej 		 * Back up one byte.  It is assumed that we will
6445c099b14Sthorpej 		 * never back up more than one byte.  If we do, this
6455c099b14Sthorpej 		 * may or may not work.
6465c099b14Sthorpej 		 */
6475c099b14Sthorpej 		if (stp->str_index)
6485c099b14Sthorpej 			--stp->str_index;
6495c099b14Sthorpej 		return(0);
6505c099b14Sthorpej 	}
6515c099b14Sthorpej 
6520878e1d3Slukem 	idx = stp->str_index++;
6530878e1d3Slukem 	if (idx == sizeof(Block)) {
6545c099b14Sthorpej 		Block b;
6555c099b14Sthorpej 		des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
6565c099b14Sthorpej 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
6575c099b14Sthorpej 		stp->str_index = 1;	/* Next time will be 1 */
6580878e1d3Slukem 		idx = 0;		/* But now use 0 */
6595c099b14Sthorpej 	}
6605c099b14Sthorpej 
6610878e1d3Slukem 	return(data ^ stp->str_feed[idx]);
6625c099b14Sthorpej }
6635c099b14Sthorpej #  endif /* DES_ENCRYPTION */
6645c099b14Sthorpej # endif	/* AUTHENTICATION */
6655c099b14Sthorpej #endif	/* ENCRYPTION */
666