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