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