Annotation of pgp/contrib/stealth/stealth.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.