des.c revision 306195
1/* crypto/des/des.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <openssl/opensslconf.h> 63#ifndef OPENSSL_SYS_MSDOS 64# ifndef OPENSSL_SYS_VMS 65# include OPENSSL_UNISTD 66# else /* OPENSSL_SYS_VMS */ 67# ifdef __DECC 68# include <unistd.h> 69# else /* not __DECC */ 70# include <math.h> 71# endif /* __DECC */ 72# endif /* OPENSSL_SYS_VMS */ 73#else /* OPENSSL_SYS_MSDOS */ 74# include <io.h> 75#endif 76 77#include <time.h> 78#include "des_ver.h" 79 80#ifdef OPENSSL_SYS_VMS 81# include <types.h> 82# include <stat.h> 83#else 84# ifndef _IRIX 85# include <sys/types.h> 86# endif 87# include <sys/stat.h> 88#endif 89#include <openssl/des.h> 90#include <openssl/rand.h> 91#include <openssl/ui_compat.h> 92 93void usage(void); 94void doencryption(void); 95int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp); 96void uufwriteEnd(FILE *fp); 97int uufread(unsigned char *out, int size, unsigned int num, FILE *fp); 98int uuencode(unsigned char *in, int num, unsigned char *out); 99int uudecode(unsigned char *in, int num, unsigned char *out); 100void DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length, 101 DES_key_schedule sk1, DES_key_schedule sk2, 102 DES_cblock *ivec1, DES_cblock *ivec2, int enc); 103#ifdef OPENSSL_SYS_VMS 104# define EXIT(a) exit(a&0x10000000L) 105#else 106# define EXIT(a) exit(a) 107#endif 108 109#define BUFSIZE (8*1024) 110#define VERIFY 1 111#define KEYSIZ 8 112#define KEYSIZB 1024 /* should hit tty line limit first :-) */ 113char key[KEYSIZB + 1]; 114int do_encrypt, longk = 0; 115FILE *DES_IN, *DES_OUT, *CKSUM_OUT; 116char uuname[200]; 117unsigned char uubuf[50]; 118int uubufnum = 0; 119#define INUUBUFN (45*100) 120#define OUTUUBUF (65*100) 121unsigned char b[OUTUUBUF]; 122unsigned char bb[300]; 123DES_cblock cksum = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 124 125char cksumname[200] = ""; 126 127int vflag, cflag, eflag, dflag, kflag, bflag, fflag, sflag, uflag, flag3, 128 hflag, error; 129 130int main(int argc, char **argv) 131{ 132 int i; 133 struct stat ins, outs; 134 char *p; 135 char *in = NULL, *out = NULL; 136 137 vflag = cflag = eflag = dflag = kflag = hflag = bflag = fflag = sflag = 138 uflag = flag3 = 0; 139 error = 0; 140 memset(key, 0, sizeof(key)); 141 142 for (i = 1; i < argc; i++) { 143 p = argv[i]; 144 if ((p[0] == '-') && (p[1] != '\0')) { 145 p++; 146 while (*p) { 147 switch (*(p++)) { 148 case '3': 149 flag3 = 1; 150 longk = 1; 151 break; 152 case 'c': 153 cflag = 1; 154 strncpy(cksumname, p, 200); 155 cksumname[sizeof(cksumname) - 1] = '\0'; 156 p += strlen(cksumname); 157 break; 158 case 'C': 159 cflag = 1; 160 longk = 1; 161 strncpy(cksumname, p, 200); 162 cksumname[sizeof(cksumname) - 1] = '\0'; 163 p += strlen(cksumname); 164 break; 165 case 'e': 166 eflag = 1; 167 break; 168 case 'v': 169 vflag = 1; 170 break; 171 case 'E': 172 eflag = 1; 173 longk = 1; 174 break; 175 case 'd': 176 dflag = 1; 177 break; 178 case 'D': 179 dflag = 1; 180 longk = 1; 181 break; 182 case 'b': 183 bflag = 1; 184 break; 185 case 'f': 186 fflag = 1; 187 break; 188 case 's': 189 sflag = 1; 190 break; 191 case 'u': 192 uflag = 1; 193 strncpy(uuname, p, 200); 194 uuname[sizeof(uuname) - 1] = '\0'; 195 p += strlen(uuname); 196 break; 197 case 'h': 198 hflag = 1; 199 break; 200 case 'k': 201 kflag = 1; 202 if ((i + 1) == argc) { 203 fputs("must have a key with the -k option\n", stderr); 204 error = 1; 205 } else { 206 int j; 207 208 i++; 209 strncpy(key, argv[i], KEYSIZB); 210 for (j = strlen(argv[i]) - 1; j >= 0; j--) 211 argv[i][j] = '\0'; 212 } 213 break; 214 default: 215 fprintf(stderr, "'%c' unknown flag\n", p[-1]); 216 error = 1; 217 break; 218 } 219 } 220 } else { 221 if (in == NULL) 222 in = argv[i]; 223 else if (out == NULL) 224 out = argv[i]; 225 else 226 error = 1; 227 } 228 } 229 if (error) 230 usage(); 231 /*- 232 * We either 233 * do checksum or 234 * do encrypt or 235 * do decrypt or 236 * do decrypt then ckecksum or 237 * do checksum then encrypt 238 */ 239 if (((eflag + dflag) == 1) || cflag) { 240 if (eflag) 241 do_encrypt = DES_ENCRYPT; 242 if (dflag) 243 do_encrypt = DES_DECRYPT; 244 } else { 245 if (vflag) { 246#ifndef _Windows 247 fprintf(stderr, "des(1) built with %s\n", libdes_version); 248#endif 249 EXIT(1); 250 } else 251 usage(); 252 } 253 254#ifndef _Windows 255 if (vflag) 256 fprintf(stderr, "des(1) built with %s\n", libdes_version); 257#endif 258 if ((in != NULL) && (out != NULL) && 259#ifndef OPENSSL_SYS_MSDOS 260 (stat(in, &ins) != -1) && 261 (stat(out, &outs) != -1) && 262 (ins.st_dev == outs.st_dev) && (ins.st_ino == outs.st_ino)) 263#else /* OPENSSL_SYS_MSDOS */ 264 (strcmp(in, out) == 0)) 265#endif 266 { 267 fputs("input and output file are the same\n", stderr); 268 EXIT(3); 269 } 270 271 if (!kflag) 272 if (des_read_pw_string 273 (key, KEYSIZB + 1, "Enter key:", eflag ? VERIFY : 0)) { 274 fputs("password error\n", stderr); 275 EXIT(2); 276 } 277 278 if (in == NULL) 279 DES_IN = stdin; 280 else if ((DES_IN = fopen(in, "r")) == NULL) { 281 perror("opening input file"); 282 EXIT(4); 283 } 284 285 CKSUM_OUT = stdout; 286 if (out == NULL) { 287 DES_OUT = stdout; 288 CKSUM_OUT = stderr; 289 } else if ((DES_OUT = fopen(out, "w")) == NULL) { 290 perror("opening output file"); 291 EXIT(5); 292 } 293#ifdef OPENSSL_SYS_MSDOS 294 /* This should set the file to binary mode. */ 295 { 296# include <fcntl.h> 297 if (!(uflag && dflag)) 298 setmode(fileno(DES_IN), O_BINARY); 299 if (!(uflag && eflag)) 300 setmode(fileno(DES_OUT), O_BINARY); 301 } 302#endif 303 304 doencryption(); 305 fclose(DES_IN); 306 fclose(DES_OUT); 307 EXIT(0); 308} 309 310void usage(void) 311{ 312 char **u; 313 static const char *Usage[] = { 314 "des <options> [input-file [output-file]]", 315 "options:", 316 "-v : des(1) version number", 317 "-e : encrypt using SunOS compatible user key to DES key conversion.", 318 "-E : encrypt ", 319 "-d : decrypt using SunOS compatible user key to DES key conversion.", 320 "-D : decrypt ", 321 "-c[ckname] : generate a cbc_cksum using SunOS compatible user key to", 322 " DES key conversion and output to ckname (stdout default,", 323 " stderr if data being output on stdout). The checksum is", 324 " generated before encryption and after decryption if used", 325 " in conjunction with -[eEdD].", 326 "-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].", 327 "-k key : use key 'key'", 328 "-h : the key that is entered will be a hexadecimal number", 329 " that is used directly as the des key", 330 "-u[uuname] : input file is uudecoded if -[dD] or output uuencoded data if -[eE]", 331 " (uuname is the filename to put in the uuencode header).", 332 "-b : encrypt using DES in ecb encryption mode, the default is cbc mode.", 333 "-3 : encrypt using triple DES encryption. This uses 2 keys", 334 " generated from the input key. If the input key is less", 335 " than 8 characters long, this is equivalent to normal", 336 " encryption. Default is triple cbc, -b makes it triple ecb.", 337 NULL 338 }; 339 for (u = (char **)Usage; *u; u++) { 340 fputs(*u, stderr); 341 fputc('\n', stderr); 342 } 343 344 EXIT(1); 345} 346 347void doencryption(void) 348{ 349#ifdef _LIBC 350 extern unsigned long time(); 351#endif 352 353 register int i; 354 DES_key_schedule ks, ks2; 355 DES_cblock iv, iv2; 356 char *p; 357 int num = 0, j, k, l, rem, ll, len, last, ex = 0; 358 DES_cblock kk, k2; 359 FILE *O; 360 int Exit = 0; 361#ifndef OPENSSL_SYS_MSDOS 362 static unsigned char buf[BUFSIZE + 8], obuf[BUFSIZE + 8]; 363#else 364 static unsigned char *buf = NULL, *obuf = NULL; 365 366 if (buf == NULL) { 367 if (((buf = OPENSSL_malloc(BUFSIZE + 8)) == NULL) || 368 ((obuf = OPENSSL_malloc(BUFSIZE + 8)) == NULL)) { 369 fputs("Not enough memory\n", stderr); 370 Exit = 10; 371 goto problems; 372 } 373 } 374#endif 375 376 if (hflag) { 377 j = (flag3 ? 16 : 8); 378 p = key; 379 for (i = 0; i < j; i++) { 380 k = 0; 381 if ((*p <= '9') && (*p >= '0')) 382 k = (*p - '0') << 4; 383 else if ((*p <= 'f') && (*p >= 'a')) 384 k = (*p - 'a' + 10) << 4; 385 else if ((*p <= 'F') && (*p >= 'A')) 386 k = (*p - 'A' + 10) << 4; 387 else { 388 fputs("Bad hex key\n", stderr); 389 Exit = 9; 390 goto problems; 391 } 392 p++; 393 if ((*p <= '9') && (*p >= '0')) 394 k |= (*p - '0'); 395 else if ((*p <= 'f') && (*p >= 'a')) 396 k |= (*p - 'a' + 10); 397 else if ((*p <= 'F') && (*p >= 'A')) 398 k |= (*p - 'A' + 10); 399 else { 400 fputs("Bad hex key\n", stderr); 401 Exit = 9; 402 goto problems; 403 } 404 p++; 405 if (i < 8) 406 kk[i] = k; 407 else 408 k2[i - 8] = k; 409 } 410 DES_set_key_unchecked(&k2, &ks2); 411 OPENSSL_cleanse(k2, sizeof(k2)); 412 } else if (longk || flag3) { 413 if (flag3) { 414 DES_string_to_2keys(key, &kk, &k2); 415 DES_set_key_unchecked(&k2, &ks2); 416 OPENSSL_cleanse(k2, sizeof(k2)); 417 } else 418 DES_string_to_key(key, &kk); 419 } else 420 for (i = 0; i < KEYSIZ; i++) { 421 l = 0; 422 k = key[i]; 423 for (j = 0; j < 8; j++) { 424 if (k & 1) 425 l++; 426 k >>= 1; 427 } 428 if (l & 1) 429 kk[i] = key[i] & 0x7f; 430 else 431 kk[i] = key[i] | 0x80; 432 } 433 434 DES_set_key_unchecked(&kk, &ks); 435 OPENSSL_cleanse(key, sizeof(key)); 436 OPENSSL_cleanse(kk, sizeof(kk)); 437 /* woops - A bug that does not showup under unix :-( */ 438 memset(iv, 0, sizeof(iv)); 439 memset(iv2, 0, sizeof(iv2)); 440 441 l = 1; 442 rem = 0; 443 /* first read */ 444 if (eflag || (!dflag && cflag)) { 445 for (;;) { 446 num = l = fread(&(buf[rem]), 1, BUFSIZE, DES_IN); 447 l += rem; 448 num += rem; 449 if (l < 0) { 450 perror("read error"); 451 Exit = 6; 452 goto problems; 453 } 454 455 rem = l % 8; 456 len = l - rem; 457 if (feof(DES_IN)) { 458 for (i = 7 - rem; i > 0; i--) { 459 if (RAND_bytes(buf + l++, 1) <= 0) 460 goto problems; 461 } 462 buf[l++] = rem; 463 ex = 1; 464 len += rem; 465 } else 466 l -= rem; 467 468 if (cflag) { 469 DES_cbc_cksum(buf, &cksum, (long)len, &ks, &cksum); 470 if (!eflag) { 471 if (feof(DES_IN)) 472 break; 473 else 474 continue; 475 } 476 } 477 478 if (bflag && !flag3) 479 for (i = 0; i < l; i += 8) 480 DES_ecb_encrypt((DES_cblock *)&(buf[i]), 481 (DES_cblock *)&(obuf[i]), 482 &ks, do_encrypt); 483 else if (flag3 && bflag) 484 for (i = 0; i < l; i += 8) 485 DES_ecb2_encrypt((DES_cblock *)&(buf[i]), 486 (DES_cblock *)&(obuf[i]), 487 &ks, &ks2, do_encrypt); 488 else if (flag3 && !bflag) { 489 char tmpbuf[8]; 490 491 if (rem) 492 memcpy(tmpbuf, &(buf[l]), (unsigned int)rem); 493 DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf, 494 (long)l, ks, ks2, &iv, &iv2, do_encrypt); 495 if (rem) 496 memcpy(&(buf[l]), tmpbuf, (unsigned int)rem); 497 } else { 498 DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt); 499 if (l >= 8) 500 memcpy(iv, &(obuf[l - 8]), 8); 501 } 502 if (rem) 503 memcpy(buf, &(buf[l]), (unsigned int)rem); 504 505 i = 0; 506 while (i < l) { 507 if (uflag) 508 j = uufwrite(obuf, 1, (unsigned int)l - i, DES_OUT); 509 else 510 j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT); 511 if (j == -1) { 512 perror("Write error"); 513 Exit = 7; 514 goto problems; 515 } 516 i += j; 517 } 518 if (feof(DES_IN)) { 519 if (uflag) 520 uufwriteEnd(DES_OUT); 521 break; 522 } 523 } 524 } else { /* decrypt */ 525 526 ex = 1; 527 for (;;) { 528 if (ex) { 529 if (uflag) 530 l = uufread(buf, 1, BUFSIZE, DES_IN); 531 else 532 l = fread(buf, 1, BUFSIZE, DES_IN); 533 ex = 0; 534 rem = l % 8; 535 l -= rem; 536 } 537 if (l < 0) { 538 perror("read error"); 539 Exit = 6; 540 goto problems; 541 } 542 543 if (bflag && !flag3) 544 for (i = 0; i < l; i += 8) 545 DES_ecb_encrypt((DES_cblock *)&(buf[i]), 546 (DES_cblock *)&(obuf[i]), 547 &ks, do_encrypt); 548 else if (flag3 && bflag) 549 for (i = 0; i < l; i += 8) 550 DES_ecb2_encrypt((DES_cblock *)&(buf[i]), 551 (DES_cblock *)&(obuf[i]), 552 &ks, &ks2, do_encrypt); 553 else if (flag3 && !bflag) { 554 DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf, 555 (long)l, ks, ks2, &iv, &iv2, do_encrypt); 556 } else { 557 DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt); 558 if (l >= 8) 559 memcpy(iv, &(buf[l - 8]), 8); 560 } 561 562 if (uflag) 563 ll = uufread(&(buf[rem]), 1, BUFSIZE, DES_IN); 564 else 565 ll = fread(&(buf[rem]), 1, BUFSIZE, DES_IN); 566 ll += rem; 567 rem = ll % 8; 568 ll -= rem; 569 if (feof(DES_IN) && (ll == 0)) { 570 last = obuf[l - 1]; 571 572 if ((last > 7) || (last < 0)) { 573 fputs("The file was not decrypted correctly.\n", stderr); 574 Exit = 8; 575 last = 0; 576 } 577 l = l - 8 + last; 578 } 579 i = 0; 580 if (cflag) 581 DES_cbc_cksum(obuf, 582 (DES_cblock *)cksum, (long)l / 8 * 8, &ks, 583 (DES_cblock *)cksum); 584 while (i != l) { 585 j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT); 586 if (j == -1) { 587 perror("Write error"); 588 Exit = 7; 589 goto problems; 590 } 591 i += j; 592 } 593 l = ll; 594 if ((l == 0) && feof(DES_IN)) 595 break; 596 } 597 } 598 if (cflag) { 599 l = 0; 600 if (cksumname[0] != '\0') { 601 if ((O = fopen(cksumname, "w")) != NULL) { 602 CKSUM_OUT = O; 603 l = 1; 604 } 605 } 606 for (i = 0; i < 8; i++) 607 fprintf(CKSUM_OUT, "%02X", cksum[i]); 608 fprintf(CKSUM_OUT, "\n"); 609 if (l) 610 fclose(CKSUM_OUT); 611 } 612 problems: 613 OPENSSL_cleanse(buf, sizeof(buf)); 614 OPENSSL_cleanse(obuf, sizeof(obuf)); 615 OPENSSL_cleanse(&ks, sizeof(ks)); 616 OPENSSL_cleanse(&ks2, sizeof(ks2)); 617 OPENSSL_cleanse(iv, sizeof(iv)); 618 OPENSSL_cleanse(iv2, sizeof(iv2)); 619 OPENSSL_cleanse(kk, sizeof(kk)); 620 OPENSSL_cleanse(k2, sizeof(k2)); 621 OPENSSL_cleanse(uubuf, sizeof(uubuf)); 622 OPENSSL_cleanse(b, sizeof(b)); 623 OPENSSL_cleanse(bb, sizeof(bb)); 624 OPENSSL_cleanse(cksum, sizeof(cksum)); 625 if (Exit) 626 EXIT(Exit); 627} 628 629/* We ignore this parameter but it should be > ~50 I believe */ 630int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp) 631{ 632 int i, j, left, rem, ret = num; 633 static int start = 1; 634 635 if (start) { 636 fprintf(fp, "begin 600 %s\n", 637 (uuname[0] == '\0') ? "text.d" : uuname); 638 start = 0; 639 } 640 641 if (uubufnum) { 642 if (uubufnum + num < 45) { 643 memcpy(&(uubuf[uubufnum]), data, (unsigned int)num); 644 uubufnum += num; 645 return (num); 646 } else { 647 i = 45 - uubufnum; 648 memcpy(&(uubuf[uubufnum]), data, (unsigned int)i); 649 j = uuencode((unsigned char *)uubuf, 45, b); 650 fwrite(b, 1, (unsigned int)j, fp); 651 uubufnum = 0; 652 data += i; 653 num -= i; 654 } 655 } 656 657 for (i = 0; i < (((int)num) - INUUBUFN); i += INUUBUFN) { 658 j = uuencode(&(data[i]), INUUBUFN, b); 659 fwrite(b, 1, (unsigned int)j, fp); 660 } 661 rem = (num - i) % 45; 662 left = (num - i - rem); 663 if (left) { 664 j = uuencode(&(data[i]), left, b); 665 fwrite(b, 1, (unsigned int)j, fp); 666 i += left; 667 } 668 if (i != num) { 669 memcpy(uubuf, &(data[i]), (unsigned int)rem); 670 uubufnum = rem; 671 } 672 return (ret); 673} 674 675void uufwriteEnd(FILE *fp) 676{ 677 int j; 678 static const char *end = " \nend\n"; 679 680 if (uubufnum != 0) { 681 uubuf[uubufnum] = '\0'; 682 uubuf[uubufnum + 1] = '\0'; 683 uubuf[uubufnum + 2] = '\0'; 684 j = uuencode(uubuf, uubufnum, b); 685 fwrite(b, 1, (unsigned int)j, fp); 686 } 687 fwrite(end, 1, strlen(end), fp); 688} 689 690/* 691 * int size: should always be > ~ 60; I actually ignore this parameter :-) 692 */ 693int uufread(unsigned char *out, int size, unsigned int num, FILE *fp) 694{ 695 int i, j, tot; 696 static int done = 0; 697 static int valid = 0; 698 static int start = 1; 699 700 if (start) { 701 for (;;) { 702 b[0] = '\0'; 703 fgets((char *)b, 300, fp); 704 if (b[0] == '\0') { 705 fprintf(stderr, "no 'begin' found in uuencoded input\n"); 706 return (-1); 707 } 708 if (strncmp((char *)b, "begin ", 6) == 0) 709 break; 710 } 711 start = 0; 712 } 713 if (done) 714 return (0); 715 tot = 0; 716 if (valid) { 717 memcpy(out, bb, (unsigned int)valid); 718 tot = valid; 719 valid = 0; 720 } 721 for (;;) { 722 b[0] = '\0'; 723 fgets((char *)b, 300, fp); 724 if (b[0] == '\0') 725 break; 726 i = strlen((char *)b); 727 if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) { 728 done = 1; 729 while (!feof(fp)) { 730 fgets((char *)b, 300, fp); 731 } 732 break; 733 } 734 i = uudecode(b, i, bb); 735 if (i < 0) 736 break; 737 if ((i + tot + 8) > num) { 738 /* num to copy to make it a multiple of 8 */ 739 j = (num / 8 * 8) - tot - 8; 740 memcpy(&(out[tot]), bb, (unsigned int)j); 741 tot += j; 742 memcpy(bb, &(bb[j]), (unsigned int)i - j); 743 valid = i - j; 744 break; 745 } 746 memcpy(&(out[tot]), bb, (unsigned int)i); 747 tot += i; 748 } 749 return (tot); 750} 751 752#define ccc2l(c,l) (l =((DES_LONG)(*((c)++)))<<16, \ 753 l|=((DES_LONG)(*((c)++)))<< 8, \ 754 l|=((DES_LONG)(*((c)++)))) 755 756#define l2ccc(l,c) (*((c)++)=(unsigned char)(((l)>>16)&0xff), \ 757 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ 758 *((c)++)=(unsigned char)(((l) )&0xff)) 759 760int uuencode(unsigned char *in, int num, unsigned char *out) 761{ 762 int j, i, n, tot = 0; 763 DES_LONG l; 764 register unsigned char *p; 765 p = out; 766 767 for (j = 0; j < num; j += 45) { 768 if (j + 45 > num) 769 i = (num - j); 770 else 771 i = 45; 772 *(p++) = i + ' '; 773 for (n = 0; n < i; n += 3) { 774 ccc2l(in, l); 775 *(p++) = ((l >> 18) & 0x3f) + ' '; 776 *(p++) = ((l >> 12) & 0x3f) + ' '; 777 *(p++) = ((l >> 6) & 0x3f) + ' '; 778 *(p++) = ((l) & 0x3f) + ' '; 779 tot += 4; 780 } 781 *(p++) = '\n'; 782 tot += 2; 783 } 784 *p = '\0'; 785 l = 0; 786 return (tot); 787} 788 789int uudecode(unsigned char *in, int num, unsigned char *out) 790{ 791 int j, i, k; 792 unsigned int n = 0, space = 0; 793 DES_LONG l; 794 DES_LONG w, x, y, z; 795 unsigned int blank = (unsigned int)'\n' - ' '; 796 797 for (j = 0; j < num;) { 798 n = *(in++) - ' '; 799 if (n == blank) { 800 n = 0; 801 in--; 802 } 803 if (n > 60) { 804 fprintf(stderr, "uuencoded line length too long\n"); 805 return (-1); 806 } 807 j++; 808 809 for (i = 0; i < n; j += 4, i += 3) { 810 /* 811 * the following is for cases where spaces are removed from 812 * lines. 813 */ 814 if (space) { 815 w = x = y = z = 0; 816 } else { 817 w = *(in++) - ' '; 818 x = *(in++) - ' '; 819 y = *(in++) - ' '; 820 z = *(in++) - ' '; 821 } 822 if ((w > 63) || (x > 63) || (y > 63) || (z > 63)) { 823 k = 0; 824 if (w == blank) 825 k = 1; 826 if (x == blank) 827 k = 2; 828 if (y == blank) 829 k = 3; 830 if (z == blank) 831 k = 4; 832 space = 1; 833 switch (k) { 834 case 1: 835 w = 0; 836 in--; 837 case 2: 838 x = 0; 839 in--; 840 case 3: 841 y = 0; 842 in--; 843 case 4: 844 z = 0; 845 in--; 846 break; 847 case 0: 848 space = 0; 849 fprintf(stderr, "bad uuencoded data values\n"); 850 w = x = y = z = 0; 851 return (-1); 852 break; 853 } 854 } 855 l = (w << 18) | (x << 12) | (y << 6) | (z); 856 l2ccc(l, out); 857 } 858 if (*(in++) != '\n') { 859 fprintf(stderr, "missing nl in uuencoded line\n"); 860 w = x = y = z = 0; 861 return (-1); 862 } 863 j++; 864 } 865 *out = '\0'; 866 w = x = y = z = 0; 867 return (n); 868} 869