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