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