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