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