1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: src/crypto/telnet/libtelnet/enc_des.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $
34 */
35
36#include <sys/cdefs.h>
37
38#ifdef __FBSDID
39__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/enc_des.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $");
40#endif
41
42#ifndef __unused
43#define __unused        __attribute__((__unused__))
44#endif
45
46#ifndef lint
47static const char sccsid[] = "@(#)enc_des.c	8.3 (Berkeley) 5/30/95";
48#endif /* not lint */
49
50#ifdef	ENCRYPTION
51# ifdef	AUTHENTICATION
52#include <arpa/telnet.h>
53#include <des.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57
58#include "encrypt.h"
59#include "key-proto.h"
60#include "misc-proto.h"
61
62extern int encrypt_debug_mode;
63
64#define	CFB	0
65#define	OFB	1
66
67#define	NO_SEND_IV	1
68#define	NO_RECV_IV	2
69#define	NO_KEYID	4
70#define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
71#define	SUCCESS		0
72#define	FAILED		-1
73
74
75struct fb {
76	Block krbdes_key;
77	Schedule krbdes_sched;
78	Block temp_feed;
79	unsigned char fb_feed[64];
80	int need_start;
81	int state[2];
82	int keyid[2];
83	int once;
84	struct stinfo {
85		Block		str_output;
86		Block		str_feed;
87		Block		str_iv;
88		Block		str_ikey;
89		Schedule	str_sched;
90		int		str_index;
91		int		str_flagshift;
92	} streams[2];
93};
94
95static struct fb fb[2];
96
97struct keyidlist {
98	const char *keyid;
99	int	keyidlen;
100	char	*key;
101	int	keylen;
102	int	flags;
103} keyidlist [] = {
104	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
105	{ 0, 0, 0, 0, 0 }
106};
107
108#define	KEYFLAG_MASK	03
109
110#define	KEYFLAG_NOINIT	00
111#define	KEYFLAG_INIT	01
112#define	KEYFLAG_OK	02
113#define	KEYFLAG_BAD	03
114
115#define	KEYFLAG_SHIFT	2
116
117#define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
118
119#define	FB64_IV		1
120#define	FB64_IV_OK	2
121#define	FB64_IV_BAD	3
122
123
124void fb64_stream_iv(Block, struct stinfo *);
125void fb64_init(struct fb *);
126static int fb64_start(struct fb *, int, int);
127int fb64_is(unsigned char *, int, struct fb *);
128int fb64_reply(unsigned char *, int, struct fb *);
129static void fb64_session(Session_Key *, int, struct fb *);
130void fb64_stream_key(Block, struct stinfo *);
131int fb64_keyid(int, unsigned char *, int *, struct fb *);
132
133void
134cfb64_init(int server __unused)
135{
136	fb64_init(&fb[CFB]);
137	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
138	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
139	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
140}
141
142void
143ofb64_init(int server __unused)
144{
145	fb64_init(&fb[OFB]);
146	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
147	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
148	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
149}
150
151void
152fb64_init(struct fb *fbp)
153{
154	memset((void *)fbp, 0, sizeof(*fbp));
155	fbp->state[0] = fbp->state[1] = FAILED;
156	fbp->fb_feed[0] = IAC;
157	fbp->fb_feed[1] = SB;
158	fbp->fb_feed[2] = TELOPT_ENCRYPT;
159	fbp->fb_feed[3] = ENCRYPT_IS;
160}
161
162/*
163 * Returns:
164 *	-1: some error.  Negotiation is done, encryption not ready.
165 *	 0: Successful, initial negotiation all done.
166 *	 1: successful, negotiation not done yet.
167 *	 2: Not yet.  Other things (like getting the key from
168 *	    Kerberos) have to happen before we can continue.
169 */
170int
171cfb64_start(int dir, int server)
172{
173	return(fb64_start(&fb[CFB], dir, server));
174}
175
176int
177ofb64_start(int dir, int server)
178{
179	return(fb64_start(&fb[OFB], dir, server));
180}
181
182static int
183fb64_start(struct fb *fbp, int dir, int server __unused)
184{
185	size_t x;
186	unsigned char *p;
187	int state;
188
189	switch (dir) {
190	case DIR_DECRYPT:
191		/*
192		 * This is simply a request to have the other side
193		 * start output (our input).  He will negotiate an
194		 * IV so we need not look for it.
195		 */
196		state = fbp->state[dir-1];
197		if (state == FAILED)
198			state = IN_PROGRESS;
199		break;
200
201	case DIR_ENCRYPT:
202		state = fbp->state[dir-1];
203		if (state == FAILED)
204			state = IN_PROGRESS;
205		else if ((state & NO_SEND_IV) == 0)
206			break;
207
208		if (!VALIDKEY(fbp->krbdes_key)) {
209			fbp->need_start = 1;
210			break;
211		}
212		state &= ~NO_SEND_IV;
213		state |= NO_RECV_IV;
214		if (encrypt_debug_mode)
215			printf("Creating new feed\r\n");
216		/*
217		 * Create a random feed and send it over.
218		 */
219		des_new_random_key(fbp->temp_feed);
220		des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed,
221				fbp->krbdes_sched, 1);
222		p = fbp->fb_feed + 3;
223		*p++ = ENCRYPT_IS;
224		p++;
225		*p++ = FB64_IV;
226		for (x = 0; x < sizeof(Block); ++x) {
227			if ((*p++ = fbp->temp_feed[x]) == IAC)
228				*p++ = IAC;
229		}
230		*p++ = IAC;
231		*p++ = SE;
232		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
233		net_write(fbp->fb_feed, p - fbp->fb_feed);
234		break;
235	default:
236		return(FAILED);
237	}
238	return(fbp->state[dir-1] = state);
239}
240
241/*
242 * Returns:
243 *	-1: some error.  Negotiation is done, encryption not ready.
244 *	 0: Successful, initial negotiation all done.
245 *	 1: successful, negotiation not done yet.
246 */
247int
248cfb64_is(unsigned char *data, int cnt)
249{
250	return(fb64_is(data, cnt, &fb[CFB]));
251}
252
253int
254ofb64_is(unsigned char *data, int cnt)
255{
256	return(fb64_is(data, cnt, &fb[OFB]));
257}
258
259int
260fb64_is(unsigned char *data, int cnt, struct fb *fbp)
261{
262	unsigned char *p;
263	int state = fbp->state[DIR_DECRYPT-1];
264
265	if (cnt-- < 1)
266		goto failure;
267
268	switch (*data++) {
269	case FB64_IV:
270		if (cnt != sizeof(Block)) {
271			if (encrypt_debug_mode)
272				printf("CFB64: initial vector failed on size\r\n");
273			state = FAILED;
274			goto failure;
275		}
276
277		if (encrypt_debug_mode)
278			printf("CFB64: initial vector received\r\n");
279
280		if (encrypt_debug_mode)
281			printf("Initializing Decrypt stream\r\n");
282
283		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
284
285		p = fbp->fb_feed + 3;
286		*p++ = ENCRYPT_REPLY;
287		p++;
288		*p++ = FB64_IV_OK;
289		*p++ = IAC;
290		*p++ = SE;
291		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
292		net_write(fbp->fb_feed, p - fbp->fb_feed);
293
294		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
295		break;
296
297	default:
298		if (encrypt_debug_mode) {
299			printf("Unknown option type: %d\r\n", *(data-1));
300			printd(data, cnt);
301			printf("\r\n");
302		}
303		/* FALL THROUGH */
304	failure:
305		/*
306		 * We failed.  Send an FB64_IV_BAD option
307		 * to the other side so it will know that
308		 * things failed.
309		 */
310		p = fbp->fb_feed + 3;
311		*p++ = ENCRYPT_REPLY;
312		p++;
313		*p++ = FB64_IV_BAD;
314		*p++ = IAC;
315		*p++ = SE;
316		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
317		net_write(fbp->fb_feed, p - fbp->fb_feed);
318
319		break;
320	}
321	return(fbp->state[DIR_DECRYPT-1] = state);
322}
323
324/*
325 * Returns:
326 *	-1: some error.  Negotiation is done, encryption not ready.
327 *	 0: Successful, initial negotiation all done.
328 *	 1: successful, negotiation not done yet.
329 */
330int
331cfb64_reply(unsigned char *data, int cnt)
332{
333	return(fb64_reply(data, cnt, &fb[CFB]));
334}
335
336int
337ofb64_reply(unsigned char *data, int cnt)
338{
339	return(fb64_reply(data, cnt, &fb[OFB]));
340}
341
342int
343fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
344{
345	int state = fbp->state[DIR_ENCRYPT-1];
346
347	if (cnt-- < 1)
348		goto failure;
349
350	switch (*data++) {
351	case FB64_IV_OK:
352		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
353		if (state == FAILED)
354			state = IN_PROGRESS;
355		state &= ~NO_RECV_IV;
356		encrypt_send_keyid(DIR_ENCRYPT, "\0", 1, 1);
357		break;
358
359	case FB64_IV_BAD:
360		memset(fbp->temp_feed, 0, sizeof(Block));
361		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
362		state = FAILED;
363		break;
364
365	default:
366		if (encrypt_debug_mode) {
367			printf("Unknown option type: %d\r\n", data[-1]);
368			printd(data, cnt);
369			printf("\r\n");
370		}
371		/* FALL THROUGH */
372	failure:
373		state = FAILED;
374		break;
375	}
376	return(fbp->state[DIR_ENCRYPT-1] = state);
377}
378
379void
380cfb64_session(Session_Key *key, int server)
381{
382	fb64_session(key, server, &fb[CFB]);
383}
384
385void
386ofb64_session(Session_Key *key, int server)
387{
388	fb64_session(key, server, &fb[OFB]);
389}
390
391static void
392fb64_session(Session_Key *key, int server, struct fb *fbp)
393{
394	if (!key || key->type != SK_DES) {
395		if (encrypt_debug_mode)
396			printf("Can't set krbdes's session key (%d != %d)\r\n",
397				key ? key->type : -1, SK_DES);
398		return;
399	}
400	memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
401
402	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
403	fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
404
405	if (fbp->once == 0) {
406		des_set_random_generator_seed(fbp->krbdes_key);
407		fbp->once = 1;
408	}
409	des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
410	/*
411	 * Now look to see if krbdes_start() was was waiting for
412	 * the key to show up.  If so, go ahead an call it now
413	 * that we have the key.
414	 */
415	if (fbp->need_start) {
416		fbp->need_start = 0;
417		fb64_start(fbp, DIR_ENCRYPT, server);
418	}
419}
420
421/*
422 * We only accept a keyid of 0.  If we get a keyid of
423 * 0, then mark the state as SUCCESS.
424 */
425int
426cfb64_keyid(int dir, unsigned char *kp, int *lenp)
427{
428	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
429}
430
431int
432ofb64_keyid(int dir, unsigned char *kp, int *lenp)
433{
434	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
435}
436
437int
438fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
439{
440	int state = fbp->state[dir-1];
441
442	if (*lenp != 1 || (*kp != '\0')) {
443		*lenp = 0;
444		return(state);
445	}
446
447	if (state == FAILED)
448		state = IN_PROGRESS;
449
450	state &= ~NO_KEYID;
451
452	return(fbp->state[dir-1] = state);
453}
454
455void
456fb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen, const char *type)
457{
458	char lbuf[32];
459	int i;
460	char *cp;
461
462	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
463	buflen -= 1;
464
465	switch(data[2]) {
466	case FB64_IV:
467		sprintf(lbuf, "%s_IV", type);
468		cp = lbuf;
469		goto common;
470
471	case FB64_IV_OK:
472		sprintf(lbuf, "%s_IV_OK", type);
473		cp = lbuf;
474		goto common;
475
476	case FB64_IV_BAD:
477		sprintf(lbuf, "%s_IV_BAD", type);
478		cp = lbuf;
479		goto common;
480
481	default:
482		sprintf(lbuf, " %d (unknown)", data[2]);
483		cp = lbuf;
484	common:
485		for (; (buflen > 0) && (*buf = *cp++); buf++)
486			buflen--;
487		for (i = 3; i < cnt; i++) {
488			sprintf(lbuf, " %d", data[i]);
489			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
490				buflen--;
491		}
492		break;
493	}
494}
495
496void
497cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
498{
499	fb64_printsub(data, cnt, buf, buflen, "CFB64");
500}
501
502void
503ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
504{
505	fb64_printsub(data, cnt, buf, buflen, "OFB64");
506}
507
508void
509fb64_stream_iv(Block seed, struct stinfo *stp)
510{
511
512	memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
513	memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
514
515	des_key_sched(stp->str_ikey, stp->str_sched);
516
517	stp->str_index = sizeof(Block);
518}
519
520void
521fb64_stream_key(Block key, struct stinfo *stp)
522{
523	memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
524	des_key_sched(key, stp->str_sched);
525
526	memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
527
528	stp->str_index = sizeof(Block);
529}
530
531/*
532 * DES 64 bit Cipher Feedback
533 *
534 *     key --->+-----+
535 *          +->| DES |--+
536 *          |  +-----+  |
537 *	    |           v
538 *  INPUT --(--------->(+)+---> DATA
539 *          |             |
540 *	    +-------------+
541 *
542 *
543 * Given:
544 *	iV: Initial vector, 64 bits (8 bytes) long.
545 *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
546 *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
547 *
548 *	V0 = DES(iV, key)
549 *	On = Dn ^ Vn
550 *	V(n+1) = DES(On, key)
551 */
552
553void
554cfb64_encrypt(unsigned char *s, int c)
555{
556	struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
557	int idx;
558
559	idx = stp->str_index;
560	while (c-- > 0) {
561		if (idx == sizeof(Block)) {
562			Block b;
563			des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
564			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
565			idx = 0;
566		}
567
568		/* On encryption, we store (feed ^ data) which is cypher */
569		*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
570		s++;
571		idx++;
572	}
573	stp->str_index = idx;
574}
575
576int
577cfb64_decrypt(int data)
578{
579	struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
580	int idx;
581
582	if (data == -1) {
583		/*
584		 * Back up one byte.  It is assumed that we will
585		 * never back up more than one byte.  If we do, this
586		 * may or may not work.
587		 */
588		if (stp->str_index)
589			--stp->str_index;
590		return(0);
591	}
592
593	idx = stp->str_index++;
594	if (idx == sizeof(Block)) {
595		Block b;
596		des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
597		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
598		stp->str_index = 1;	/* Next time will be 1 */
599		idx = 0;		/* But now use 0 */
600	}
601
602	/* On decryption we store (data) which is cypher. */
603	stp->str_output[idx] = data;
604	return(data ^ stp->str_feed[idx]);
605}
606
607/*
608 * DES 64 bit Output Feedback
609 *
610 * key --->+-----+
611 *	+->| DES |--+
612 *	|  +-----+  |
613 *	+-----------+
614 *	            v
615 *  INPUT -------->(+) ----> DATA
616 *
617 * Given:
618 *	iV: Initial vector, 64 bits (8 bytes) long.
619 *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
620 *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
621 *
622 *	V0 = DES(iV, key)
623 *	V(n+1) = DES(Vn, key)
624 *	On = Dn ^ Vn
625 */
626void
627ofb64_encrypt(unsigned char *s, int c)
628{
629	struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
630	int idx;
631
632	idx = stp->str_index;
633	while (c-- > 0) {
634		if (idx == sizeof(Block)) {
635			Block b;
636			des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
637			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
638			idx = 0;
639		}
640		*s++ ^= stp->str_feed[idx];
641		idx++;
642	}
643	stp->str_index = idx;
644}
645
646int
647ofb64_decrypt(int data)
648{
649	struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
650	int idx;
651
652	if (data == -1) {
653		/*
654		 * Back up one byte.  It is assumed that we will
655		 * never back up more than one byte.  If we do, this
656		 * may or may not work.
657		 */
658		if (stp->str_index)
659			--stp->str_index;
660		return(0);
661	}
662
663	idx = stp->str_index++;
664	if (idx == sizeof(Block)) {
665		Block b;
666		des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
667		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
668		stp->str_index = 1;	/* Next time will be 1 */
669		idx = 0;		/* But now use 0 */
670	}
671
672	return(data ^ stp->str_feed[idx]);
673}
674# endif	/* AUTHENTICATION */
675#endif	/* ENCRYPTION */
676