|
|
1.1 ! root 1: ! 2: /* ! 3: * Stealth V1.1 by Henry Hastur ! 4: * ! 5: * May or may not be covered by US ITAR encryption export regulations, if ! 6: * in doubt, don't export it. It would be pretty stupid if it was, but ! 7: * hey, governments have done some pretty stupid things before now.... ! 8: * ! 9: * This program is copyright Henry Hastur 1994, but may be freely distributed, ! 10: * modified, incorporated into other programs and used, as long as the ! 11: * copyright stays attached and you obey any relevant import or export ! 12: * restrictions on the code. No warranty is offered, and no responsibility ! 13: * is taken for any damage use of this program may cause. In other words, ! 14: * do what you want with it, but don't expect me to pay up if anything ! 15: * unexpected goes wrong - you're using it at your own risk... ! 16: * ! 17: */ ! 18: ! 19: #include <stdio.h> ! 20: #include <ctype.h> ! 21: #include <stdlib.h> ! 22: #ifndef DOS ! 23: #include <unistd.h> ! 24: #else ! 25: #include <fcntl.h> ! 26: #include <io.h> ! 27: #endif ! 28: #include <signal.h> ! 29: ! 30: /* Few definitions from PGP for its header/algorithm versions */ ! 31: ! 32: #define CURRENT_VERSION 0x02 ! 33: #define RSA_VERSION 0x01 ! 34: #define ID_SIZE 8 ! 35: ! 36: /* define TRUE and FALSE */ ! 37: ! 38: #define TRUE 1 ! 39: #define FALSE 0 ! 40: ! 41: /* A byte */ ! 42: ! 43: typedef unsigned char byte; ! 44: ! 45: /* Few global variables */ ! 46: ! 47: static int verbose = FALSE; ! 48: static int conventional = FALSE; ! 49: static int adding = FALSE; ! 50: static char file_name [1024]; ! 51: static int file_open = FALSE; ! 52: static FILE *afp; ! 53: ! 54: /* int_handler() - tidy up and exit */ ! 55: ! 56: static void int_handler(unused) ! 57: ! 58: int unused; ! 59: ! 60: { ! 61: long fpos; ! 62: ! 63: /* If we've still got a file open */ ! 64: ! 65: if (file_open) { ! 66: ! 67: /* If we can still write to it, erase it */ ! 68: ! 69: if (afp) { ! 70: fseek (afp, 0l, 2); ! 71: fpos = ftell (afp); ! 72: fseek (afp, 0l, 0); ! 73: ! 74: while (fpos --) ! 75: putc (0, afp); ! 76: } ! 77: ! 78: #ifndef UNIX ! 79: /* Finally unlink it */ ! 80: ! 81: unlink (file_name); ! 82: #endif ! 83: } ! 84: ! 85: exit (1); ! 86: } ! 87: ! 88: /* Read a PGP ctb-lengh */ ! 89: ! 90: static long read_length (c,fp) ! 91: ! 92: FILE *fp; ! 93: int c; ! 94: ! 95: { ! 96: static int bytes [] = { 1, 2, 4, 0 }; ! 97: long len = 0; ! 98: int n; ! 99: ! 100: n = bytes [c & 0x03]; ! 101: ! 102: if (!n) ! 103: return 0x7FFFFFFF; ! 104: ! 105: for (; n > 0 ; n--) { ! 106: len *= 256; ! 107: len += getc(fp); ! 108: } ! 109: ! 110: return len; ! 111: } ! 112: ! 113: /* Write a PGP ctb-length */ ! 114: ! 115: static void write_length (ctb,length,fp) ! 116: ! 117: int ctb; ! 118: unsigned long length; ! 119: FILE *fp; ! 120: ! 121: { ! 122: unsigned long mask; ! 123: int bytes, shift,c; ! 124: ! 125: ctb &= 0xFC; ! 126: ! 127: if (length < 256) { ! 128: mask = 0xFF; ! 129: bytes = 1; ! 130: shift = 0; ! 131: } ! 132: else if (length < 65536) { ! 133: mask = 0xFF00; ! 134: bytes = 2; ! 135: shift = 8; ! 136: ctb |= 1; ! 137: } ! 138: else { ! 139: mask = 0xFF000000; ! 140: shift = 24; ! 141: bytes = 4; ! 142: ctb |= 2; ! 143: } ! 144: ! 145: putc (ctb, fp); ! 146: ! 147: while (bytes-- > 0) { ! 148: c = ((length & mask) >> shift); ! 149: mask >>= 8; ! 150: shift -= 8; ! 151: ! 152: putc (c, fp); ! 153: } ! 154: } ! 155: ! 156: /* Hunt through pubring.pgp for the appropriate secret key */ ! 157: ! 158: #define ID_FROM_NAME 0 ! 159: #define LENGTH_FROM_ID 1 ! 160: ! 161: static int find_key_id(id,length,s,type) ! 162: ! 163: char *s; ! 164: byte *id; ! 165: int *length; ! 166: int type; ! 167: ! 168: { ! 169: char *path; ! 170: FILE *pub = NULL; ! 171: int c1, c2, len, i, klen, c; ! 172: long hex_id = (-1); ! 173: ! 174: /* Following are static only to reduce DOS stack requirements */ ! 175: ! 176: static char pub_name [1024]; ! 177: static char userid [256]; ! 178: ! 179: /* Find pubring.pgp */ ! 180: ! 181: if (path = getenv("PGPPATH")) { ! 182: sprintf (pub_name, "%s/pubring.pgp", path); ! 183: pub = fopen(pub_name, "rb"); ! 184: } ! 185: ! 186: if (!pub) ! 187: pub = fopen ("pubring.pgp", "rb"); ! 188: ! 189: if (!pub) { ! 190: fprintf (stderr,"Can't find pubring.pgp in $PGPPATH or . : exiting !\n"); ! 191: exit (1); ! 192: } ! 193: ! 194: /* Also allow for use of hex key id */ ! 195: ! 196: if (type == ID_FROM_NAME && !strncmp(s,"0x",2)) { ! 197: char *i; ! 198: int c; ! 199: ! 200: hex_id = 0l; ! 201: i = s + 2; ! 202: ! 203: while (*i) { ! 204: hex_id <<= 4; ! 205: c = tolower (*i); ! 206: ! 207: if (c >= '0' && c <= '9') { ! 208: hex_id += (c - '0'); ! 209: } ! 210: else if (c >= 'a' && c <= 'f') { ! 211: hex_id += (c + 10 - 'a'); ! 212: } ! 213: else { ! 214: fprintf (stderr, "Hex key id given with invalid hex digits !\n"); ! 215: exit (1); ! 216: } ! 217: ! 218: i++; ! 219: } ! 220: } ! 221: ! 222: /* Read the contents till we find what we're looking for */ ! 223: ! 224: while ((c1 = getc(pub)) != EOF) { ! 225: c2 = (c1 & 0xBC); ! 226: ! 227: switch (c2) { ! 228: ! 229: /* Secret key, probably revocation cert. */ ! 230: ! 231: case 0x94: ! 232: len = read_length (c1, pub); ! 233: ! 234: for (; len > 0; len--) ! 235: (void) getc (pub); ! 236: ! 237: break; ! 238: ! 239: /* Public key - grab id and length */ ! 240: ! 241: case 0x98: ! 242: len = read_length (c1, pub); ! 243: ! 244: for (i = 0; i < 8; i++) ! 245: (void) getc (pub); ! 246: ! 247: len -= 10; ! 248: ! 249: /* OK, here we are at the public modulus, get the ! 250: size from the MPI header */ ! 251: ! 252: klen = getc(pub) * 256; ! 253: klen += getc (pub); ! 254: ! 255: /* Return the length for the caller to use */ ! 256: ! 257: *length = klen; ! 258: ! 259: /* We only need the last 64 bits */ ! 260: ! 261: len -= ((klen + 7) / 8); ! 262: i = (((klen + 7) / 8) - ID_SIZE); ! 263: ! 264: /* Skip unneccesary bytes */ ! 265: ! 266: for (; i > 0; i--) { ! 267: (void) getc (pub); ! 268: } ! 269: ! 270: if (type == ID_FROM_NAME) { ! 271: for (i = 0; i < ID_SIZE; i++) { ! 272: id [i] = getc(pub); ! 273: } ! 274: } ! 275: else { ! 276: ! 277: /* Looking for length from ID */ ! 278: ! 279: int found_id = TRUE; ! 280: ! 281: for (i = 0; i < ID_SIZE; i++) { ! 282: if (id[i] != getc(pub)) ! 283: found_id = FALSE; ! 284: } ! 285: ! 286: if (found_id) { ! 287: fclose (pub); ! 288: return TRUE; ! 289: } ! 290: } ! 291: ! 292: for (; len > 0 ; len--) { ! 293: (void) getc (pub); ! 294: } ! 295: ! 296: break; ! 297: ! 298: /* Keyring trust, comment */ ! 299: ! 300: case 0xB0: ! 301: case 0xB8: ! 302: ! 303: len = getc (pub); ! 304: ! 305: for (; len > 0; len--) ! 306: (void) getc (pub); ! 307: ! 308: break; ! 309: ! 310: /* USER ID ! */ ! 311: ! 312: case 0xB4: ! 313: ! 314: len = getc (pub); ! 315: ! 316: if (type == ID_FROM_NAME) { ! 317: for (i = 0; i < len; i++) { ! 318: c = getc (pub); ! 319: userid [i] = tolower (c); ! 320: } ! 321: ! 322: userid [i] = 0; ! 323: ! 324: if (strstr(userid, s)) { ! 325: if (verbose) ! 326: fprintf (stderr, "Found user: %s\n",userid); ! 327: return TRUE; ! 328: } ! 329: ! 330: /* Ok, check for hex id */ ! 331: ! 332: if (hex_id >= 0) { ! 333: long id_read = 0l; ! 334: ! 335: for (i = 5; i < 8; i++) { ! 336: id_read <<= 8; ! 337: id_read += id[i]; ! 338: } ! 339: ! 340: if (hex_id == id_read) { ! 341: if (verbose) ! 342: fprintf (stderr, "Found hex id : 0x%06X\n", hex_id); ! 343: return TRUE; ! 344: } ! 345: } ! 346: } ! 347: else ! 348: for (i = 0; i < len; i++) ! 349: (void) getc (pub); ! 350: break; ! 351: ! 352: /* Anything we don't care about */ ! 353: ! 354: default: ! 355: len = read_length (c1, pub); ! 356: ! 357: for (; len > 0; len--) ! 358: (void) getc (pub); ! 359: break; ! 360: ! 361: } ! 362: } ! 363: ! 364: fclose (pub); ! 365: ! 366: /* Uh-oh, failed to find it ! */ ! 367: ! 368: return FALSE; ! 369: } ! 370: ! 371: /* Strip_headers() : Should be obvious what this does, really ! */ ! 372: ! 373: static void strip_headers(fp) ! 374: ! 375: FILE *fp; ! 376: ! 377: { ! 378: int c1,c2; ! 379: long len; ! 380: int i; ! 381: byte id [ID_SIZE]; ! 382: int key_length; ! 383: byte key_length_found = FALSE; ! 384: byte rsa_written = FALSE; ! 385: int mpi_length; ! 386: ! 387: /* Run through the whole message checking each packet */ ! 388: ! 389: while ((c1 = getc(fp)) != EOF) { ! 390: c2 = (c1 & 0xBC); ! 391: ! 392: switch (c2) { ! 393: ! 394: /* Public key encoded packet */ ! 395: ! 396: case 0x84: ! 397: ! 398: /* Read length */ ! 399: ! 400: len = read_length(c1, fp); ! 401: if (verbose) ! 402: fprintf (stderr, "Found %d byte RSA packet.\n", ! 403: len); ! 404: ! 405: /* ! 406: We only support ONE RSA block ! This is because ! 407: we have no idea of the file format when we start ! 408: adding headers, so we have to assume that this ! 409: is the case. Warn the user, then abort... ! 410: */ ! 411: ! 412: if (rsa_written) { ! 413: fprintf (stderr, "WARNING: More than one RSA block found... stripping extra block !\n"); ! 414: ! 415: /* Throw away the block */ ! 416: ! 417: ohno_abort_abort: ! 418: while (len-- > 0) ! 419: (void) getc (fp); ! 420: ! 421: break; ! 422: } ! 423: ! 424: /* Check for conventional encryption specified */ ! 425: ! 426: if (conventional) { ! 427: fprintf (stderr, "WARNING: You specified conventional encryption with an RSA-encrypted file !\nI hope you know what you're doing... stripping RSA header....\n"); ! 428: ! 429: goto ohno_abort_abort; ! 430: } ! 431: ! 432: /* Check public key version byte */ ! 433: ! 434: c1 = getc (fp); ! 435: ! 436: if (c1 != CURRENT_VERSION) { ! 437: fprintf(stderr, "Hmm, PK version %d not %d, may not decrypt at recipient\n", c1, CURRENT_VERSION); ! 438: } ! 439: ! 440: /* Strip key ID */ ! 441: ! 442: for (i = 0; i < ID_SIZE; i++) ! 443: id[i] = getc (fp); ! 444: ! 445: if (find_key_id (id,&key_length,NULL,LENGTH_FROM_ID)) { ! 446: key_length_found = TRUE; ! 447: } ! 448: ! 449: /* Check RSA version byte */ ! 450: ! 451: c1 = getc(fp); ! 452: ! 453: if (c1 != RSA_VERSION) { ! 454: fprintf (stderr, "Hmm, RSA version %d not %d, may not decrypt at recipient\n", c1, RSA_VERSION); ! 455: } ! 456: ! 457: /* Strip MPI prefix */ ! 458: ! 459: mpi_length = getc(fp); ! 460: mpi_length = mpi_length * 256 + getc(fp); ! 461: ! 462: /* Now, we have a problem in that PGP may generate ! 463: an RSA block shorter than your key, in which ! 464: case decryption is likely to fail. Check for ! 465: this and warn the user ! */ ! 466: ! 467: if (!key_length_found) { ! 468: fprintf (stderr, "Hmm, couldn't get the length of this key, so can't verify that decryption\nwill be successful.\n"); ! 469: } ! 470: else { ! 471: if (((mpi_length + 7) / 8) != ! 472: ((key_length + 7) / 8)) { ! 473: fprintf (stderr, "WARNING : Short RSA block output, decryption will probably fail if used !\n"); ! 474: } ! 475: } ! 476: ! 477: /* Copy remaining data from packet */ ! 478: ! 479: len -= 12; ! 480: for (; len > 0; len--) ! 481: putchar (getc(fp)); ! 482: ! 483: rsa_written = TRUE; ! 484: break; ! 485: ! 486: /* IDEA packet */ ! 487: ! 488: case 0xA4: ! 489: ! 490: /* Read length */ ! 491: ! 492: len = read_length(c1, fp); ! 493: if (verbose) ! 494: fprintf (stderr, "Found %d byte IDEA packet.\n", ! 495: len); ! 496: ! 497: /* Copy data from packet */ ! 498: ! 499: for (; len > 0; len--) ! 500: putchar (getc (fp)); ! 501: ! 502: break; ! 503: ! 504: default: ! 505: ! 506: /* Oh no ! Don't know what this is - just skip it ! */ ! 507: ! 508: if (verbose) ! 509: fprintf (stderr, "Oops ! Unexpected packet type, skipping !\n"); ! 510: ! 511: len = read_length (c1, fp); ! 512: ! 513: for (; len > 0; len --) ! 514: (void) getc (fp); ! 515: ! 516: break; ! 517: } ! 518: } ! 519: } ! 520: ! 521: /* Now we put the headers back in again */ ! 522: ! 523: static void add_headers(id, length) ! 524: ! 525: byte *id; ! 526: int length; ! 527: ! 528: { ! 529: unsigned long len, mask; ! 530: int shift; ! 531: int i, c; ! 532: long fpos; ! 533: long flen; ! 534: int s; ! 535: #ifdef USE_PGPPATH ! 536: char *pgp_path; ! 537: #endif ! 538: ! 539: /* Foo ! We have to use a temporary file, because we need to be ! 540: able to output the length after reading it in ! */ ! 541: ! 542: #ifdef USE_TMP ! 543: strcpy (file_name, "/tmp/stealth.t"); ! 544: #else ! 545: #ifdef USE_PGPPATH ! 546: pgp_path = getenv ("PGPPATH"); ! 547: ! 548: if (!pgp_path) { ! 549: fprintf (stderr, "PGPPATH not set !\n"); ! 550: exit (1); ! 551: } ! 552: ! 553: sprintf(file_name,"%s/stealth.t",pgp_path); ! 554: #else ! 555: strcpy (file_name, "stealth.t"); ! 556: #endif ! 557: #endif ! 558: ! 559: s = strlen (file_name); ! 560: ! 561: i = 0; ! 562: ! 563: #ifdef DOS ! 564: #define F_OK 0 ! 565: #endif ! 566: ! 567: while (!access (file_name, F_OK) && i < 100) { ! 568: sprintf (file_name + s, "%d", i++); ! 569: } ! 570: ! 571: afp = fopen (file_name,"w+b"); ! 572: ! 573: if (!afp) { ! 574: fprintf (stderr, "Can't open '%s' !\n", file_name); ! 575: exit (2); ! 576: } ! 577: ! 578: /* On unix, unlink the file immediately, to improve security */ ! 579: ! 580: #ifdef UNIX ! 581: unlink (file_name); ! 582: #endif ! 583: ! 584: file_open = TRUE; ! 585: ! 586: if (!conventional) { ! 587: ! 588: /* First output the PK header */ ! 589: ! 590: len = 4 + ID_SIZE + (length + 7)/8; ! 591: ! 592: write_length (0x84, len, afp); ! 593: putc (CURRENT_VERSION, afp); ! 594: ! 595: /* Store the key ID */ ! 596: ! 597: for (i = 0; i < 8; i++) { ! 598: putc (id [i], afp); ! 599: } ! 600: ! 601: /* RSA version */ ! 602: ! 603: putc (RSA_VERSION, afp); ! 604: ! 605: /* MPI header */ ! 606: ! 607: c = (length & 0xFF00) >> 8; ! 608: putc (c, afp); ! 609: putc (length & 0xFF, afp); ! 610: ! 611: /* Copy the MPI over */ ! 612: ! 613: i = (length + 7) / 8; ! 614: while (i-- > 0) { ! 615: c = getchar(); ! 616: putc (c, afp); ! 617: } ! 618: ! 619: } ! 620: ! 621: /* Now the IDEA bits */ ! 622: ! 623: len = 0xFFFFFFFF; ! 624: ! 625: fpos = ftell (afp) + 1; ! 626: write_length (0xA4, len, afp); ! 627: ! 628: len = 0; ! 629: ! 630: while ((c = getchar ()) != EOF) { ! 631: len ++; ! 632: putc (c, afp); ! 633: } ! 634: ! 635: fseek (afp, fpos, 0); ! 636: ! 637: /* Set up mask for length writing */ ! 638: ! 639: mask = 0xFF000000; ! 640: shift = 24; ! 641: ! 642: /* Write the length back */ ! 643: ! 644: for (i = 0; i < 4; i++) { ! 645: c = (len & mask) >> shift; ! 646: shift -= 8; ! 647: mask >>= 8; ! 648: ! 649: putc (c, afp); ! 650: } ! 651: ! 652: /* OK, now let's output the data ! */ ! 653: ! 654: fseek (afp, 0l, 0); ! 655: ! 656: while ((c = getc (afp)) != EOF) { ! 657: putchar (c); ! 658: } ! 659: ! 660: /* Erase the file */ ! 661: ! 662: flen = ftell (afp); ! 663: ! 664: fseek (afp, 0l,0); ! 665: ! 666: while (flen --) ! 667: putc (0, afp); ! 668: ! 669: fclose (afp); ! 670: afp = NULL; ! 671: ! 672: #ifndef UNIX ! 673: /* Finally, delete the temporary file */ ! 674: ! 675: unlink (file_name); ! 676: #endif ! 677: ! 678: file_open = FALSE; ! 679: } ! 680: ! 681: static char looking_for [256]; ! 682: ! 683: /* Do the stuff */ ! 684: ! 685: main(argc,argv) ! 686: ! 687: char *argv[]; ! 688: int argc; ! 689: ! 690: { ! 691: int length; ! 692: byte id [ID_SIZE]; ! 693: char *s, *d; ! 694: int arg = 1,i; ! 695: ! 696: /* Following needed for binary stdin/stdout on DOS */ ! 697: ! 698: #ifdef DOS ! 699: _fmode = O_BINARY; ! 700: setmode (fileno(stdin), O_BINARY); ! 701: setmode (fileno(stdout), O_BINARY); ! 702: #endif ! 703: ! 704: /* Set the umask for any files we may create */ ! 705: ! 706: umask (077); ! 707: ! 708: signal (SIGINT, int_handler); ! 709: ! 710: /* Check command line parameters */ ! 711: ! 712: while (arg != argc && argv [arg][0] == '-') { ! 713: ! 714: for (i = 1; argv[arg][i]; i++) { ! 715: switch (argv[arg][i]) { ! 716: ! 717: case 'v': ! 718: verbose = TRUE; ! 719: break; ! 720: ! 721: case 'c': ! 722: conventional = TRUE; ! 723: break; ! 724: ! 725: case 'a': ! 726: adding = TRUE; ! 727: break; ! 728: ! 729: } ! 730: } ! 731: ! 732: arg++; ! 733: } ! 734: ! 735: if (!adding) ! 736: strip_headers (stdin); ! 737: else { ! 738: if (!conventional) { ! 739: ! 740: if (arg == argc) { ! 741: fprintf (stderr, "You specified -a, but gave no user id !\n"); ! 742: exit (1); ! 743: } ! 744: ! 745: s = argv[arg]; ! 746: d = looking_for; ! 747: ! 748: while (*s) { ! 749: *d++ = tolower (*s); ! 750: s++; ! 751: } ! 752: *d = 0; ! 753: } ! 754: ! 755: if (conventional || ! 756: find_key_id (id,&length,looking_for,ID_FROM_NAME)) { ! 757: add_headers (id, length); ! 758: } ! 759: else { ! 760: fprintf (stderr, "Can't find key for user %s\n",argv[arg]); ! 761: } ! 762: } ! 763: } ! 764:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.