]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/telnet/libtelnet/enc_des.c
This commit was generated by cvs2svn to compensate for changes in r97241,
[FreeBSD/FreeBSD.git] / contrib / telnet / libtelnet / enc_des.c
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$
34  */
35
36 #include <sys/cdefs.h>
37
38 __FBSDID("$FreeBSD$");
39
40 #ifndef lint
41 static 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
56 extern int encrypt_debug_mode;
57 void 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
70 struct 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
90 static struct fb fb[2];
91
92 struct 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
119 void fb64_stream_iv(Block, struct stinfo *);
120 void fb64_init(struct fb *);
121 static int fb64_start(struct fb *, int, int);
122 int fb64_is(unsigned char *, int, struct fb *);
123 int fb64_reply(unsigned char *, int, struct fb *);
124 static void fb64_session(Session_Key *, int, struct fb *);
125 void fb64_stream_key(Block, struct stinfo *);
126 int fb64_keyid(int, unsigned char *, int *, struct fb *);
127
128 void
129 cfb64_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
137 void
138 ofb64_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
146 void
147 fb64_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  */
165 int
166 cfb64_start(int dir, int server)
167 {
168         return(fb64_start(&fb[CFB], dir, server));
169 }
170
171 int
172 ofb64_start(int dir, int server)
173 {
174         return(fb64_start(&fb[OFB], dir, server));
175 }
176
177 static int
178 fb64_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  */
242 int
243 cfb64_is(unsigned char *data, int cnt)
244 {
245         return(fb64_is(data, cnt, &fb[CFB]));
246 }
247
248 int
249 ofb64_is(unsigned char *data, int cnt)
250 {
251         return(fb64_is(data, cnt, &fb[OFB]));
252 }
253
254 int
255 fb64_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  */
325 int
326 cfb64_reply(unsigned char *data, int cnt)
327 {
328         return(fb64_reply(data, cnt, &fb[CFB]));
329 }
330
331 int
332 ofb64_reply(unsigned char *data, int cnt)
333 {
334         return(fb64_reply(data, cnt, &fb[OFB]));
335 }
336
337 int
338 fb64_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
374 void
375 cfb64_session(Session_Key *key, int server)
376 {
377         fb64_session(key, server, &fb[CFB]);
378 }
379
380 void
381 ofb64_session(Session_Key *key, int server)
382 {
383         fb64_session(key, server, &fb[OFB]);
384 }
385
386 static void
387 fb64_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  */
420 int
421 cfb64_keyid(int dir, unsigned char *kp, int *lenp)
422 {
423         return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
424 }
425
426 int
427 ofb64_keyid(int dir, unsigned char *kp, int *lenp)
428 {
429         return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
430 }
431
432 int
433 fb64_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
450 void
451 fb64_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
491 void
492 cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
493 {
494         fb64_printsub(data, cnt, buf, buflen, "CFB64");
495 }
496
497 void
498 ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
499 {
500         fb64_printsub(data, cnt, buf, buflen, "OFB64");
501 }
502
503 void
504 fb64_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
515 void
516 fb64_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
548 void
549 cfb64_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
571 int
572 cfb64_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  */
621 void
622 ofb64_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
641 int
642 ofb64_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 */