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