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