home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 February / PCO_0298.ISO / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / contrib / stealth / stealth.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-29  |  13.2 KB  |  765 lines

  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.  
  765.