Annotation of pgp/src/pgp.c, revision 1.1.1.1

1.1       root        1: /*
                      2:        Pretty Good(tm) Privacy - RSA public key cryptography for the masses
                      3:        Written by Philip Zimmermann, Phil's Pretty Good(tm) Software.
                      4:        Beta test version 1.0 - Last revised 5 Jun 91 by PRZ
                      5: 
                      6:        PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
                      7:        public key cryptosystem with the speed of fast conventional
                      8:        cryptographic algorithms, fast message digest algorithms, data
                      9:        compression, and sophisticated key management.  And PGP performs 
                     10:        the RSA functions faster than most other software implementations.  
                     11:        PGP is RSA public key cryptography for the masses.
                     12: 
                     13:        Uses RSA Data Security, Inc. MD4 Message Digest Algorithm
                     14:        for signatures.  Uses the LZHUF algorithm for compression.
                     15:        Uses my own algorithm, BassOmatic, for conventional encryption.
                     16: 
                     17:        (c) Copyright 1990 by Philip Zimmermann.  All rights reserved.
                     18:        The author assumes no liability for damages resulting from the use 
                     19:        of this software, even if the damage results from defects in this 
                     20:        software.  No warranty is expressed or implied.  
                     21: 
                     22:        All the source code I wrote for PGP is available for free under 
                     23:        the "Copyleft" General Public License from the Free Software 
                     24:        Foundation.  A copy of that license agreement is included in the 
                     25:        source release package of PGP.  The source code for the MD4 
                     26:        functions and the LZHUF functions were separately placed in the 
                     27:        public domain by their respective authors.  See the PGP User's 
                     28:        Guide for more complete information about licensing, patent 
                     29:        restrictions on the RSA algorithm, trademarks, copyrights, and 
                     30:        export controls.  Technical assistance from me is available for 
                     31:        an hourly fee.
                     32: 
                     33: 
                     34:        PGP generally zeros its used stack and memory areas before exiting.  
                     35:        This avoids leaving sensitive information in RAM where other users 
                     36:        could find it later.  The RSA library and keygen routines also 
                     37:        sanitize their own stack areas.  This stack sanitizing has not been 
                     38:        checked out under all the error exit conditions, when routines exit 
                     39:        abnormally.  Also, we must find a way to clear the C I/O library 
                     40:        file buffers, and the MSDOS disk buffers.  
                     41:        
                     42:        The code in this source file (pgp.c) was hastily written, and it 
                     43:        shows.  It has a lot of redundant code, developed by ad-hoc 
                     44:        "accretion" rather than by well-planned design.  It isn't buggy, but 
                     45:        it needs to be reorganized to make it cleaner, clearer, and more 
                     46:        succinct.  Maybe someday.  Better and more typical examples of my 
                     47:        programming style can be seen in the RSA library code in rsalib.c 
                     48:        and keygen.c, and in the BassOmatic conventional encryption routines 
                     49:        in basslib.c and related files.
                     50: 
                     51:        If you modify this code, PLEASE preserve the style of indentation 
                     52:        used for {begin...end} blocks.  It drives me bats to have to deal 
                     53:        with more than one style in the same program.
                     54: 
                     55: */
                     56: 
                     57: 
                     58: #include <stdlib.h>    /* for exit(), malloc(), free(), etc. */
                     59: #include <stdio.h>     /* for printf(), tmpfile(), etc.        */
                     60: #include <time.h>      /* for timestamps and performance measurement */
                     61: #include <string.h>    /* for strcat(), etc.   */
                     62: #include <io.h>
                     63: #include <conio.h>     /* for kbhit()                  */
                     64: 
                     65: #include "md4.h"       /* for MD4 message digest stuff */
                     66: #include "rsalib.h"
                     67: #include "rsaio.h"
                     68: #include "keygen.h"
                     69: #include "random.h"
                     70: #include "basslib.h"
                     71: #include "basslib2.h"
                     72: 
                     73: #define KEYFRAGSIZE 8  /* # of bytes in key ID modulus fragment */
                     74: #define SIZEOF_TIMESTAMP 4 /* 32-bit timestamp */
                     75: 
                     76: /* This macro is for burning sensitive data (byte arrays only) on stack */
                     77: #define burn(x) fill0(x,sizeof(x))
                     78: 
                     79: /*
                     80: **********************************************************************
                     81: */
                     82: 
                     83: /* Cipher Type Byte (CTB) definitions follow...*/
                     84: #define CTB_DESIGNATOR 0x80
                     85: #define is_ctb(c) (((c) & CTB_DESIGNATOR)==CTB_DESIGNATOR)
                     86: #define CTB_TYPE_MASK 0x7c
                     87: #define CTB_LLEN_MASK 0x03
                     88: 
                     89: /* length of length field of packet, in bytes (1, 2, 4, 8 bytes): */
                     90: #define ctb_llength(ctb) ((int) 1 << (int) ((ctb) & CTB_LLEN_MASK))
                     91: 
                     92: #define is_ctb_type(ctb,type) (((ctb) & CTB_TYPE_MASK)==(4*type))
                     93: #define CTB_BYTE(type,llen) (CTB_DESIGNATOR + (4*type) + llen)
                     94: 
                     95: #define CTB_PKE_TYPE 1 /* packet encrypted with RSA public key */
                     96: #define CTB_SKE_TYPE 2 /* packet signed with RSA secret key */
                     97: #define CTB_MD_TYPE 3          /* message digest packet */
                     98: #define CTB_CONKEY_TYPE 4      /* conventional key packet */
                     99: #define CTB_CERT_SECKEY_TYPE 5  /* secret key certificate */
                    100: #define CTB_CERT_PUBKEY_TYPE 6  /* public key certificate */
                    101: #define CTB_COMPRESSED_TYPE 8  /* compressed data packet */
                    102: #define CTB_CKE_TYPE 9                 /* conventional-key-encrypted data */
                    103: #define CTB_LITERAL_TYPE 12                    /* raw data */
                    104: 
                    105: /* Unimplemented CTB packet types follow... */
                    106: /* #define CTB_RAW1_TYPE 13            /* raw data, with filename, date, crc32 prefix */
                    107: /* #define CTB_PATTERN_TYPE 14 /* unique file prefix autorecognition pattern */
                    108: /* #define CTB_EXTENDED_TYPE 15        /* 2-byte CTB, 256 extra CTB types */
                    109: 
                    110: #define CTB_PKE CTB_BYTE(CTB_PKE_TYPE,1)
                    111:        /* CTB_PKE len16 keyID mpi(RSA(CONKEYPKT)) */
                    112:        /*        1              2       SIZE  countbytes()+2 */
                    113: #define CTB_SKE CTB_BYTE(CTB_SKE_TYPE,1)
                    114:        /* CTB_SKE len16 keyID mpi(RSA(MDPKT)) */
                    115:        /*        1              2       SIZE  countbytes()+2 */
                    116: #define CTB_MD CTB_BYTE(CTB_MD_TYPE,0)
                    117:        /* CTB_MD len8 algorithm MD timestamp */
                    118: #define CTB_CONKEY CTB_BYTE(CTB_CONKEY_TYPE,0)
                    119:        /* CTB_CONKEY len8 algorithm key */
                    120: #define CTB_CERT_SECKEY CTB_BYTE(CTB_CERT_SECKEY_TYPE,1)
                    121:        /* CTB_CERT_SECKEY len16 timestamp userID mpi(n) mpi(e) mpi(d) mpi(p) mpi(q) mpi(u) crc16 */
                    122: #define CTB_CERT_PUBKEY CTB_BYTE(CTB_CERT_PUBKEY_TYPE,1)
                    123:        /* CTB_CERT_PUBKEY len16 timestamp userID mpi(n) mpi(e) crc16 */
                    124: 
                    125: /*     Note that a "secret key compromised" certificate is exactly the same 
                    126:        as a public key certificate, but with mpi(e)==0. */
                    127: 
                    128: #define CTB_CKE CTB_BYTE(CTB_CKE_TYPE,3)
                    129:        /*      CTB_CKE ciphertext */
                    130: 
                    131: #define CTB_LITERAL CTB_BYTE(CTB_LITERAL_TYPE,3)
                    132:        /*      CTB_LITERAL data */
                    133: 
                    134: #define CTB_COMPRESSED CTB_BYTE(CTB_COMPRESSED_TYPE,3)
                    135:        /*      CTB_COMPRESSED compressedtext */
                    136: 
                    137: #define CTB_PATTERN CTB_BYTE(CTB_PATTERN_TYPE,0)
                    138:        /*      Unique 40-bit auto-recognition prefix pattern: B8 03 'P' 'R' 'Z' */
                    139: 
                    140: /*     Conventional encryption algorithm selector bytes. */
                    141: #define DES_ALGORITHM_BYTE     1       /*      use the DES     (unimplemented) */
                    142: #define BASS_ALGORITHM_BYTE    2       /*      use the BassOmatic              */
                    143: 
                    144: /*     Message digest algorithm selector bytes. */
                    145: #define MD4_ALGORITHM_BYTE 1   /* MD4 message digest algorithm */
                    146: 
                    147: /*     Data compression algorithm selector bytes. */
                    148: #define LZH_ALGORITHM_BYTE 1   /* LZH compression algorithm */
                    149: 
                    150: #define is_secret_key(ctb) is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE)
                    151: 
                    152: #define MAX_SIGCERT_LENGTH (1+2 + KEYFRAGSIZE + 2+MAX_BYTE_PRECISION)
                    153: 
                    154: #define MAX_KEYCERT_LENGTH (1+2+4+256 + 5*(2+MAX_BYTE_PRECISION))
                    155: 
                    156: 
                    157: /* Global filenames and system-wide file extensions... */
                    158: char CTX_EXTENSION[] = ".ctx";
                    159: char PUB_EXTENSION[] = ".pub";
                    160: char SEC_EXTENSION[] = ".sec";
                    161: char SCRATCH_CTX_FILENAME[] = "_pgptemp.ctx";
                    162: char SCRATCH_PTX_FILENAME[] = "_pgptemp.ptx";
                    163: char SCRATCH_KEYRING_FILENAME[] = "_tmpring.pub"; /* gets modified */
                    164: char PGPPATH[] = "PGPPATH";    /* environmental variable */
                    165: 
                    166: /* These files use the environmental variable PGPPATH as a default path: */
                    167: char PUBLIC_KEYRING_FILENAME[32] = "keyring.pub";
                    168: char SECRET_KEYRING_FILENAME[32] = "keyring.sec";
                    169: char RANDSEED_FILENAME[32] = "randseed.pgp";
                    170: 
                    171: boolean        verbose = FALSE;        /* -l option: display maximum information */
                    172: 
                    173: /*
                    174: **********************************************************************
                    175: */
                    176: 
                    177: 
                    178: 
                    179: boolean pkzipSignature( byte *header )
                    180: {
                    181:        /*
                    182:        **      Return TRUE if header begins with the PKzip signature
                    183:        **      Useful for MSDOS only.
                    184:        */
                    185: 
                    186:        if ((header[0] == 'P')   && (header[1] == 'K')
                    187:        &&  (header[2] == '\03') && (header[3] == '\04'))
                    188:                return(TRUE);
                    189:        return(FALSE);
                    190: }      /* pkzipSignature */
                    191: 
                    192: 
                    193: /*
                    194: **     Convert to or from external byte order.
                    195: **     Note that hilo_swap does nothing if this is a LSB-first CPU.
                    196: */
                    197: 
                    198: #define convert2(x,lx) hilo_swap( (byteptr)&(x), (lx) )
                    199: #define convert(x)             convert2( (x), sizeof(x) )
                    200: 
                    201: word16 fetch_word16(byte *buf)
                    202: /*     Fetches a 16-bit word from where byte pointer is pointing.
                    203:        buf points to external-format byteorder array, assuming LSB-first.
                    204: */
                    205: {      word16 w0,w1;
                    206:        w0 = *buf++;
                    207:        w1 = *buf++;
                    208:        return((w1<<8) + w0);   
                    209: }      /* fetch_word16 */
                    210: 
                    211: 
                    212: void get_timestamp(byte *timestamp)
                    213: /*     Returns timestamp byte array, in internal byteorder */
                    214: {      word32 t;
                    215:        t = time(0);
                    216:        timestamp[0] = t;               /* fill array in external byte order */
                    217:        timestamp[1] = t>>8;
                    218:        timestamp[2] = t>>16;
                    219:        timestamp[3] = t>>24;
                    220:        /* Note that hilo_swap does nothing if this is a LSB-first CPU. */
                    221:        hilo_swap(timestamp,4); /* convert to internal byteorder */
                    222: }      /* get_timestamp */
                    223: 
                    224: 
                    225: void CToPascal(char *s)
                    226: {      /* "xyz\0" --> "\3xyz" ... converts C string to Pascal string */
                    227:        int i,j;
                    228:        j = string_length(s);
                    229:        for (i=j; i!=0; i--)
                    230:                s[i] = s[i-1];  /* move everything 1 byte to the right */
                    231:        s[0] = j;               /* Pascal length byte at beginning */   
                    232: }      /* CToPascal */
                    233: 
                    234: 
                    235: void PascalToC( char *s )
                    236: {      /* "\3xyz" --> "xyz\0" ... converts Pascal string to C string */
                    237:        int i,j;
                    238:        for (i=0,j=s[0]; i<j; i++)
                    239:                s[i] = s[i+1];  /* move everything 1 byte to the left */
                    240:        s[i] = '\0';            /* append C string terminator */
                    241: }      /* PascalToC */
                    242: 
                    243: 
                    244: 
                    245: int date_ymd(word32 *tstamp, int *year, int *month, int *day)
                    246: /*     Given timestamp as seconds elapsed since 1970 Jan 1 00:00:00,
                    247:        returns year (1970-2106), month (1-12), day (1-31).
                    248:        Not valid for dates after 2100 Feb 28 (no leap day that year).
                    249:        Also returns day of week (0-6) as functional return.
                    250: */
                    251: {      word32 days,y;
                    252:        int m,d,i;
                    253:        static short mdays[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
                    254:        days = (*tstamp)/86400UL;       /* day 0 is 1970/1/1 */
                    255:        days -= 730UL;  /* align days relative to 1st leap year, 1972 */
                    256:        y = ((days*4UL)/1461UL);        /* 1972 is year 0 */
                    257:        /* reduce to days elapsed since 1/1 last leap year: */ 
                    258:        d = days - ((y/4UL)*1461UL);
                    259:        *year = y+1972;
                    260:        for (i=0; i<48; i++)    /* count months 0-47 */
                    261:        {       m = i % 12;
                    262:                d -= mdays[m] + (i==1); /* i==1 is the only leap month */
                    263:                if (d < 0)
                    264:                {       d += mdays[m] + (i==1);
                    265:                        break;
                    266:                }
                    267:        }
                    268:        *month = m+1;
                    269:        *day = d+1;
                    270:        i = (days-2UL) % 7UL;   /* compute day of week 0-6 */
                    271:        return(i);      /* returns weekday 0-6; 0=Sunday, 6=Saturday */
                    272: }      /* date_ymd */
                    273: 
                    274: 
                    275: 
                    276: void show_date(word32 *tstamp)
                    277: {      int m,d,y;
                    278:        static char *month[12] = 
                    279:        {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
                    280:        date_ymd(tstamp,&y,&m,&d);
                    281:        fprintf(stderr,"%2d-%s-%02d", d, month[m-1], y % 100);
                    282: }      /* show_date */
                    283: 
                    284: 
                    285: 
                    286: boolean file_exists(char *filename)
                    287: /*     Returns TRUE iff file is can be opened for reading. */
                    288: {      FILE *f;
                    289:        /* open file f for read, in binary (not text) mode...*/
                    290:        if ((f = fopen(filename,"rb")) == NULL)
                    291:                return(FALSE);
                    292:        fclose(f);
                    293:        return(TRUE);
                    294: }      /* file_exists */
                    295: 
                    296: 
                    297: 
                    298: #define diskbufsize 1024
                    299: 
                    300: int wipeout(FILE *f)
                    301: {      /*      Completely overwrite and erase file, so that no sensitive 
                    302:                information is left on the disk.  
                    303:                NOTE:  File MUST be open for read/write.
                    304:        */
                    305: 
                    306:        long flength;
                    307:        int count;
                    308:        byte textbuf[diskbufsize];
                    309: 
                    310:     fseek(f, 0L, SEEK_END);
                    311:     flength = ftell(f);
                    312:        rewind(f);
                    313: 
                    314:        fill0(textbuf,diskbufsize);
                    315:        while (flength > 0L)
                    316:        {       /* write zeros to the whole file... */
                    317:                if (flength < (word32) diskbufsize)
                    318:                        count = flength;
                    319:                else
                    320:                        count = diskbufsize;
                    321:                fwrite(textbuf,1,count,f);
                    322:                flength -= count;
                    323:        }
                    324:        rewind(f);      /* maybe this isn't necessary */
                    325:        return(0);      /* normal return */
                    326: }      /* wipeout */
                    327: 
                    328: 
                    329: int wipefile(char *filename)
                    330: {      /*      Completely overwrite and erase file, so that no sensitive 
                    331:                information is left on the disk.
                    332:        */
                    333:        FILE *f;
                    334:        /* open file f for read/write, in binary (not text) mode...*/
                    335:        if ((f = fopen(filename,"rb+")) == NULL)
                    336:                return(-1);     /* error - file can't be opened */
                    337:        wipeout(f);
                    338:        fclose(f);
                    339:        return(0);      /* normal return */
                    340: }      /* wipefile */
                    341: 
                    342: 
                    343: 
                    344: #define strhas(s,c) (strchr((s),(c)) != NULL)
                    345: 
                    346: boolean strhasany( char *s1, char *s2 )
                    347: {      /*      Searches s1 for any of the characters in s2.  
                    348:                Returns TRUE if found.
                    349:        */
                    350:        while (*s2)
                    351:        {       if (strhas(s1,*s2))
                    352:                        return(TRUE);
                    353:                s2++;
                    354:        }
                    355:        return(FALSE);
                    356: }      /* strhasany */
                    357: 
                    358: 
                    359: boolean strcontains( char *s1, char *s2 )
                    360: {      /*
                    361:        **      Searches s1 for s2, without case sensitivity.
                    362:        **      Return TRUE if found.
                    363:        **
                    364:        **      If s2 is an empty string then return TRUE.  This is because,
                    365:        **      at least in the world of mathematics, the empty set is contained
                    366:        **      in all other sets.  The Microsoft C version 6.0 strstr function
                    367:        **      behaves this way but version 5.1 does not, so we need to
                    368:        **      explicitly test for the situation. -- ALH 91/2/17
                    369:        */
                    370: 
                    371:        if (s2[0] != '\0')
                    372:        {
                    373:                char buf1[256], buf2[256];      /* scratch buffers */
                    374: 
                    375:                strncpy( buf1, s1, 256 );       strlwr( buf1 ); /* converts to lower case */
                    376:                strncpy( buf2, s2, 256 );       strlwr( buf2 ); /* converts to lower case */
                    377: 
                    378:                if (strstr( buf1, buf2 ) == NULL) 
                    379:                        return( FALSE );                /* string not found */
                    380:        }
                    381:        return(TRUE);
                    382: }      /*      strcontains     */
                    383: 
                    384: 
                    385: void translate_spaces(char *s)
                    386: /* Changes all the underlines to spaces in a string. */
                    387: {      while (strchr(s,'_') != NULL)
                    388:                *strchr(s,'_') = ' ';
                    389: }
                    390: 
                    391: 
                    392: boolean no_extension(char *filename)
                    393: /*     Returns TRUE if user left off file extension, allowing default. */
                    394: {      if (strrchr(filename,'.')==NULL)
                    395:                return(TRUE);
                    396:        /* see if the last '.' is followed by a backslash...*/ 
                    397:        if (*(strrchr(filename,'.')+1) == '\\')
                    398:                return(TRUE);   /* just a "..\filename" construct */
                    399:        return(FALSE);  /* user specified extension, even if a blank one */
                    400: }      /* no_extension */
                    401: 
                    402: 
                    403: void drop_extension(char *filename)
                    404: {      /* deletes trailing ".xxx" file extension after the period. */
                    405:        if (!no_extension(filename))
                    406:                *strrchr(filename,'.') = '\0';
                    407: }      /* drop_extension */
                    408: 
                    409: 
                    410: void default_extension(char *filename, char *extension)
                    411: {      /* append filename extension if there isn't one already. */
                    412:        if (no_extension(filename))
                    413:                strcat(filename,extension);
                    414: }      /* default_extension */
                    415: 
                    416: 
                    417: void force_extension(char *filename, char *extension)
                    418: {      /* change the filename extension. */
                    419:        drop_extension(filename);       /* out with the old */
                    420:        strcat(filename,extension);     /* in with the new */
                    421: }      /* force_extension */
                    422: 
                    423: 
                    424: boolean getyesno(char default_answer)
                    425: {      /* Get yes/no answer from user, returns TRUE for yes, FALSE for no. */
                    426:        char buf[8];
                    427:        while (keypress())      /* flush typahead buffer */
                    428:                getkey();
                    429:        getstring(buf,6,TRUE);  /* echo keyboard input */
                    430:        if (strlen(buf)==0)             /* if user didn't give an answer... */
                    431:                buf[0] = default_answer;        /* assume default answer */
                    432:        buf[0] = tolower(buf[0]);
                    433:        return(buf[0]=='y');
                    434: }      /* getyesno */
                    435: 
                    436: 
                    437: void maybe_force_extension(char *filename, char *extension)
                    438: {      /* if user consents to it, change the filename extension. */
                    439:        char newname[64];
                    440:        if (!strcontains(filename,extension))
                    441:        {       strcpy(newname,filename);
                    442:                force_extension(newname,extension);
                    443:                if (!file_exists(newname))
                    444:                {       fprintf(stderr,"\nShould '%s' be renamed to '%s' [Y/n]? ",
                    445:                                filename,newname);
                    446:                        if (getyesno('y'))
                    447:                                rename(filename,newname);
                    448:                }
                    449:        }
                    450: }      /* maybe_force_extension */
                    451: 
                    452: 
                    453: /*---------------------------------------------------------------------*/
                    454: /*     Begin uuencode routines.
                    455:        This converts a binary file into printable ASCII characters, in a 
                    456:        form compatible with the Unix uuencode utility.
                    457:        This makes it easier to send encrypted files over a 7-bit channel.
                    458: */
                    459: 
                    460: /* ENC is the basic 1 character encoding function to make a char printing */
                    461: #define ENC(c) (((c) & 077) + ' ')
                    462: 
                    463: /*
                    464:  * output one group of 3 bytes, pointed at by p, on file f.
                    465:  */
                    466: void outdec(char *p, FILE *f)
                    467: {
                    468:        int c1, c2, c3, c4;
                    469: 
                    470:        c1 = *p >> 2;
                    471:        c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
                    472:        c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
                    473:        c4 = p[2] & 077;
                    474:        putc(ENC(c1), f);
                    475:        putc(ENC(c2), f);
                    476:        putc(ENC(c3), f);
                    477:        putc(ENC(c4), f);
                    478: }      /* outdec */
                    479: 
                    480: 
                    481: /* fr: like read but stdio */
                    482: int fr(FILE *fd, char *buf, int cnt)
                    483: {
                    484:        int c, i;
                    485: 
                    486:        for (i=0; i<cnt; i++)
                    487:        {
                    488:                c = getc(fd);
                    489:                if (c == EOF)
                    490:                        return(i);
                    491:                buf[i] = c;
                    492:        }
                    493:        return (cnt);
                    494: }      /* fr */
                    495: 
                    496: 
                    497: /*
                    498:  * copy from in to out, uuencoding as you go along.
                    499:  */
                    500: void uuencode(FILE *in, FILE *out)
                    501: {
                    502:        char buf[80];
                    503:        int i, n;
                    504: 
                    505:        for (;;)
                    506:        {       /* 1 (up to) 45 character line */
                    507:                n = fr(in, buf, 45);
                    508:                putc(ENC(n), out);
                    509: 
                    510:                for (i=0; i<n; i += 3)
                    511:                        outdec(&buf[i], out);
                    512: 
                    513:                putc('\n', out);
                    514:                if (n <= 0)
                    515:                        break;
                    516:        }
                    517: }      /* uuencode */
                    518: 
                    519: 
                    520: int uue_file(char *infile, char *outfile)
                    521: {      /* translates infile to uuencode format, writing to outfile */
                    522:        FILE *in,*out;
                    523:        int mode;
                    524: 
                    525:        if (verbose)
                    526:                fprintf(stderr,"Converting output to uuecode format.\n");
                    527: 
                    528:        /* open input file as binary */
                    529:        if ((in = fopen(infile,"rb")) == NULL)
                    530:        {   
                    531:            return(1);
                    532:        }
                    533: 
                    534:        /* open output file as text */
                    535:        if ((out = fopen(outfile,"w")) == NULL)
                    536:        {       fclose(in);
                    537:            return(1);
                    538:        }
                    539: 
                    540:        mode = 0666;    /* Assume a reasonable dummy default for file mode */
                    541: 
                    542:        fprintf(out,"begin %o %s\n", mode, infile);
                    543: 
                    544:        uuencode(in, out);
                    545: 
                    546:        fprintf(out,"end\n");
                    547:        fclose(out);
                    548:        fclose(in);
                    549: 
                    550:        return(0);
                    551: }      /* uue_file */
                    552: 
                    553: 
                    554: /*     End uuencode routines. */
                    555: 
                    556: /*     uudecode routines.  
                    557:        Portions derived from unix uudecode utility by Mark Horton.
                    558: */
                    559: 
                    560: #define SUMSIZE 64
                    561: #define DEC(c) (((c) - ' ') & 077)    /* single character decode */
                    562: 
                    563: 
                    564: int uud_buffer(char *inbuf, char *outbuf, int *outlength)
                    565: {
                    566:        char *bp;
                    567:        boolean has_checksum=FALSE;
                    568: 
                    569:        register int j;
                    570:        register int n;
                    571:        int checksum;
                    572:        int status;
                    573: 
                    574: 
                    575:                status = 0;
                    576:                *outlength = 0;
                    577: 
                    578:                /* Pad end of lines in case some editor truncated trailing
                    579:                   spaces */
                    580: 
                    581:                for (n=0; n<79; n++)  /* search for first \r, \n or \000 */
                    582:            {
                    583:                    if (inbuf[n]=='\176')     /* If BITNET made a twiddle, */
                    584:                                inbuf[n]='\136';     /* we make a caret           */
                    585:                if (inbuf[n]=='\r' || inbuf[n]=='\n' || inbuf[n]=='\000')
                    586:                                break;
                    587:                        if ((inbuf[n] < '\040') || (inbuf[n] > '\137'))
                    588:                                status = -1;    /* illegal uudecode character */
                    589:            }
                    590:                for (; n<79; n++)       /* when found, fill rest of line with space */
                    591:                    inbuf[n]=' ';
                    592: 
                    593:                inbuf[79]=0;        /* terminate new string */
                    594: 
                    595:                checksum = 0;
                    596:                n = DEC(inbuf[0]);
                    597:                if (n == 0)
                    598:                    return(0);  /* 0 bytes on a line??  Must be the last line */
                    599: 
                    600:                if (status) 
                    601:                        return(status); /* bad character, out of range */
                    602: 
                    603:                bp = &inbuf[1];
                    604: 
                    605:                /* FOUR input characters go into each THREE output charcters */
                    606: 
                    607:                while (n >= 4)
                    608:            {
                    609:                    j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; 
                    610:                        checksum += j;
                    611:                        outbuf[(*outlength)++]=j; 
                    612:                j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; 
                    613:                        checksum += j;
                    614:                        outbuf[(*outlength)++]=j; 
                    615:                    j = DEC(bp[2]) << 6 | DEC(bp[3]);
                    616:                        checksum += j;
                    617:                        outbuf[(*outlength)++]=j; 
                    618:                    checksum = checksum % SUMSIZE;
                    619:                bp += 4;
                    620:                    n -= 3;
                    621:            }
                    622: 
                    623:            j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
                    624:                checksum += j;
                    625:                if (n >= 1)
                    626:                        outbuf[(*outlength)++]=j; 
                    627:            j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
                    628:                checksum += j;
                    629:                if (n >= 2)
                    630:                        outbuf[(*outlength)++]=j; 
                    631:            j = DEC(bp[2]) << 6 | DEC(bp[3]);
                    632:                checksum += j;
                    633:                if (n >= 3)
                    634:                        outbuf[(*outlength)++]=j; 
                    635:            checksum = checksum % SUMSIZE;
                    636:            bp += 4;
                    637:            n -= 3;
                    638: 
                    639:                /* The line has been decoded; now check that sum */
                    640: 
                    641:                has_checksum |= !isspace(*bp);
                    642:                if (has_checksum)                       /* Is there a checksum at all?? */
                    643:                if (checksum != DEC(*bp))       /* Does that checksum match? */
                    644:                                return(-2);     /* checksum error */
                    645: 
                    646:        return(status); /* normal return */
                    647: 
                    648: }      /* uud_buffer */
                    649: 
                    650: /*
                    651:  * Copy from in to out, decoding as you go.
                    652:  * If a return or newline is encountered too early in a line, it is
                    653:  * assumed that means that some editor has truncated trailing spaces.
                    654:  */
                    655: int uudecode(FILE *in, FILE *out)
                    656: {
                    657: char inbuf[81];
                    658: char outbuf[81];
                    659: char *bp;
                    660: boolean has_checksum=FALSE;
                    661: 
                    662: register int j;
                    663: int n, status;
                    664: int checksum, line;
                    665: 
                    666:     for (line = 1; ; line++)   /* for each input line */
                    667:        {
                    668:                if (fgets(inbuf, sizeof inbuf, in) == NULL)
                    669:            {
                    670:                    fprintf(stderr,"ERROR: uudecode input ended unexpectedly!\n");
                    671:                return(18);
                    672:            }
                    673: 
                    674:                status = uud_buffer(inbuf,outbuf,&n);
                    675: 
                    676:                if (status == -1)
                    677:                        fprintf(stderr,"ERROR: bad uudecode character decoding line %d.\n", line);
                    678:                if (status == -2)
                    679:                        fprintf(stderr,"ERROR: checksum mismatch decoding line %d.\n", line);
                    680:                if (n==0)       /* zero-length line is the end. */
                    681:                        break;
                    682: 
                    683:                fwrite(outbuf,1,n,out);
                    684: 
                    685:     }  /* line */
                    686: 
                    687:        return(0);      /* normal return */
                    688: }   /* uudecode */
                    689: 
                    690: 
                    691: boolean is_uufile(char *infile)
                    692: {
                    693:        FILE    *in;
                    694:        char    inbuf[80];
                    695:        char    outbuf[80];
                    696:        int i, n, status;
                    697: 
                    698:        if ((in = fopen(infile, "r")) == NULL)
                    699:     {  /* can't open file */
                    700:            return(FALSE);
                    701:     }
                    702: 
                    703:     /* search file for header line */
                    704:     for (i=0; i<50; i++)       /* give up after 50 lines of garbage */
                    705:        {
                    706:                if (fgets(inbuf, sizeof inbuf, in) == NULL)
                    707:                        break;
                    708:                else
                    709:                {
                    710:                        if (strncmp(inbuf, "begin ", 6) == 0)
                    711:                        {
                    712:                                if (fgets(inbuf, sizeof inbuf, in) == NULL)
                    713:                                        break;
                    714:                                status = uud_buffer(inbuf,outbuf,&n);
                    715:                                if (status < 0)
                    716:                                        break;
                    717:                                fclose(in);
                    718:                                return(TRUE);
                    719:                        }
                    720:                }
                    721:        }
                    722: 
                    723:        fclose(in);
                    724:        return(FALSE);
                    725: 
                    726: }      /* is_uufile */
                    727: 
                    728: 
                    729: int uud_file(char *infile, char *outfile)
                    730: {
                    731: FILE   *in, *out;
                    732: int    mode;           /* file's mode (from header) */
                    733: long   filesize;       /* theoretical file size (from header) */
                    734: char   buf[80];
                    735: int status;
                    736: 
                    737:        if ((in = fopen(infile, "r")) == NULL)
                    738:     {
                    739:            fprintf(stderr,"ERROR: can't find %s\n", infile);
                    740:            return(10);
                    741:     }
                    742: 
                    743:     /* Loop through file, searching for header.  Decode anything with a
                    744:        header, complain if there where no headers. */
                    745: 
                    746:     /* search file for header line */
                    747:     for (;;)
                    748:        {
                    749:                if (fgets(buf, sizeof buf, in) == NULL)
                    750:                {
                    751:                        fprintf(stderr,"ERROR: no `begin' line!\n");
                    752:                        fclose(in);
                    753:                        return(12);
                    754:                }
                    755:                if (strncmp(buf, "begin ", 6) == 0)
                    756:                break;
                    757:        }
                    758: 
                    759:        /* Ignore filename and mode.  Use outfile instead of dest. */
                    760:     /* sscanf(buf, "begin %o %s", &mode, dest); */
                    761: 
                    762:     /* create output file */
                    763:     if ((out = fopen(outfile, "wb")) == NULL)
                    764:        {
                    765:                fprintf(stderr,"ERROR: can't open output file %s\n", outfile);
                    766:                fclose(in);
                    767:                return(15);
                    768:        }
                    769: 
                    770:     status = uudecode(in, out);
                    771:        if (status != 0)
                    772:        {       fclose(in);
                    773:                fclose(out);
                    774:                return(status);
                    775:        }
                    776: 
                    777:     if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
                    778:        {              /* don't be overly picky about newline ^ */
                    779:                fprintf(stderr,"ERROR: no `end' line\n");
                    780:                fclose(in);
                    781:                fclose(out);
                    782:                return(16);
                    783:        }
                    784: 
                    785:     if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
                    786:        {
                    787:                sscanf(buf, "size %ld", &filesize);
                    788:                if (ftell(out) != filesize)
                    789:        {
                    790:                fprintf(stderr,"ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out));
                    791:                return(17);
                    792:            }
                    793:        }
                    794:        fclose(out);
                    795:        fclose(in);
                    796:        return(0);      /* normal return */
                    797: }   /* uud_file */
                    798: 
                    799: 
                    800: /*     End uudecode routines. */
                    801: /*---------------------------------------------------------------------*/
                    802: 
                    803: 
                    804: 
                    805: boolean legal_ctb(byte ctb)
                    806: {      /* Used to determine if nesting should be allowed. */
                    807:        boolean legal;
                    808:        byte ctbtype;
                    809:        if (!is_ctb(ctb))               /* not even a bonafide CTB */ 
                    810:                return(FALSE);
                    811:        /* Sure hope CTB internal bit definitions don't change... */
                    812:        ctbtype = (ctb & CTB_TYPE_MASK) >> 2;
                    813:        /* Only allow these CTB types to be nested... */
                    814:        legal = (
                    815:                        (ctbtype==CTB_PKE_TYPE)
                    816:                ||      (ctbtype==CTB_SKE_TYPE)
                    817:                ||      (ctbtype==CTB_CERT_SECKEY_TYPE)
                    818:                ||      (ctbtype==CTB_CERT_PUBKEY_TYPE)
                    819:                ||      (ctbtype==CTB_LITERAL_TYPE)
                    820:                ||      (ctbtype==CTB_COMPRESSED_TYPE)
                    821:                ||  (ctbtype==CTB_CKE_TYPE)
                    822:                /* || (ctbtype==CTB_CONKEY_TYPE) */
                    823:                /* || (ctbtype==CTB_MD_TYPE) */
                    824:                 );
                    825:        return(legal);
                    826: }      /* legal_ctb */
                    827: 
                    828: 
                    829: /*======================================================================*/
                    830: 
                    831: /* MDfile0(MD, f)
                    832: ** Computes and returns the message digest from a file position to eof.
                    833: ** Uses RSA Data Security, Inc. MD4 Message Digest Algorithm.
                    834: */
                    835: int MDfile0(MDstruct *MD, FILE *f)
                    836: {      byte X[64];
                    837:        int bytecount;
                    838: 
                    839:        MDbegin(MD);
                    840:        /* Process 512 bits, or 64 bytes, at a time... */
                    841:        while ((bytecount = fread(X, 1, 64, f)) != 0)
                    842:                MDupdate(MD, X, bytecount<<3);  /* pass bitcount */
                    843:        MDupdate(MD, X, 0);     /* finish with a bitcount of 0 */
                    844:        /* MDprint(MD); */
                    845: 
                    846:        return(0);      /* normal return */
                    847: }      /* MDfile0 */
                    848: 
                    849: 
                    850: /* MDfile(MD, filename)
                    851: ** Computes and returns the message digest for a specified file.
                    852: */
                    853: int MDfile(MDstruct *MD, char *filename)
                    854: {      FILE *f;
                    855:        f = fopen(filename,"rb");
                    856:        if (f == NULL) 
                    857:        {       fprintf(stderr,"Can't open file '%s'\n",filename);
                    858:                return(-1);     /* error return */
                    859:        }
                    860:        MDfile0(MD, f);
                    861:        fclose(f);
                    862:        return(0);      /* normal return */
                    863: }      /* MDfile */
                    864: 
                    865: 
                    866: /* MD_of_buffer(MD, s, len)
                    867: ** Computes and returns the message digest for buffer s.
                    868: ** len is the length in bytes of buffer s.
                    869: ** Uses RSA Data Security, Inc. MD4 Message Digest Algorithm.
                    870: */
                    871: void MD_of_buffer(MDstruct *MD, byte *s, int len)
                    872: {      int i;
                    873: 
                    874:        MDbegin(MD);
                    875:        /* Process 512 bits, or 64 bytes, at a time... */
                    876:        for (i=0; i+64<=len; i+=64) 
                    877:                MDupdate(MD, s+i, 512);
                    878:        MDupdate(MD, s+i, (len-i)<<3);  /* finish with short block */
                    879:        /* MDprint(MD); */
                    880: 
                    881: }      /* MD_of_buffer */
                    882: 
                    883: 
                    884: boolean equal_buffers(byte *buf1, byte *buf2, word16 count)
                    885: /*     Compares two byte buffers. */
                    886: {      while (count--)
                    887:                if (*buf1++ != *buf2++)
                    888:                        return(FALSE);  /* mismatch. */
                    889:        return(TRUE);   /* compares OK */
                    890: }      /* equal_buffers */
                    891: 
                    892: 
                    893: char *buildfilename(char *result, char *fname)
                    894: /*     Builds a filename with a complete path specifier from the environmental
                    895:        variable PGPPATH.  Assumes MSDOS pathname conventions.
                    896: */
                    897: {      char *s = getenv(PGPPATH);
                    898:        if (strlen(s) > 50)     /* too long to use */
                    899:                s = "";
                    900:        strcpy(result,s);
                    901:        if (strlen(result) != 0)
                    902:                if (result[strlen(result)-1] != '\\')
                    903:                        strcat(result,"\\");
                    904:        strcat(result,fname);
                    905:        return(result);
                    906: }      /* buildfilename */
                    907: 
                    908: 
                    909: int strong_pseudorandom(byte *buf, int bufsize)
                    910: /*     Reads BassOmatic random key and random number seed from file, 
                    911:        cranks the the seed through the bassrand strong pseudorandom 
                    912:        number generator, and writes them back out.  This is used for
                    913:        generation of cryptographically strong pseudorandom numbers.
                    914:        This is mainly to save the user the trouble of having to 
                    915:        type in lengthy keyboard sequences for generation of truly
                    916:        random numbers every time we want to make a random BassOmatic
                    917:        session key.  This pseudorandom generator will only work if
                    918:        the file containing the random seed exists and is not empty.
                    919:        If it doesn't exist, it will be automatically created.
                    920:        If it exists and is empty or nearly empty, it will not be used.
                    921: */
                    922: {      char seedfile[64];      /* Random seed filename */
                    923:        FILE *f;
                    924:        byte key[64];   /* not to exceed 256 byes in length */
                    925:        byte seed[256]; /* not to exceed 256 byes in length */
                    926:        int i;
                    927:        word32 tstamp; byte *timestamp = (byte *) &tstamp;
                    928: 
                    929:        buildfilename(seedfile,RANDSEED_FILENAME);
                    930: 
                    931:        if (!file_exists(seedfile))     /* No seed file. Start one... */
                    932:        {       f = fopen(seedfile,"wb");       /* open for writing binary */
                    933:                if (f==NULL)    /* failed to create seedfile */
                    934:                        return(-1);     /* error: no random number seed file available */
                    935:                fclose(f);      /* close new empty seed file */
                    936:                /* kickstart the generator with true random numbers */ 
                    937:                fprintf(stderr,"Initializing random seed file...");
                    938:                randaccum(8*(sizeof(key)+32)); 
                    939:                for (i=1; i<sizeof(key); i++)
                    940:                        key[i] ^= randombyte();
                    941:                for (i=0; i<sizeof(seed); i++)
                    942:                        seed[i] ^= randombyte();
                    943:        }       /* seedfile does not exist */
                    944: 
                    945:        else    /* seedfile DOES exist.  Open it and read it. */
                    946:        {       f = fopen(seedfile,"rb");       /* open for reading binary */
                    947:                if (f==NULL)    /* did open fail? */
                    948:                        return(-1);     /* error: no random number seed file available */
                    949:                /* read BassOmatic random generator key */
                    950:                if (fread(key,1,sizeof(key),f) < sizeof(key))   /* empty file? */
                    951:                {       /* Empty or nearly empty file means don't use it. */
                    952:                        fclose(f);
                    953:                        return(-1);     /* error: no random number seed file available */
                    954:                }
                    955:                else
                    956:                        fread(seed,1,sizeof(seed),f); /* read pseudorandom seed */
                    957:                fclose(f);
                    958:        }       /* seedfile exists */
                    959: 
                    960: 
                    961:        get_timestamp(timestamp);
                    962:        for (i=0; i<4; i++)
                    963:                key[i+1] ^= timestamp[i];
                    964: 
                    965:        key[0] = 0x0f;  /* BassOmatic key control byte */
                    966: 
                    967:        /* Initialize, key, and seed the BassOmatic pseudorandom generator: */
                    968:        initbassrand(key, sizeof(key), seed, sizeof(seed));
                    969: 
                    970:        /* Note that the seed will be cycled thru BassOmatic once before use */
                    971: 
                    972:        /* Now fill the user's buffer with gobbledygook... */
                    973:        while (bufsize--)
                    974:                *buf++ = bassrand() ^ randombyte();
                    975: 
                    976:        /* now cover up evidence of what user got */
                    977:        for (i=1; i<sizeof(key); i++)
                    978:                key[i] ^= bassrand() ^ randombyte();
                    979:        for (i=0; i<sizeof(seed); i++)
                    980:                seed[i] = bassrand() ^ randombyte();
                    981: 
                    982:        closebass();    /* close BassOmatic random number generator */
                    983: 
                    984:        f = fopen(seedfile,"wb");       /* open for writing binary */
                    985:        if (f==NULL)    /* did open fail? */
                    986:                return(-1);     /* error: no random number seed file available */
                    987:        /* Now at start of file again */
                    988:        fwrite(key,1,sizeof(key),f);
                    989:        fwrite(seed,1,sizeof(seed),f);
                    990:        fclose(f);
                    991:        burn(key);              /* burn sensitive data on stack */
                    992:        burn(seed);             /* burn sensitive data on stack */
                    993:        return(0);      /* normal return */
                    994: }      /* strong_pseudorandom */
                    995: 
                    996: 
                    997: 
                    998: int make_random_basskey(byte *key, int keybytes)
                    999: /*     Make a keybytes-byte random BassOmatic key, plus 1 key control byte.
                   1000:        The byte count returned includes key control byte.
                   1001: */
                   1002: {      int count;
                   1003: 
                   1004:        key[0] = 0x1f;  /* Default is Military grade BassOmatic key control byte */
                   1005:        if (keybytes <= 24)
                   1006:                key[0] = 0x12;  /* Commercial grade BassOmatic key control byte */
                   1007:        if (keybytes <= 16)
                   1008:                key[0] = 0x00;  /* Casual grade BassOmatic key control byte */
                   1009: 
                   1010:        if (strong_pseudorandom(key+1, keybytes) == 0)
                   1011:                return(keybytes+1); /* return length of key, including control byte */
                   1012: 
                   1013:        fprintf(stderr,"Preparing random conventional crypto session key...");
                   1014: 
                   1015:        randaccum(keybytes*8); /* get some random key bits */
                   1016: 
                   1017:        count=0;
                   1018:        while (++count <= keybytes)
                   1019:                key[count] = randombyte();
                   1020: 
                   1021:        return(count+1);        /* return length of key, including control byte */
                   1022: 
                   1023: }      /* make_random_basskey */
                   1024: 
                   1025: 
                   1026: 
                   1027: void copyfile(FILE *f, FILE *g, word32 longcount)
                   1028: {      /* copy file f to file g, for longcount bytes */
                   1029:        int count;
                   1030:        byte textbuf[diskbufsize];
                   1031:        do      /* read and write the whole file... */
                   1032:        {
                   1033:                if (longcount < (word32) diskbufsize)
                   1034:                        count = longcount;
                   1035:                else
                   1036:                        count = diskbufsize;
                   1037:                count = fread(textbuf,1,count,f);
                   1038:                if (count>0)
                   1039:                {       fwrite(textbuf,1,count,g);
                   1040:                        longcount -= count;
                   1041:                }
                   1042:                /* if text block was short, exit loop */
                   1043:        } while (count==diskbufsize);
                   1044:        burn(textbuf);  /* burn sensitive data on stack */
                   1045: }      /* copyfile */
                   1046: 
                   1047: 
                   1048: word32 getpastlength(byte ctb, FILE *f)
                   1049: /*     Returns the length of a packet according to the CTB and 
                   1050:        the length field. */
                   1051: {      word32 length;
                   1052:        int llength;    /* length of length */
                   1053:        byte buf[8];
                   1054: 
                   1055:        fill0(buf,sizeof(buf));
                   1056:        length = 0L;
                   1057:        /* Use ctb length-of-length field... */
                   1058:        llength = ctb_llength(ctb);     /* either 1, 2, 4, or 8 */
                   1059:        if (llength==8)         /* 8 means no length field, assume huge length */ 
                   1060:                return(-1L);    /* return huge length */
                   1061: 
                   1062:        /* now read in the actual length field... */
                   1063:        if (fread((byteptr) buf,1,llength,f) < llength)
                   1064:                return (-2L); /* error -- read failure or premature eof */
                   1065:        /* convert length from external LSB-first format... */
                   1066:        while (llength--)
                   1067:        {       length <<= 8;
                   1068:                length += buf[llength];
                   1069:        }
                   1070:        return(length);
                   1071: }      /* getpastlength */
                   1072: 
                   1073: 
                   1074: 
                   1075: int bass_file(byte *basskey, int lenbasskey, boolean decryp, 
                   1076:                FILE *f, FILE *g)
                   1077: /*     Use BassOmatic in cipher feedback (CFB) mode to encrypt 
                   1078:        or decrypt a file.  Encrypted key check bytes determine
                   1079:        if correct BassOmatic key was used to decrypt ciphertext.
                   1080: */
                   1081: {      int count;
                   1082:        byte textbuf[diskbufsize], iv[256];
                   1083: #define KEYCHECKLENGTH 4
                   1084: 
                   1085:        /* init CFB BassOmatic key */
                   1086:        fill0(iv,256);  /* define initialization vector IV as 0 */
                   1087:        if ( initcfb(iv,basskey,lenbasskey,decryp) < 0 )
                   1088:                return(-1);     /* Error return should be impossible. */
                   1089: 
                   1090:        if (!decryp)    /* encrypt-- insert key check bytes */
                   1091:        {       /* key check bytes are 2 copies of 16 random bits */
                   1092:                textbuf[0] = randombyte();
                   1093:                textbuf[1] = randombyte();
                   1094:                textbuf[2] = textbuf[0];
                   1095:                textbuf[3] = textbuf[1];
                   1096:                basscfb(textbuf,KEYCHECKLENGTH);
                   1097:                fwrite(textbuf,1,KEYCHECKLENGTH,g);
                   1098:        }
                   1099:        else    /* decrypt-- check for key check bytes */
                   1100:        {       /* See if there are 2 copies of 16 random bits */
                   1101:                count = fread(textbuf,1,KEYCHECKLENGTH,f);
                   1102:                if (count==KEYCHECKLENGTH)
                   1103:                {       basscfb(textbuf,KEYCHECKLENGTH);
                   1104:                        if ((textbuf[0] != textbuf[2])
                   1105:                                || (textbuf[1] != textbuf[3]))
                   1106:                        {       return(-2);             /* bad key error */
                   1107:                        }
                   1108:                }
                   1109:                else    /* file too short for key check bytes */
                   1110:                        return(-3);             /* error of the weird kind */
                   1111:        }
                   1112: 
                   1113: 
                   1114:        do      /* read and write the whole file in CFB mode... */
                   1115:        {       count = fread(textbuf,1,diskbufsize,f);
                   1116:                if (count>0)
                   1117:                {       basscfb(textbuf,count);
                   1118:                        fwrite(textbuf,1,count,g);
                   1119:                }
                   1120:                /* if text block was short, exit loop */
                   1121:        } while (count==diskbufsize);
                   1122: 
                   1123:        closebass();    /* release BassOmatic resources */
                   1124:        burn(textbuf);  /* burn sensitive data on stack */
                   1125:        return(0);      /* should always take normal return */
                   1126: }      /* bass_file */
                   1127: 
                   1128: 
                   1129: 
                   1130: int read_mpi(unitptr r, FILE *f, boolean adjust_precision, boolean scrambled)
                   1131: /*     Read a mutiprecision integer from a file.
                   1132:        adjust_precision is TRUE iff we should call set_precision to the 
                   1133:        size of the number read in.
                   1134:        scrambled is TRUE iff field is encrypted (protects secret key fields).
                   1135:        Returns the bitcount of the number read in, or returns a negative 
                   1136:        number if an error is detected.
                   1137: */
                   1138: {      byte buf[MAX_BYTE_PRECISION+2];
                   1139:        int count;
                   1140:        word16 bytecount,bitcount,lowcount,highcount;
                   1141: 
                   1142:        mp_init(r,0);
                   1143: 
                   1144:        if ((count = fread(buf,1,2,f)) < 2)
                   1145:                return (-1); /* error -- read failure or premature eof */
                   1146: 
                   1147:        /* Assumes external format is LSB-first */
                   1148:        bitcount = (((word16) buf[1]) << 8) + (word16) buf[0];
                   1149:        if (bits2units(bitcount) > global_precision)
                   1150:                return(-1);     /* error -- possible corrupted bitcount */
                   1151: 
                   1152:        bytecount = bits2bytes(bitcount);
                   1153: 
                   1154:        count = fread(buf+2,1,bytecount,f);
                   1155:        if (count < bytecount)
                   1156:                return(-1);     /* error -- premature eof */
                   1157: 
                   1158:        if (scrambled)  /* decrypt the field */
                   1159:                basscfb(buf+2,bytecount);
                   1160: 
                   1161:        /*      We assume that the bitcount prefix we read is an exact
                   1162:                bitcount, not rounded up to the next byte boundary.
                   1163:                Otherwise we would have to call mpi2reg, then call
                   1164:                countbits, then call set_precision, then recall mpi2reg
                   1165:                again.
                   1166:        */
                   1167:        if (adjust_precision && bytecount)
                   1168:        {       /* set the precision to that specified by the number read. */
                   1169:                set_precision(bits2units(bitcount+SLOP_BITS));
                   1170:                /* Now that precision is optimally set, call mpi2reg */
                   1171:        }
                   1172: 
                   1173:        mpi2reg(r,buf); /* convert to internal format */
                   1174:        burn(buf);      /* burn sensitive data on stack */
                   1175:        return (bitcount);
                   1176: }      /* read_mpi */
                   1177: 
                   1178: 
                   1179: 
                   1180: void write_mpi(unitptr n, FILE *f, boolean scrambled)
                   1181: /*     Write a multiprecision integer to a file.
                   1182:        scrambled is TRUE iff we should scramble field on the way out,
                   1183:        which is used to protect secret key fields.
                   1184: */
                   1185: {      byte buf[MAX_BYTE_PRECISION+2];
                   1186:        short bytecount;
                   1187:        bytecount = reg2mpi(buf,n);
                   1188:        if (scrambled)  /* encrypt the field, skipping over the bitcount */
                   1189:                basscfb(buf+2,bytecount);
                   1190:        fwrite(buf,1,bytecount+2,f); 
                   1191:        burn(buf);      /* burn sensitive data on stack */
                   1192: }      /* write_mpi */
                   1193: 
                   1194: 
                   1195: 
                   1196: void showkeyID(byte *buf)
                   1197: /*     Print key fragment, which is an abbreviation or "fingerprint" 
                   1198:        of the key.
                   1199:        Show LEAST significant 64 bits (KEYFRAGSIZE bytes) of modulus,
                   1200:        LSB last.  Yes, that's LSB LAST.
                   1201: */
                   1202: {      short i,j;
                   1203:        /* fputc('[',stderr); */
                   1204:        j = KEYFRAGSIZE;
                   1205:        for (i=KEYFRAGSIZE-1; i>=0; i--)        /* print LSB last */
                   1206:        {       if (--j < 3)    /* only show bottom 3 bytes of keyID */
                   1207:                        fprintf(stderr,"%02X",buf[i]);
                   1208:        }
                   1209:        /* fputc(']',stderr); */
                   1210: }      /* showkeyID */
                   1211: 
                   1212: 
                   1213: 
                   1214: void extract_keyID(byteptr keyID, unitptr n)
                   1215: /*     Extract key fragment from modulus n.  keyID byte array must be
                   1216:        at least KEYFRAGSIZE bytes long.
                   1217: */
                   1218: {      byte buf[MAX_BYTE_PRECISION+2];
                   1219:        short i, j;
                   1220: 
                   1221:        fill0(buf,KEYFRAGSIZE+2); /* in case n is too short */
                   1222:        reg2mpi(buf,n); /* MUST be at least KEYFRAGSIZE long */
                   1223:        /* For low-byte-first keyID format, start of keyID is: */
                   1224:        i = 2;  /* skip over the 2 bytes of bitcount */
                   1225:        for (j=0; j<KEYFRAGSIZE; )
                   1226:                keyID[j++] = buf[i++];
                   1227: 
                   1228: }      /* extract_keyID */
                   1229: 
                   1230: 
                   1231: 
                   1232: void writekeyID(unitptr n, FILE *f)
                   1233: /*     Write message prefix keyID to a file.
                   1234:        n is key modulus from which to extract keyID.
                   1235: */
                   1236: {      byte keyID[KEYFRAGSIZE];
                   1237:        extract_keyID(keyID, n);
                   1238:        fwrite(keyID,1,KEYFRAGSIZE,f);
                   1239: }      /* writekeyID */
                   1240: 
                   1241: 
                   1242: 
                   1243: void showkeyID2(unitptr n)
                   1244: /*     Derive the key abbreviation fragment from the modulus n, and print it.
                   1245:        n is key modulus from which to extract keyID.
                   1246: */
                   1247: {      byte keyID[KEYFRAGSIZE];
                   1248:        extract_keyID(keyID, n);
                   1249:        showkeyID(keyID);
                   1250: }      /* showkeyID2 */
                   1251: 
                   1252: 
                   1253: 
                   1254: boolean checkkeyID(byte *keyID, unitptr n)
                   1255: /*     Compare specified keyID with one derived from actual key modulus n. */
                   1256: {
                   1257:        byte keyID0[KEYFRAGSIZE];
                   1258:        if (keyID==NULL) /* no key ID -- assume a good match */
                   1259:                return (TRUE);
                   1260:        extract_keyID(keyID0, n);
                   1261:        return(equal_buffers(keyID,keyID0,KEYFRAGSIZE));
                   1262: }      /* checkkeyID */
                   1263: 
                   1264: 
                   1265: 
                   1266: /* external function prototype, from rsaio.c */
                   1267: void dump_unit_array(string s, unitptr r);
                   1268: 
                   1269: 
                   1270: short writekeyfile(char *fname, boolean hidekey, byte *timestamp, byte *userid, 
                   1271:        unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
                   1272: /*     Write key components p, q, n, e, d, and u to specified file.
                   1273:        hidekey is TRUE iff key should be encrypted.
                   1274:        userid is a length-prefixed Pascal-type character string. 
                   1275: */
                   1276: {      FILE *f;
                   1277:        byte ctb,c;
                   1278:        word16 cert_length;
                   1279:        /* open file f for write, in binary (not text) mode...*/
                   1280:        if ((f = fopen(fname,"wb")) == NULL)
                   1281:        {       fprintf(stderr,"\n\aCan't create key file '%s'\n",fname);
                   1282:                return(-1);
                   1283:        }
                   1284:        else
                   1285:        {
                   1286:                /*** Begin key certificate header fields ***/
                   1287:                if (d==NULL)
                   1288:                {       /* public key certificate */
                   1289:                        ctb = CTB_CERT_PUBKEY;
                   1290:                        cert_length = SIZEOF_TIMESTAMP + userid[0]+1 + (countbytes(n)+2) 
                   1291:                                + (countbytes(e)+2); /* no crc16 */
                   1292:                }       /* public key certificate */
                   1293:                else
                   1294:                {       /* secret key certificate */
                   1295:                        ctb = CTB_CERT_SECKEY;
                   1296:                                cert_length = SIZEOF_TIMESTAMP + userid[0]+1    
                   1297:                                + (countbytes(n)+2)
                   1298:                                + (countbytes(e)+2)     + (countbytes(d)+2) 
                   1299:                                + (countbytes(p)+2)     + (countbytes(q)+2) 
                   1300:                                + (countbytes(u)+2); /* no crc16 */
                   1301: 
                   1302:                }       /* secret key certificate */
                   1303: 
                   1304:                fwrite(&ctb,1,1,f);             /* write key certificate header byte */
                   1305:                convert(cert_length);   /* convert to external byteorder */
                   1306:                fwrite(&cert_length,1,sizeof(cert_length),f);
                   1307:                hilo_swap(timestamp,4); /* convert to external LSB-first form */
                   1308:                fwrite(timestamp,1,4,f); /* write certificate timestamp */
                   1309:                hilo_swap(timestamp,4); /* convert back to internal form */
                   1310:                fwrite(userid,1,userid[0]+1,f); /* write user ID */
                   1311:                write_mpi(n,f,FALSE);
                   1312:                write_mpi(e,f,FALSE);
                   1313: 
                   1314:                if (is_secret_key(ctb)) /* secret key */
                   1315:                {       
                   1316:                        write_mpi(d,f,hidekey);
                   1317:                        write_mpi(p,f,hidekey);
                   1318:                        write_mpi(q,f,hidekey);
                   1319:                        write_mpi(u,f,hidekey);
                   1320:                }
                   1321:                fclose(f);
                   1322: #ifdef DEBUG
                   1323:                fprintf(stderr,"\n%d-bit %s key written to file '%s'.\n",
                   1324:                        countbits(n),
                   1325:                        is_secret_key(ctb) ? "secret" : "public" ,
                   1326:                        fname);
                   1327: #endif
                   1328:                return(0);
                   1329:        }
                   1330: }      /* writekeyfile */
                   1331: 
                   1332: 
                   1333: /*======================================================================*/
                   1334: 
                   1335: 
                   1336: int get_header_info_from_file(char *infile,  byte *header, int count)
                   1337: /*     Reads the first count bytes from infile into header. */
                   1338: {      FILE *f;
                   1339:        fill0(header,count);
                   1340:        /* open file f for read, in binary (not text) mode...*/
                   1341:        if ((f = fopen(infile,"rb")) == NULL)
                   1342:                return(-1);
                   1343:        /* read Cipher Type Byte, and maybe more */
                   1344:        count = fread(header,1,count,f);
                   1345:        fclose(f);
                   1346:     return(count);     /* normal return */
                   1347: }      /* get_header_info_from_file */
                   1348: 
                   1349: 
                   1350: 
                   1351: short readkeypacket(FILE *f, boolean hidekey, byte *ctbyte, 
                   1352:        byte *timestamp, char *userid,
                   1353:        unitptr n ,unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
                   1354: /*     Reads a key certificate from the current file position of file f.
                   1355:        It will return the ctb, timestamp, userid, public key components 
                   1356:        n and e, and if the secret key components are present in the 
                   1357:        certificate and d is not a NULL, it will read and return d, p, q, 
                   1358:        and u.  The file pointer is left positioned after the certificate.
                   1359:        hidekey is TRUE iff key is expected to be encrypted.
                   1360: */
                   1361: {
                   1362:        byte ctb;
                   1363:        word32 cert_length;
                   1364:        long file_position;
                   1365:        int count;
                   1366: 
                   1367:        set_precision(MAX_UNIT_PRECISION);      /* safest opening assumption */
                   1368: 
                   1369:        /*** Begin certificate header fields ***/
                   1370:        *ctbyte = 0;    /* assume no ctbyte for caller at first */
                   1371:        count = fread(&ctb,1,1,f);      /* read key certificate CTB byte */
                   1372:        if (count==0) return(-1);       /* premature eof */
                   1373:        *ctbyte = ctb;  /* returns type to caller */
                   1374:        if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY))
                   1375:                return(-2);     /* not a key certificate */
                   1376: 
                   1377:        cert_length = getpastlength(ctb, f); /* read certificate length */
                   1378: 
                   1379:        if (cert_length > MAX_KEYCERT_LENGTH-3)
                   1380:                return(-3);     /* bad length */
                   1381: 
                   1382:        fread(timestamp,1,4,f); /* read certificate timestamp */
                   1383:        /* note that hilo_swap does nothing if this is a LSB-first CPU */
                   1384:        hilo_swap(timestamp,4); /* convert from external LSB-first form */
                   1385:        count = fread(userid,1,1,f);    /* read user ID length byte */
                   1386:        if (count==0) return(-1);       /* premature eof */
                   1387:        fread(userid+1,1,userid[0],f); /* read rest of user ID */
                   1388:        /*** End certificate header fields ***/
                   1389: 
                   1390:        /* We're past certificate headers, now look at some key material...*/
                   1391: 
                   1392:        if (read_mpi(n,f,TRUE,FALSE) < 0)
                   1393:                return(-4);     /* data corrupted, return error */
                   1394: 
                   1395:        /* Note that precision was adjusted for n */
                   1396: 
                   1397:        if (read_mpi(e,f,FALSE,FALSE) < 0)
                   1398:                return(-4);     /* data corrupted, error return */
                   1399: 
                   1400:        cert_length -= SIZEOF_TIMESTAMP + userid[0]+1 + 
                   1401:                (countbytes(n)+2) + (countbytes(e)+2);
                   1402: 
                   1403:        if (d==NULL)    /* skip rest of this key certificate */
                   1404:        {       fseek(f, cert_length, SEEK_CUR);
                   1405:                cert_length = 0;        /* because we are skipping secret fields */
                   1406:        }
                   1407:        else    /* d is not NULL */
                   1408:        {       if (is_secret_key(ctb))
                   1409:                {
                   1410:                        if (read_mpi(d,f,FALSE,hidekey) < 0)
                   1411:                                return(-4);     /* data corrupted, error return */
                   1412:                        if (read_mpi(p,f,FALSE,hidekey) < 0)
                   1413:                                return(-4);     /* data corrupted, error return */
                   1414:                        if (read_mpi(q,f,FALSE,hidekey) < 0)
                   1415:                                return(-4);     /* data corrupted, error return */
                   1416:        
                   1417:                        /* use register 'u' briefly as scratchpad */
                   1418:                        mp_mult(u,p,q); /* compare p*q against n */
                   1419:                        if (mp_compare(n,u)!=0) /* bad pass phrase? */
                   1420:                                return(-5);     /* possible bad pass phrase, error return */
                   1421:                        /* now read in real u */
                   1422:                        if (read_mpi(u,f,FALSE,hidekey) < 0)
                   1423:                                return(-4);     /* data corrupted, error return */
                   1424: 
                   1425:                        cert_length -= (countbytes(d)+2) + (countbytes(p)+2) 
                   1426:                                + (countbytes(q)+2) + (countbytes(u)+2);
                   1427: 
                   1428:                }       /* secret key */
                   1429:                else /* not a secret key */
                   1430:                {       mp_init(d,0);
                   1431:                        mp_init(p,0);
                   1432:                        mp_init(q,0);
                   1433:                        mp_init(u,0);
                   1434:                }
                   1435:        }       /* d != NULL */
                   1436: 
                   1437:        if (cert_length != 0)
                   1438:        {       fprintf(stderr,"\n\aCorrupted key.  Bad length, off by %d bytes.\n",
                   1439:                        (signed int) cert_length);
                   1440:                return(-4);     /* data corrupted, error return */
                   1441:        }
                   1442: 
                   1443:        return(0);      /* normal return */
                   1444: 
                   1445: }      /* readkeypacket */
                   1446: 
                   1447: 
                   1448: 
                   1449: int getpublickey(boolean giveup, boolean showkey, char *keyfile, 
                   1450:        long *file_position, int *pktlen, byte *keyID, byte *timestamp, 
                   1451:        byte *userid, unitptr n, unitptr e)
                   1452: /*     keyID contains key fragment we expect to find in keyfile.
                   1453:        If keyID is NULL, then userid contains a C string search target of
                   1454:        userid to find in keyfile.
                   1455:        keyfile is the file to begin search in, and it may be modified
                   1456:        to indicate true filename of where the key was found.  It can be
                   1457:        either a public key file or a secret key file.
                   1458:        file_position is returned as the byte offset within the keyfile 
                   1459:        that the key was found at.
                   1460:        giveup is TRUE iff we are just going to do a single file search only.
                   1461: */
                   1462: {
                   1463:        int keytype;    /* 1 for secret key, 0 for public key */
                   1464:        byte ctb;       /* returned by readkeypacket */
                   1465:        FILE *f;
                   1466:        int status;
                   1467:        boolean keyfound = FALSE;
                   1468:        boolean secret;         /* indicates we are called by getsecretkey */
                   1469:        char userid0[256];      /* C string format */
                   1470: 
                   1471:        userid0[0] = '\0';
                   1472:        secret = strcontains(keyfile,SEC_EXTENSION);
                   1473: 
                   1474:        if (keyID==NULL)        /* then userid has search target */
                   1475:                strcpy(userid0,userid);
                   1476: 
                   1477: top:
                   1478:        if (secret)
                   1479:                default_extension(keyfile,SEC_EXTENSION);
                   1480:        else
                   1481:                default_extension(keyfile,PUB_EXTENSION);
                   1482: 
                   1483:        if (!file_exists(keyfile))
                   1484:        {       if (giveup)
                   1485:                        return(-1);     /* give up, error return */
                   1486:                fprintf(stderr,"\nKeyring file '%s' does not exist. ",keyfile);
                   1487:                goto nogood;
                   1488:        }
                   1489:        if (verbose) fprintf(stderr,"\nSearching key ring file '%s'.\n",keyfile);
                   1490: 
                   1491:        /* open file f for read, in binary (not text) mode...*/
                   1492:        if ((f = fopen(keyfile,"rb")) == NULL)
                   1493:                return(-1);     /* error return */
                   1494: 
                   1495:        while (TRUE) 
                   1496:        {
                   1497:                *file_position = ftell(f);
                   1498:                status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
                   1499:                                NULL,NULL,NULL,NULL);
                   1500:                /* Note that readkeypacket has called set_precision */
                   1501: 
                   1502:                if (status == -1)       /* end of file */
                   1503:                        break;
                   1504: 
                   1505:                if (status < -1)
                   1506:                {       fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
                   1507:                                keyfile);
                   1508:                        fclose(f);      /* close key file */
                   1509:                        return(-1);
                   1510:                }
                   1511: 
                   1512:                /* keyID contains key fragment.  Check it against n from keyfile. */
                   1513:                if (keyID!=NULL)
                   1514:                        keyfound = checkkeyID(keyID,n);
                   1515:                else
                   1516:                {       /* userid0 is already a C string */
                   1517:                        PascalToC(userid);      /* for C string functions */
                   1518:                        keyfound = strcontains(userid,userid0); /* any matching subset? */
                   1519:                        /* keyfound = (strcmp(userid,userid0)==0); /* exact match? */
                   1520:                        CToPascal(userid);
                   1521:                }
                   1522: 
                   1523:                if (keyfound)
                   1524:                {       *pktlen = (ftell(f) - *file_position);
                   1525:                        if (showkey)
                   1526:                        {       PascalToC(userid);      /* for display */
                   1527:                                fprintf(stderr,"\nKey for user ID: %s\n",userid);
                   1528:                                CToPascal(userid);
                   1529:                                fprintf(stderr,"%d-bit key, Key ID ",countbits(n));
                   1530:                                showkeyID2(n);
                   1531:                                fprintf(stderr,", created %s",ctime((long *)timestamp));
                   1532:                        }
                   1533:                        fclose(f);
                   1534:                        return(0);      /* normal return */
                   1535:                }
                   1536:        }       /* while TRUE */
                   1537: 
                   1538:        fclose(f);      /* close key file */
                   1539: 
                   1540:        if (giveup)
                   1541:                return(-1);     /* give up, error return */
                   1542: 
                   1543:        if (keyID!=NULL)
                   1544:        {
                   1545:                fprintf(stderr,"\n\aKey matching expected Key ID ");
                   1546:                showkeyID(keyID);
                   1547:                fprintf(stderr," not found in file '%s'.\n",keyfile);
                   1548:        }
                   1549:        else
                   1550:        {       fprintf(stderr,"\n\aKey matching userid '%s' not found in file '%s'.\n",
                   1551:                        userid0,keyfile);
                   1552:        }
                   1553: 
                   1554: nogood:
                   1555:        if (giveup)
                   1556:                return(-1);     /* give up, error return */
                   1557: 
                   1558:        if (secret)
                   1559:                fprintf(stderr,"Enter secret key filename: ");
                   1560:        else
                   1561:                fprintf(stderr,"Enter public key filename: ");
                   1562: 
                   1563:        getstring(keyfile,59,TRUE);     /* echo keyboard input */
                   1564:        if (strlen(keyfile) > 0)
                   1565:                goto top;
                   1566: 
                   1567:        return(-1);     /* give up, error return */
                   1568: 
                   1569: }      /* getpublickey */
                   1570: 
                   1571: 
                   1572: 
                   1573: int getsecretkey(byte *keyID, byte *timestamp, byte *userid, 
                   1574:        unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
                   1575: /*     keyID contains key fragment we expect to find in keyfile.
                   1576:        If keyID is NULL, then userid contains search target of
                   1577:        userid to find in keyfile.
                   1578: */
                   1579: {
                   1580:        byte ctb;       /* returned by readkeypacket */
                   1581:        FILE *f;
                   1582:        char keyfile[64];       /* for getpublickey */
                   1583:        long file_position;
                   1584:        int pktlen;     /* unused, just to satisfy getpublickey */
                   1585:        int status;
                   1586:        boolean hidekey = FALSE;        /* TRUE iff secret key is encrypted */
                   1587:        char passphrase[256];
                   1588:        byte iv[256];   /* for BassOmatic CFB mode */
                   1589:        int guesses = 3;
                   1590: 
                   1591:        buildfilename(keyfile,SECRET_KEYRING_FILENAME); /* use default pathname */
                   1592: 
                   1593:        status = getpublickey(FALSE, TRUE, keyfile, &file_position, &pktlen,
                   1594:                        keyID, timestamp, userid, n, e);
                   1595:        if (status < 0)
                   1596:                return(status); /* error return */
                   1597: 
                   1598:        /* open file f for read, in binary (not text) mode...*/
                   1599:        if ((f = fopen(keyfile,"rb")) == NULL)
                   1600:                return(-1);     /* error return */
                   1601: 
                   1602:        /* First guess is null password, so hidekey is FALSE */
                   1603: 
                   1604:        do      /* until good password */
                   1605:        {       /* init CFB BassOmatic key */
                   1606:                if (hidekey)
                   1607:                {       fill0(iv,256);  /* define initialization vector IV as 0 */
                   1608:                        if ( initcfb(iv,passphrase,string_length(passphrase),TRUE) < 0 )
                   1609:                        {       fclose(f);      /* close key file */
                   1610:                                return(-1);
                   1611:                        }
                   1612:                }
                   1613:                burn(passphrase);       /* burn sensitive data on stack */
                   1614:                fseek(f,file_position,SEEK_SET); /* reposition file to key */
                   1615:                status = readkeypacket(f,hidekey,&ctb,timestamp,userid,n,e,d,p,q,u);
                   1616:                if (hidekey) 
                   1617:                        closebass();    /* release BassOmatic resources */
                   1618: 
                   1619:                if (status == -5)       /* bad pass phrase status */
                   1620:                {       if (guesses!=3) /* not first guess of null password? */
                   1621:                                fprintf(stderr,"\n\aUnreadable secret key.  Possible bad pass phrase.\n");
                   1622:                        if (--guesses)  /* not ran out of guesses yet */
                   1623:                        {       fprintf(stderr,"\nYou need a pass phrase to unlock your RSA secret key. ");
                   1624:                                hidekey = (getpassword(passphrase,1,0x0f) > 0);
                   1625:                                continue;       /* take it from the top */
                   1626:                        }       /* more guesses to go */
                   1627:                }
                   1628:                if (status < 0)
                   1629:                {       fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
                   1630:                                keyfile);
                   1631:                        fclose(f);      /* close key file */
                   1632:                        return(-1);
                   1633:                }
                   1634:        }       while (status < 0);     /* until key reads OK, with good password */
                   1635: 
                   1636:        fclose(f);      /* close key file */
                   1637: 
                   1638:        if (!hidekey) 
                   1639:                fprintf(stderr,"\nAdvisory warning: This RSA secret key is not protected by a passphrase.\n");
                   1640:        else
                   1641:                fprintf(stderr,"Pass phrase is good.  ");
                   1642: 
                   1643:        /* Note that readkeypacket has called set_precision */
                   1644: 
                   1645:        if (testeq(d,0))        /* didn't get secret key components */
                   1646:        {       fprintf(stderr,"\n\aKey file '%s' is not a secret key file.\n",keyfile);
                   1647:                return(-1);
                   1648:        }
                   1649: 
                   1650:        return(0);      /* normal return */
                   1651: 
                   1652: }      /* getsecretkey */
                   1653: 
                   1654: 
                   1655: 
                   1656: int make_signature_certificate(byte *certificate, MDstruct *MD, 
                   1657:        byte *userid, unitptr n, unitptr d, unitptr p, unitptr q, unitptr u)
                   1658: /*     Constructs a signed message digest in a signature certificate.
                   1659:        Returns total certificate length in bytes, or returns negative 
                   1660:        error status.
                   1661: */
                   1662: {      
                   1663:        byte inbuf[MAX_BYTE_PRECISION], outbuf[MAX_BYTE_PRECISION];
                   1664:        byte mdpacket[32];
                   1665:        byte *mdbufptr;
                   1666:        int i,j,certificate_length,blocksize,bytecount;
                   1667:        word16 useridlength,certsig_length,mdp_length,ske_length;
                   1668:        word32 tstamp; byte *timestamp = (byte *) &tstamp;
                   1669:        byte keyID[KEYFRAGSIZE];
                   1670: 
                   1671:        /*      Note that RSA key must be at least big enough to encipher a 
                   1672:                complete message digest packet in a single RSA block. */
                   1673: 
                   1674:        blocksize = countbytes(n)-1;    /* size of a plaintext block */
                   1675:        if (blocksize < 31)
                   1676:        {       fprintf(stderr,"\n\aError: RSA key length must be at least 256 bits.\n");
                   1677:                return(-1);
                   1678:        }
                   1679: 
                   1680:        get_timestamp(timestamp);       /* Timestamp when signature was made */
                   1681:        hilo_swap(timestamp,4); /* convert to external LSB-first form */
                   1682: 
                   1683:        fill0(mdpacket,sizeof(mdpacket));
                   1684:        mdpacket[0] = CTB_MD;   /* Message Digest type */
                   1685:        /* mdp_length includes algorithm byte, MD, and timestamp. */
                   1686:        mdp_length = 1+16+4; /* message digest packet length */
                   1687:        /* MD packet length does not include itself or CTB prefix: */
                   1688:        mdpacket[1] = mdp_length;
                   1689:        mdpacket[2] = MD4_ALGORITHM_BYTE;       /* select MD4 algorithm */
                   1690: 
                   1691:        mdbufptr = (byte *) (MD->buffer);       /* point at actual message digest */
                   1692:        for (i=0; i<16; i++)
                   1693:                mdpacket[i+3] = *mdbufptr++;    /* Assumes LSB-first order */
                   1694:        /* Stick a timestamp in here, before signing... */
                   1695:        /* timestamp already in external format */
                   1696:        for (j=0; j<SIZEOF_TIMESTAMP; j++,i++)
                   1697:                mdpacket[i+3] = timestamp[j];
                   1698:        
                   1699:        /* Pre-block mdpacket, and convert to INTERNAL byte order: */
                   1700:        preblock((unitptr)inbuf, mdpacket, mdp_length+2, n, TRUE, NULL);
                   1701: 
                   1702:        fprintf(stderr,"Just a moment-- ");     /* RSA will take a while. */
                   1703: 
                   1704:        /* do RSA signature calculation: */
                   1705:        rsa_decrypt((unitptr)outbuf,(unitptr)inbuf,d,p,q,u);
                   1706: 
                   1707:        bytecount = reg2mpi(outbuf,(unitptr)outbuf); /* convert to external format */
                   1708:        /*      outbuf now contains a MDSB in external byteorder form.
                   1709:                Now make a complete signature certificate from this.
                   1710:        */
                   1711: 
                   1712:        certificate_length = 0;
                   1713: 
                   1714:        /* SKE is Secret Key Encryption (signed).  Append CTB for signed msg. */
                   1715:        certificate[certificate_length++] = CTB_SKE;
                   1716: 
                   1717:        ske_length = KEYFRAGSIZE + bytecount+2;
                   1718:        /* SKE packet length does not include itself or CTB prefix: */
                   1719:        certificate[certificate_length++] = ske_length & 0xff;
                   1720:        certificate[certificate_length++] = (ske_length >> 8) & 0xff;
                   1721: 
                   1722:        /* Now append keyID... */
                   1723:        extract_keyID(keyID, n);        /* gets keyID */
                   1724:        for (i=0; i<KEYFRAGSIZE; i++)
                   1725:                certificate[certificate_length++] = keyID[i];
                   1726: 
                   1727:        /* Now append the RSA-signed message digest packet: */
                   1728:        for (i=0; i<bytecount+2; i++)
                   1729:                certificate[certificate_length++] = outbuf[i];
                   1730: 
                   1731:        fputc('.',stderr);      /* Signal RSA signature completion. */
                   1732: 
                   1733:        burn(inbuf);    /* burn sensitive data on stack */
                   1734:        burn(outbuf);   /* burn sensitive data on stack */
                   1735: 
                   1736:        return(certificate_length);     /* return length of certificate in bytes */
                   1737: 
                   1738: }      /* make_signature_certificate */
                   1739: 
                   1740: 
                   1741: /*======================================================================*/
                   1742: 
                   1743: 
                   1744: int signfile(boolean nested, boolean separate_signature,
                   1745:                char *mcguffin, char *infile, char *outfile)
                   1746: /*     Write an RSA-signed message digest of input file to specified 
                   1747:        output file, and append input file to output file.
                   1748:        separate_signature is TRUE iff we should not append the 
                   1749:        plaintext to the output signature certificate.
                   1750: */
                   1751: {      
                   1752:        FILE *f;
                   1753:        FILE *g;
                   1754:        byte ctb;       /* Cipher Type Byte */
                   1755:        int certificate_length; /* signature certificate length */
                   1756:        byte certificate[MAX_SIGCERT_LENGTH];
                   1757: 
                   1758:        {       /* temporary scope for some buffers */
                   1759:                word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   1760:                byte userid[256];
                   1761:                MDstruct MD;
                   1762:                unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
                   1763:                unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
                   1764: 
                   1765:                set_precision(MAX_UNIT_PRECISION);      /* safest opening assumption */
                   1766: 
                   1767:                if (verbose)
                   1768:                        fprintf(stderr,"\nPlaintext file: %s, signature file: %s\n",
                   1769:                        infile,outfile);
                   1770: 
                   1771:                if (MDfile(&MD, infile) < 0)
                   1772:                        return(-1);     /* problem with input file.  error return */
                   1773: 
                   1774:                strcpy(userid,mcguffin);        /* Who we are looking for */
                   1775: 
                   1776:                if (getsecretkey(NULL, timestamp, userid, n, e, d, p, q, u) < 0)
                   1777:                        return(-1);     /* problem with secret key file. error return. */
                   1778: 
                   1779:                certificate_length = make_signature_certificate(certificate, &MD, userid, n, d, p, q, u);
                   1780: 
                   1781:        }       /* end of scope for some buffers */
                   1782: 
                   1783:        /* open file f for read, in binary (not text) mode...*/
                   1784:        if ((f = fopen(infile,"rb")) == NULL)
                   1785:        {       fprintf(stderr,"\n\aCan't open plaintext file '%s'\n",infile);
                   1786:                return(-1);
                   1787:        }
                   1788: 
                   1789:        /* open file g for write, in binary (not text) mode...*/
                   1790:        if ((g = fopen(outfile,"wb")) == NULL)
                   1791:        {       fprintf(stderr,"\n\aCan't create signature file '%s'\n",outfile);
                   1792:                fclose(f);
                   1793:                return(-1);
                   1794:        }
                   1795: 
                   1796:        /* write out certificate record to outfile ... */
                   1797:        fwrite(certificate,1,certificate_length,g);
                   1798:        
                   1799:        if (!separate_signature)
                   1800:        {       
                   1801:                if (!nested)
                   1802:                {       ctb = CTB_LITERAL;
                   1803:                        fwrite( &ctb, 1, 1, g );        /*      write LITERAL CTB */
                   1804:                        /* No CTB packet length specified means indefinite length. */
                   1805:                }
                   1806:                copyfile(f,g,-1UL);     /* copy rest of file from file f to g */
                   1807:        }
                   1808: 
                   1809:        fclose(g);
                   1810:        fclose(f);
                   1811:        return(0);      /* normal return */
                   1812: 
                   1813: }      /* signfile */
                   1814: 
                   1815: 
                   1816: /*======================================================================*/
                   1817: 
                   1818: int check_signaturefile(char *infile, char *outfile)
                   1819: {
                   1820:        byte ctb,ctb2;  /* Cipher Type Bytes */
                   1821:        char keyfile[64];       /* for getpublickey */
                   1822:        long fp;        /* unused, just to satisfy getpublickey */
                   1823:        int pktlen;     /* unused, just to satisfy getpublickey */
                   1824:        FILE *f;
                   1825:        FILE *g;
                   1826:        long start_text;        /* marks file position */
                   1827:        int i,count,blocksize;
                   1828:        word16 SKElength, cert_length;
                   1829:        word32 LITlength;
                   1830:        int certificate_length; /* signature certificate length */
                   1831:        byte certbuf[MAX_SIGCERT_LENGTH];
                   1832:        byteptr certificate; /* for parsing certificate buffer */
                   1833:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   1834:        byte inbuf[MAX_BYTE_PRECISION];
                   1835:        byte outbuf[MAX_BYTE_PRECISION];
                   1836:        byte keyID[KEYFRAGSIZE];
                   1837:        word32 tstamp;
                   1838:        byte *timestamp = (byte *) &tstamp;             /* key certificate timestamp */
                   1839:        byte userid[256];
                   1840:        MDstruct MD;
                   1841:        boolean separate_signature;
                   1842:        
                   1843:        fill0( keyID, KEYFRAGSIZE );
                   1844: 
                   1845:        set_precision(MAX_UNIT_PRECISION);      /* safest opening assumption */
                   1846: 
                   1847:        buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
                   1848: 
                   1849:        if (verbose)
                   1850:                fprintf(stderr,"\nSignature file: %s, output file: %s\n",
                   1851:                infile,outfile);
                   1852: 
                   1853:        /* open file f for read, in binary (not text) mode...*/
                   1854:        if ((f = fopen(infile,"rb")) == NULL)
                   1855:        {       fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
                   1856:                return(-1);
                   1857:        }
                   1858: 
                   1859:        /******************** Read header CTB and length field ******************/
                   1860: 
                   1861:        fread(&ctb,1,1,f);      /* read certificate CTB byte */
                   1862:        certificate = certbuf;
                   1863:        *certificate++ = ctb;   /* copy ctb into certificate */
                   1864: 
                   1865:        if (!is_ctb(ctb))
                   1866:        {       fprintf(stderr,"\n\a'%s' is not a cipher file.\n",infile);
                   1867:                goto err1;
                   1868:        }
                   1869: 
                   1870:        cert_length = getpastlength(ctb, f); /* read certificate length */
                   1871:        certificate += ctb_llength(ctb);        /* either 1, 2, 4, or 8 */
                   1872:        if (cert_length > MAX_SIGCERT_LENGTH-3)
                   1873:        {       fprintf(stderr,"\n\aSignature file '%s' has huge packet length field.\n",infile);
                   1874:                goto err1;
                   1875:        }
                   1876: 
                   1877:        /* read whole certificate: */
                   1878:        if (fread((byteptr) certificate, 1, cert_length, f) < cert_length)
                   1879:        {       fprintf(stderr,"\n\aSignature file '%s' has bad packet length field.\n",infile);
                   1880:                goto err1;
                   1881:        }
                   1882: 
                   1883:        if (!is_ctb_type(ctb,CTB_SKE_TYPE))
                   1884:        {       fprintf(stderr,"\n\a'%s' is not a signature file.\n",infile);
                   1885:                goto err1;
                   1886:        }
                   1887: 
                   1888:        for (i=0; i<KEYFRAGSIZE; i++)
                   1889:                keyID[i] = *certificate++; /* copy rest of key fragment */
                   1890: 
                   1891:        mpi2reg((unitptr)inbuf,certificate);    /* get signed message digest */
                   1892:        certificate += countbytes((unitptr)inbuf)+2;
                   1893: 
                   1894:        if ((certificate-certbuf) != cert_length+3)
                   1895:        {       fprintf(stderr,"\n\aBad length in signature certificate.  Off by %d.\n",
                   1896:                        (signed int) ((certificate-certbuf) - (cert_length+3)));
                   1897:                goto err1;
                   1898:        }
                   1899: 
                   1900:        start_text = ftell(f);  /* mark position of text for later */
                   1901: 
                   1902:        if (fread(outbuf,1,1,f) < 1)    /* see if any plaintext is there */
                   1903:        {       /*      Signature certificate has no plaintext following it.
                   1904:                        Must be in another file.  Go look. */
                   1905:                separate_signature = TRUE;
                   1906:                fclose(f);
                   1907:                fprintf(stderr,"\nFile '%s' has signature, but with no text.",infile);
                   1908:                if (file_exists(outfile))
                   1909:                {       fprintf(stderr,"\nText is assumed to be in file '%s'.\n",outfile);
                   1910:                }
                   1911:                else
                   1912:                {       fprintf(stderr,"\nPlease enter filename of text that signature applies to: ");
                   1913:                        getstring(outfile,59,TRUE);     /* echo keyboard */
                   1914:                        if (strlen(outfile) == 0)
                   1915:                                return(-1);
                   1916:                }
                   1917:                /* open file f for read, in binary (not text) mode...*/
                   1918:                if ((f = fopen(outfile,"rb")) == NULL)
                   1919:                {       fprintf(stderr,"\n\aCan't open file '%s'\n",outfile);
                   1920:                        return(-1);
                   1921:                }
                   1922:                start_text = ftell(f);  /* mark position of text for later */
                   1923:        }       /* had to open new input file */
                   1924:        else
                   1925:        {       separate_signature = FALSE;
                   1926:                /*      We just read 1 byte, so outbuf[0] should contain a ctb, 
                   1927:                        maybe a CTB_LITERAL byte. */
                   1928:                ctb2 = outbuf[0];
                   1929:                if (is_ctb(ctb2) && is_ctb_type(ctb2,CTB_LITERAL_TYPE))
                   1930:                {       /* skip over the CTB_LITERAL header to compute signature */
                   1931:                        LITlength = getpastlength(ctb2, f); /* read packet length */
                   1932:                        start_text = ftell(f);  /* mark position of text for later */
                   1933:                        /* Now we are 1 byte past the CTB_LITERAL header. */
                   1934:                }
                   1935:        }
                   1936: 
                   1937: 
                   1938:        /* Use keyID prefix to look up key... */
                   1939: 
                   1940:        /*      Get and validate public key from a key file: */
                   1941:        if (getpublickey(FALSE, verbose, keyfile, &fp, &pktlen, 
                   1942:                        keyID, timestamp, userid, n, e) < 0)
                   1943:        {       /* Can't get public key.  Complain and process file copy anyway. */
                   1944:                fprintf(stderr,"\n\aWARNING: Can't find the right public key-- can't check signature integrity.\n");
                   1945:        }       /* Can't find public key */
                   1946:        else    /* got good public key, now use it to check signature...*/
                   1947:        {
                   1948:                if (testeq(e,0))        /* Means secret key has been compromised */
                   1949:                {       PascalToC(userid);
                   1950:                        fprintf(stderr,"\n\aWarning: Secret key compromised for userid \"%s\".",userid);
                   1951:                        fprintf(stderr,"\nThus this public key cannot be used.\n");
                   1952:                        goto err1;
                   1953:                }
                   1954: 
                   1955:                /* Recover message digest via public key */
                   1956:                mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n);
                   1957: 
                   1958:                /* Unblock message digest, and convert to external byte order: */
                   1959:                count = postunblock(outbuf, (unitptr)outbuf, n, TRUE, TRUE);
                   1960:                if (count < 0)
                   1961:                {       fprintf(stderr,"\n\aBad RSA decrypt: checksum or pad error during unblocking.\n");
                   1962:                        goto err1;
                   1963:                }
                   1964: 
                   1965:                fputc('.',stderr);      /* Signal RSA completion. */
                   1966: 
                   1967:                /* outbuf should contain message digest packet */
                   1968:                /*==================================================================*/
                   1969:                /* Look at nested stuff within RSA block... */
                   1970: 
                   1971:                if (!is_ctb_type(outbuf[0],CTB_MD_TYPE))
                   1972:                {       fprintf(stderr,"\aNested info is not a message digest packet.\n");
                   1973:                        goto err1;
                   1974:                }
                   1975: 
                   1976:                if (outbuf[2] != MD4_ALGORITHM_BYTE)
                   1977:                {       fprintf(stderr,"\a\nUnrecognized message digest algorithm.\n");
                   1978:                        goto err1;
                   1979:                }
                   1980: 
                   1981:                /* Reposition file to where that plaintext begins... */
                   1982:                fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
                   1983: 
                   1984:                MDfile0(&MD,f); /* compute a message digest from rest of file */
                   1985: 
                   1986:                hilo_swap(outbuf+19,4); /* convert timestamp from external LSB-first form */
                   1987:                PascalToC(userid);      /* for display */
                   1988: 
                   1989:                /* now compare computed MD with claimed MD */
                   1990:                if (!equal_buffers((byte *)(MD.buffer), outbuf+3, 16))
                   1991:                {       fprintf(stderr,"\a\nWARNING: Bad signature, doesn't match file contents!\a\n");
                   1992:                        fprintf(stderr,"\nBad signature from user \"%s\".\n",userid);
                   1993:                        fprintf(stderr,"Signature made %s",ctime((long *)(outbuf+19))); /* '\n' */
                   1994:                        goto xnormal;   /* normal exit */
                   1995:                }
                   1996: 
                   1997:                fprintf(stderr,"\nGood signature from user \"%s\".\n",userid);
                   1998:                fprintf(stderr,"Signature made %s",ctime((long *)(outbuf+19))); /* '\n' */
                   1999: 
                   2000:        }       /* Found correct public key */
                   2001: 
                   2002:        /* Reposition file to where that plaintext begins... */
                   2003:        fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
                   2004: 
                   2005:        if (separate_signature)
                   2006:                fprintf(stderr,"\nSignature and text are separate.  No output file produced. ");
                   2007:        else    /* signature precedes plaintext in file... */
                   2008:        {       /* produce a plaintext output file from signature file */
                   2009:                if (file_exists(outfile))
                   2010:                {       fprintf(stderr,"\n\aOutput file '%s' already exists.  Overwrite (y/N)? ",outfile);
                   2011:                        if (!getyesno('n'))     /* user said don't do it. */
                   2012:                                goto err1;      /* abort operation */
                   2013:                }
                   2014:                /* open file g for write, in binary (not text) mode...*/
                   2015:                if ((g = fopen(outfile,"wb")) == NULL)
                   2016:                {       fprintf(stderr,"\n\aCan't create plaintext file '%s'\n",outfile);
                   2017:                        goto err1;
                   2018:                }
                   2019:                copyfile(f,g,-1UL);     /* copy rest of file from file f to g */
                   2020:                fclose(g);
                   2021:        }
                   2022: 
                   2023: xnormal:
                   2024:        burn(inbuf);    /* burn sensitive data on stack */
                   2025:        burn(outbuf);   /* burn sensitive data on stack */
                   2026:        fclose(f);
                   2027:        if (separate_signature)
                   2028:                return(0);      /* normal return, no nested info */
                   2029:        if (is_ctb(ctb2) && is_ctb_type(ctb2,CTB_LITERAL_TYPE))
                   2030:                /* we already stripped away the CTB_LITERAL */
                   2031:                return(0);      /* normal return, no nested info */
                   2032:        /* Otherwise, it's best to assume a nested CTB */
                   2033:        return(1);      /* nested information return */
                   2034: 
                   2035: err1:
                   2036:        burn(inbuf);    /* burn sensitive data on stack */
                   2037:        burn(outbuf);   /* burn sensitive data on stack */
                   2038:        fclose(f);
                   2039:        return(-1);     /* error return */
                   2040: 
                   2041: }      /* check_signaturefile */
                   2042: 
                   2043: 
                   2044: 
                   2045: /*======================================================================*/
                   2046: int squish_and_bass_file(byte *basskey, int lenbasskey, FILE *f, FILE *g)
                   2047: {
                   2048:        FILE *t;
                   2049:        byte header[4];
                   2050:        byte ctb;
                   2051: 
                   2052:        /*
                   2053:        **      Create a temporary file 't' and compress our input file 'f' into
                   2054:        **      't'.  If we get a good compression ratio then use file 't' for
                   2055:        **      input and write a CTB_COMPRESSED prefix.
                   2056:        **      But, if the file looks like a PKZIP file then skip our compression.
                   2057:        */
                   2058: 
                   2059:        fread( header, 1, 4, f );
                   2060:        rewind( f );
                   2061: 
                   2062:        if (pkzipSignature( header ))
                   2063:                t = f;
                   2064:        else
                   2065:        if ((t = tmpfile()) != NULL)
                   2066:        {
                   2067:                extern int lzhEncode( FILE *, FILE * );
                   2068: 
                   2069:                if (verbose) fprintf(stderr, "Compressing plaintext..." );
                   2070: 
                   2071:                ctb = CTB_COMPRESSED;           /* use compression prefix CTB */
                   2072:                fwrite( &ctb, 1, 1, t );        /* write CTB_COMPRESSED */
                   2073:                /* No CTB packet length specified means indefinite length. */
                   2074:                ctb = LZH_ALGORITHM_BYTE;       /* use lzh compression */
                   2075:                fwrite( &ctb, 1, 1, t );        /* write LZH algorithm byte */
                   2076: 
                   2077:                /* lzhEncode returns the ratio of file size t to size f. */
                   2078: 
                   2079:                if (lzhEncode( f, t) < 9)
                   2080:                {
                   2081:                        /*      Compression made the input file smaller by at least
                   2082:                                10 per cent, so use the 't' file. */
                   2083: 
                   2084:                        if (verbose) fprintf(stderr, "compressed.  " );
                   2085: 
                   2086:                        rewind( t );
                   2087:                }
                   2088:                else
                   2089:                {
                   2090:                        /*      Compression made no significant difference in size so
                   2091:                                pass the input file along as it is.  Close and remove
                   2092:                                the temporary file. */
                   2093: 
                   2094:                        if (verbose) fprintf(stderr, "incompressible.  " );
                   2095: 
                   2096:                        wipeout( t );
                   2097:                        fclose( t );
                   2098:                        rewind( f );
                   2099:                        t = f;
                   2100:                }
                   2101:        }
                   2102:        else
                   2103:                t = f;
                   2104: 
                   2105:        /*      Now write out file thru BassOmatic ... */
                   2106: 
                   2107:        ctb = CTB_CKE;                  /*      CKE is Conventional Key Encryption */
                   2108:        fwrite( &ctb, 1, 1, g );        /* write CTB_CKE */
                   2109:        /* No CTB packet length specified means indefinite length. */
                   2110: 
                   2111:        bass_file( basskey, lenbasskey, FALSE, t, g ); /* encrypt file */
                   2112: 
                   2113:        if (t != f)     
                   2114:        {       wipeout( t );
                   2115:                fclose( t );  /* close and remove the temporary file */
                   2116:        }
                   2117: 
                   2118:        return(0);      /* normal return */
                   2119: 
                   2120: }      /* squish_and_bass_file */
                   2121: 
                   2122: 
                   2123: #define NOECHO1 1      /* Disable password from being displayed on screen */
                   2124: #define NOECHO2 2      /* Disable password from being displayed on screen */
                   2125: 
                   2126: int bass_encryptfile(boolean nested, char *infile, char *outfile)
                   2127: {
                   2128:        FILE *f;        /* input file */
                   2129:        FILE *g;        /* output file */
                   2130:        byte basskey[256];
                   2131:        int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
                   2132: 
                   2133:        if (verbose)
                   2134:                fprintf(stderr,"\nPlaintext file: %s, ciphertext file: %s\n",
                   2135:                infile,outfile);
                   2136: 
                   2137:        /* open file f for read, in binary (not text) mode...*/
                   2138:        if ((f = fopen( infile, "rb" )) == NULL)
                   2139:        {
                   2140:                fprintf(stderr,"\n\aCan't open plaintext file '%s'\n", infile );
                   2141:                return(-1);
                   2142:        }
                   2143: 
                   2144:        /* open file g for write, in binary (not text) mode...*/
                   2145:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2146:        {
                   2147:                fprintf(stderr,"\n\aCan't create ciphertext file '%s'\n", outfile );
                   2148:                fclose(f);
                   2149:                return(-1);
                   2150:        }
                   2151: 
                   2152:        /* Get BassOmatic password with leading BassOmatic control byte: */
                   2153:        /* Default is Military grade BassOmatic key control byte */
                   2154:        if (getpassword(basskey,NOECHO2,0x1f) <= 0)
                   2155:                return(-1);
                   2156: 
                   2157:        basskeylen = strlen(basskey);
                   2158: 
                   2159:        /* Now compress the plaintext and encrypt it with BassOmatic... */
                   2160:        squish_and_bass_file( basskey, basskeylen, f, g );
                   2161: 
                   2162:        burn(basskey);  /* burn sensitive data on stack */
                   2163: 
                   2164:        fclose(g);
                   2165:        fclose(f);
                   2166: 
                   2167:        return(0);
                   2168: 
                   2169: }      /* bass_encryptfile */
                   2170: 
                   2171: 
                   2172: /*======================================================================*/
                   2173: 
                   2174: 
                   2175: int encryptfile(boolean nested, char *mcguffin, char *infile, char *outfile)
                   2176: {
                   2177:        byte ctb;
                   2178:        byte ctbCKE = CTB_CKE;
                   2179:        byte randompad[MAX_BYTE_PRECISION];     /* buffer of random pad bytes */
                   2180:        int i,blocksize,ckp_length,PKElength,bytecount;
                   2181:        FILE *f;
                   2182:        FILE *g;
                   2183:        FILE *t;
                   2184:        byte header[4];
                   2185:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2186:        byte inbuf[MAX_BYTE_PRECISION];
                   2187:        byte outbuf[MAX_BYTE_PRECISION];
                   2188:        word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   2189:        byte userid[256];
                   2190:        byte basskey[64]; /* must be big enough for make_random_basskey */
                   2191:        int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
                   2192:        char keyfile[64];       /* for getpublickey */
                   2193:        long fp;        /* unused, just to satisfy getpublickey */
                   2194:        int pktlen;     /* unused, just to satisfy getpublickey */
                   2195: 
                   2196: 
                   2197:        buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
                   2198: 
                   2199:        if (verbose)
                   2200:                fprintf(stderr,"\nPlaintext file: %s, ciphertext file: %s\n",
                   2201:                infile,outfile);
                   2202: 
                   2203:        strcpy(userid,mcguffin);        /* Who we are looking for (C string) */
                   2204: 
                   2205:        /*      Get and validate public key from a key file: */
                   2206:        if (getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, NULL, timestamp, userid, n, e) < 0)
                   2207:        {       return(-1);
                   2208:        }
                   2209: 
                   2210:        if (testeq(e,0))        /* Means secret key has been compromised */
                   2211:        {       PascalToC(userid);
                   2212:                fprintf(stderr,"\n\aWarning: Secret key compromised for userid \"%s\".",userid);
                   2213:                fprintf(stderr,"\nThus this public key cannot be used.\n");
                   2214:                return(-1);
                   2215:        }
                   2216: 
                   2217: 
                   2218:        /* set_precision has been properly called by getpublickey */
                   2219: 
                   2220:        /*      Note that RSA key must be at least big enough to encipher a 
                   2221:                complete conventional key packet in a single RSA block.
                   2222:                The BassOmatic key packet is 28 bytes long, which requires 
                   2223:                an RSA key 32 bytes (256 bits) long.  
                   2224:                If we implemented DES, the DES key packet is 37 bytes long 
                   2225:                (with IV, prewhitener and postwhitener), requiring an RSA 
                   2226:                key 41 bytes (328 bits) long.
                   2227:        */
                   2228: 
                   2229:        blocksize = countbytes(n)-1;    /* size of a plaintext block */
                   2230:        if (blocksize < 31)
                   2231:        {       fprintf(stderr,"\n\aError: RSA key length must be at least 256 bits.\n");
                   2232:                return(-1);
                   2233:        }
                   2234: 
                   2235:        /* open file f for read, in binary (not text) mode...*/
                   2236:        if ((f = fopen( infile, "rb" )) == NULL)
                   2237:        {
                   2238:                fprintf(stderr,"\n\aCan't open plaintext file '%s'\n", infile );
                   2239:                return(-1);
                   2240:        }
                   2241: 
                   2242:        /* open file g for write, in binary (not text) mode...*/
                   2243:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2244:        {
                   2245:                fprintf(stderr,"\n\aCan't create ciphertext file '%s'\n", outfile );
                   2246:                fclose(f);
                   2247:                return(-1);
                   2248:        }
                   2249: 
                   2250:        /*      Now we have to time some user keystrokes to get some random 
                   2251:                bytes for generating a random BassOmatic key.
                   2252:                We would have to solicit fewer keystrokes for random BassOmatic 
                   2253:                key generation if we had already accumulated some keystrokes 
                   2254:                incidental to some other purpose, such as asking for a password 
                   2255:                to decode an RSA secret key so that a signature could be applied 
                   2256:                to the message before encrypting it.
                   2257:        */
                   2258: 
                   2259:        basskeylen = 32;        /* Default is big BassOmatic key */
                   2260:        if (blocksize < 64)             /* <= 512 bits */ 
                   2261:                basskeylen = 24;
                   2262:        if (blocksize < 36)     /* <= 288 bits */
                   2263:                basskeylen = 16;
                   2264:        ckp_length = make_random_basskey(basskey,basskeylen);
                   2265:        /* Returns a basskeylen+1 byte random BassOmatic key */
                   2266: 
                   2267:        outbuf[0] = CTB_CONKEY; /* conventional key packet */
                   2268: 
                   2269:        ckp_length += 1; /* add length of algorithm field */
                   2270:        /* Conventional key packet length does not include itself or CTB prefix: */
                   2271:        outbuf[1] = ckp_length;
                   2272: 
                   2273:        outbuf[2] = BASS_ALGORITHM_BYTE;        /* select BassOmatic algorithm */
                   2274: 
                   2275:        for (i=0; i<ckp_length-1; i++)
                   2276:                outbuf[3+i] = basskey[i];
                   2277: 
                   2278:        /*
                   2279:        **      Messages encrypted with a public key should use random padding, 
                   2280:        **      while messages "signed" with a secret key should use constant 
                   2281:        **      padding.
                   2282:        */
                   2283: 
                   2284:        for (i = 0; i < (blocksize - (ckp_length + 2)); i++)
                   2285:                randompad[i] = randombyte();
                   2286: 
                   2287:        /*
                   2288:        **      Note that RSA key must be at least big enough to encipher a 
                   2289:        **      complete conventional key packet in a single RSA block.
                   2290:        */
                   2291: 
                   2292:        /* ckp_length+2 is conventional key packet length. */
                   2293: 
                   2294:        preblock( (unitptr)inbuf, outbuf, ckp_length+2, n, TRUE, randompad );
                   2295:        mp_modexp( (unitptr)outbuf, (unitptr)inbuf, e, n );     /* RSA encrypt */
                   2296: 
                   2297:        /* write out header record to outfile ... */
                   2298: 
                   2299:        ctb = CTB_PKE;                          /*      PKE is Public Key Encryption */
                   2300:        PKElength = KEYFRAGSIZE + countbytes( (unitptr)outbuf ) + 2;
                   2301:        fwrite( &ctb, 1, 1, g );        /*      write RSA msg CTB */
                   2302: 
                   2303:        /* Change PKElength to external byte order: */
                   2304: 
                   2305:        convert( PKElength ); 
                   2306:        fwrite( &PKElength, 1, sizeof( PKElength ), g );        /* write length */
                   2307: 
                   2308:        writekeyID( n, g );     /* write msg prefix fragment of modulus n */
                   2309: 
                   2310:        /* convert RSA ciphertext block via reg2mpi and write to file */
                   2311: 
                   2312:        write_mpi( (unitptr)outbuf, g, FALSE );
                   2313: 
                   2314:        burn(inbuf);    /* burn sensitive data on stack */
                   2315:        burn(outbuf);   /* burn sensitive data on stack */
                   2316: 
                   2317:        /**     Finished with RSA block containing BassOmatic key. */
                   2318: 
                   2319:        /* Now compress the plaintext and encrypt it with BassOmatic... */
                   2320:        squish_and_bass_file( basskey, ckp_length-1, f, g );
                   2321: 
                   2322:        burn(basskey);  /* burn sensitive data on stack */
                   2323: 
                   2324:        fclose(g);
                   2325:        fclose(f);
                   2326: 
                   2327:        return(0);
                   2328: }      /* encryptfile */
                   2329: 
                   2330: 
                   2331: /*======================================================================*/
                   2332: int make_literal(char *infile, char *outfile)
                   2333: {      /*      An awful lot of hassle to go thru just to prepend 1 lousy byte.
                   2334:                Prepends a CTB_LITERAL prefix byte to a file.
                   2335:        */
                   2336:        byte ctb;       /* Cipher Type Byte */
                   2337:        FILE *f;
                   2338:        FILE *g;
                   2339: 
                   2340:        if (verbose)
                   2341:                fprintf(stderr,"\nInput plaintext file: %s, Output plaintext file: %s\n",
                   2342:                infile,outfile);
                   2343: 
                   2344:        /* open file f for read, in binary (not text) mode...*/
                   2345:        if ((f = fopen(infile,"rb")) == NULL)
                   2346:        {       fprintf(stderr,"\n\aCan't open input plaintext file '%s'\n",infile);
                   2347:                return(-1);
                   2348:        }
                   2349: 
                   2350:        /*      open file g for write, in binary (not text) mode... */
                   2351:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2352:        {       fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
                   2353:                goto err1;
                   2354:        }
                   2355: 
                   2356:        ctb = CTB_LITERAL;      /* prepend this byte prefix to message */
                   2357:        fwrite( &ctb, 1, 1, g );        /*      write LITERAL CTB */
                   2358:        /* No CTB packet length specified means indefinite length. */
                   2359: 
                   2360:        copyfile( f, g, -1UL ); /* copy rest of literal plaintext file */
                   2361: 
                   2362:        fclose(g);
                   2363:        fclose(f);
                   2364:        return(0);      /* normal return */
                   2365: 
                   2366: err1:
                   2367:        fclose(f);
                   2368:        return(-1);     /* error return */
                   2369: 
                   2370: }      /* make_literal */
                   2371: 
                   2372: 
                   2373: /*======================================================================*/
                   2374: int strip_literal(char *infile, char *outfile)
                   2375: {      /*      A lot of hassle to go thru just to strip off 1 lousy prefix byte. 
                   2376:                Strips off the CTB_LITERAL prefix byte from a file.
                   2377:        */
                   2378:        byte ctb;       /* Cipher Type Byte */
                   2379:        FILE *f;
                   2380:        FILE *g;
                   2381:        word32 LITlength = 0;
                   2382: 
                   2383:        if (verbose)
                   2384:                fprintf(stderr,"\nInput plaintext file: %s, output plaintext file: %s\n",
                   2385:                infile,outfile);
                   2386: 
                   2387:        /* open file f for read, in binary (not text) mode...*/
                   2388:        if ((f = fopen(infile,"rb")) == NULL)
                   2389:        {       fprintf(stderr,"\n\aCan't open input plaintext file '%s'\n",infile);
                   2390:                return(-1);
                   2391:        }
                   2392: 
                   2393:        fread(&ctb,1,1,f);      /* read Cipher Type Byte */
                   2394: 
                   2395:        if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_LITERAL_TYPE))
                   2396:        {       fprintf(stderr,"\n\a'%s' is not a literal plaintext file.\n",infile);
                   2397:                fclose(f);
                   2398:                return(-1);
                   2399:        }
                   2400: 
                   2401:        LITlength = getpastlength(ctb, f); /* read packet length */
                   2402: 
                   2403:        if (file_exists( outfile ))
                   2404:        {       fprintf(stderr, "\n\aOutput file '%s' already exists.  Overwrite (y/N)? ", outfile );
                   2405:                if (! getyesno( 'n' ))
                   2406:                        goto err1;              /* user said don't do it - abort operation */
                   2407:        }
                   2408: 
                   2409:        /*      open file g for write, in binary (not text) mode... */
                   2410: 
                   2411:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2412:        {       fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
                   2413:                goto err1;
                   2414:        }
                   2415: 
                   2416:        copyfile( f, g, LITlength );    /* copy rest of literal plaintext file */
                   2417: 
                   2418:        fclose(g);
                   2419:        fclose(f);
                   2420:        return(0);      /* normal return */
                   2421: 
                   2422: err1:
                   2423:        fclose(f);
                   2424:        return(-1);     /* error return */
                   2425: 
                   2426: }      /* strip_literal */
                   2427: 
                   2428: 
                   2429: /*======================================================================*/
                   2430: 
                   2431: 
                   2432: int decryptfile(char *infile, char *outfile)
                   2433: {
                   2434:        byte ctb;       /* Cipher Type Byte */
                   2435:        byte ctbCKE; /* Cipher Type Byte */
                   2436:        FILE *f;
                   2437:        FILE *g;
                   2438:        int count, status;
                   2439:        word32 PKElength, CKElength;
                   2440:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
                   2441:        unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
                   2442:        byte inbuf[MAX_BYTE_PRECISION];
                   2443:        byte outbuf[MAX_BYTE_PRECISION];
                   2444:        byte keyID[KEYFRAGSIZE];
                   2445:        word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   2446:        byte userid[256];
                   2447: 
                   2448:        set_precision(MAX_UNIT_PRECISION);      /* safest opening assumption */
                   2449: 
                   2450:        if (verbose)
                   2451:                fprintf(stderr,"\nCiphertext file: %s, plaintext file: %s\n",
                   2452:                infile,outfile);
                   2453: 
                   2454:        /* open file f for read, in binary (not text) mode...*/
                   2455:        if ((f = fopen(infile,"rb")) == NULL)
                   2456:        {       fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
                   2457:                return(-1);
                   2458:        }
                   2459: 
                   2460:        fread(&ctb,1,1,f);      /* read Cipher Type Byte */
                   2461:        if (!is_ctb(ctb))
                   2462:        {       fprintf(stderr,"\n\a'%s' is not a cipher file.\n",infile);
                   2463:                fclose(f);
                   2464:                return(-1);
                   2465:        }
                   2466: 
                   2467:        /* PKE is Public Key Encryption */
                   2468:        if (!is_ctb_type(ctb,CTB_PKE_TYPE))
                   2469:        {       fprintf(stderr,"\n\a'%s' is not enciphered with a public key.\n",infile);
                   2470:                fclose(f);
                   2471:                return(-1);
                   2472:        }
                   2473: 
                   2474:        PKElength = getpastlength(ctb, f); /* read packet length */
                   2475: 
                   2476:        fread(keyID,1,KEYFRAGSIZE,f); /* read key ID */
                   2477:        /* Use keyID prefix to look up key. */
                   2478: 
                   2479:        /*      Get and validate secret key from a key file: */
                   2480:        if (getsecretkey(keyID, timestamp, userid, n, e, d, p, q, u) < 0)
                   2481:        {       fclose(f);
                   2482:                return(-1);
                   2483:        }
                   2484: 
                   2485:        /*      Note that RSA key must be at least big enough to encipher a
                   2486:                complete conventional key packet in a single RSA block. */
                   2487: 
                   2488:        /*==================================================================*/
                   2489:        /* read ciphertext block, converting to internal format: */
                   2490:        read_mpi((unitptr)inbuf, f, FALSE, FALSE);
                   2491: 
                   2492:        fprintf(stderr,"Just a moment-- ");     /* RSA will take a while. */
                   2493: 
                   2494:        rsa_decrypt((unitptr)outbuf, (unitptr)inbuf, d, p, q, u);
                   2495: 
                   2496:        if ((count = postunblock(outbuf, (unitptr)outbuf, n, TRUE, TRUE)) < 0)
                   2497:        {       fprintf(stderr,"\n\aBad RSA decrypt: checksum or pad error during unblocking.\n");
                   2498:                fclose(f);
                   2499:                return(-1);
                   2500:        }
                   2501: 
                   2502:        fputc('.',stderr);      /* Signal RSA completion. */
                   2503: 
                   2504:        /* outbuf should contain random BassOmatic key packet */
                   2505:        /*==================================================================*/
                   2506:        /* Look at nested stuff within RSA block... */
                   2507: 
                   2508:        ctb = outbuf[0];        /* get nested CTB, should be CTB_CONKEY */
                   2509: 
                   2510:        if (!is_ctb_type(ctb,CTB_CONKEY_TYPE))
                   2511:        {       fprintf(stderr,"\aNested info is not a conventional key packet.\n");
                   2512:                goto err1;
                   2513:        }
                   2514: 
                   2515:        /*      Test the Conventional Key Packet for supported algorithms.
                   2516:                (currently, just the BassOmatic is supported) */
                   2517: 
                   2518:        if ( outbuf[2] != BASS_ALGORITHM_BYTE )
                   2519:        {       fprintf(stderr,"\a\nUnrecognized conventional encryption algorithm.\n");
                   2520:                goto err1;
                   2521:        }
                   2522: 
                   2523:        if (file_exists( outfile ))
                   2524:        {       fprintf(stderr, "\n\aOutput file '%s' already exists.  Overwrite (y/N)? ", outfile );
                   2525:                if (! getyesno( 'n' ))
                   2526:                        goto err1;              /* user said don't do it - abort operation */
                   2527:        }
                   2528: 
                   2529:        /*      open file g for write, in binary (not text) mode... */
                   2530:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2531:        {       fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
                   2532:                goto err1;
                   2533:        }
                   2534: 
                   2535:        fread(&ctbCKE,1,1,f);   /* read Cipher Type Byte, should be CTB_CKE */
                   2536:        if (ctbCKE != CTB_CKE)
                   2537:        {       /* Should never get here. */
                   2538:                fprintf(stderr,"\a\nBad or missing CTB_CKE byte.\n");
                   2539:                goto err1;      /* Abandon ship! */
                   2540:        }
                   2541: 
                   2542:        CKElength = getpastlength(ctbCKE, f); /* read packet length */
                   2543: 
                   2544:        status = bass_file( outbuf+3, count-3, TRUE, f, g );    /* Decrypt ciphertext file */
                   2545: 
                   2546:        fclose(g);
                   2547:        fclose(f);
                   2548:        burn(inbuf);    /* burn sensitive data on stack */
                   2549:        burn(outbuf);   /* burn sensitive data on stack */
                   2550:        mp_burn(d);     /* burn sensitive data on stack */
                   2551:        mp_burn(p);     /* burn sensitive data on stack */
                   2552:        mp_burn(q);     /* burn sensitive data on stack */
                   2553:        mp_burn(u);     /* burn sensitive data on stack */
                   2554:        if (status < 0) /* if bass_file failed, then error return */
                   2555:                return(status);
                   2556:        return(1);      /* always indicate output file has nested stuff in it. */
                   2557: 
                   2558: err1:
                   2559:        fclose(f);
                   2560:        burn(inbuf);    /* burn sensitive data on stack */
                   2561:        burn(outbuf);   /* burn sensitive data on stack */
                   2562:        mp_burn(d);     /* burn sensitive data on stack */
                   2563:        mp_burn(p);     /* burn sensitive data on stack */
                   2564:        mp_burn(q);     /* burn sensitive data on stack */
                   2565:        mp_burn(u);     /* burn sensitive data on stack */
                   2566:        return(-1);     /* error return */
                   2567: 
                   2568: }      /* decryptfile */
                   2569: 
                   2570: 
                   2571: 
                   2572: int bass_decryptfile(char *infile, char *outfile)
                   2573: {
                   2574:        byte ctb;       /* Cipher Type Byte */
                   2575:        FILE *f;
                   2576:        FILE *g;
                   2577:        word32 CKElength;
                   2578:        byte basskey[256];
                   2579:        int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
                   2580:        int status;
                   2581: 
                   2582:        if (verbose)
                   2583:                fprintf(stderr,"\nCiphertext file: %s, plaintext file: %s\n",
                   2584:                infile,outfile);
                   2585: 
                   2586:        /* open file f for read, in binary (not text) mode...*/
                   2587:        if ((f = fopen(infile,"rb")) == NULL)
                   2588:        {       fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
                   2589:                return(-1);
                   2590:        }
                   2591: 
                   2592:        fread(&ctb,1,1,f);      /* read Cipher Type Byte, should be CTB_CKE */
                   2593: 
                   2594:        if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_CKE_TYPE))
                   2595:        {       /* Should never get here. */
                   2596:                fprintf(stderr,"\a\nBad or missing CTB_CKE byte.\n");
                   2597:                goto err1;      /* Abandon ship! */
                   2598:        }
                   2599: 
                   2600:        CKElength = getpastlength(ctb, f); /* read packet length */
                   2601:        /* The packet length is ignored.  Assume it's huge. */
                   2602: 
                   2603:        if (file_exists( outfile ))
                   2604:        {       fprintf(stderr, "\n\aOutput file '%s' already exists.  Overwrite (y/N)? ", outfile );
                   2605:                if (! getyesno( 'n' ))
                   2606:                        goto err1;              /* user said don't do it - abort operation */
                   2607:        }
                   2608: 
                   2609:        /*      open file g for write, in binary (not text) mode... */
                   2610:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2611:        {       fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
                   2612:                goto err1;
                   2613:        }
                   2614: 
                   2615:        /* Get BassOmatic password with leading BassOmatic control byte: */
                   2616:        /* Default is Military grade BassOmatic key control byte */
                   2617:        if (getpassword(basskey,NOECHO1,0x1f) <= 0)
                   2618:                return(-1);
                   2619: 
                   2620:        basskeylen = strlen(basskey);
                   2621: 
                   2622:        status = bass_file( basskey, basskeylen, TRUE, f, g ); /* decrypt file */
                   2623: 
                   2624:        burn(basskey);  /* burn sensitive data on stack */
                   2625: 
                   2626:        fclose(g);
                   2627:        fclose(f);
                   2628: 
                   2629:        if (status < 0) /* if bass_file failed, then complain */
                   2630:        {       fprintf(stderr,"\n\aError:  Bad pass phrase. ");
                   2631:                remove(outfile);        /* throw away our mistake */
                   2632:                return(status);         /* error return */
                   2633:        }
                   2634:        return(1);      /* always indicate output file has nested stuff in it. */
                   2635: 
                   2636: err1:
                   2637:        fclose(f);
                   2638:        return(-1);     /* error return */
                   2639: 
                   2640: }      /* bass_decryptfile */
                   2641: 
                   2642: 
                   2643: 
                   2644: int decompress_file(char *infile, char *outfile)
                   2645: {
                   2646:        byte ctb;
                   2647:        FILE *f;
                   2648:        FILE *g;
                   2649:        word32 compress_pkt_length;
                   2650:        extern void lzhDecode( FILE *, FILE * );
                   2651:        if (verbose) fprintf(stderr, "Decompressing plaintext..." );
                   2652: 
                   2653:        /* open file f for read, in binary (not text) mode...*/
                   2654:        if ((f = fopen(infile,"rb")) == NULL)
                   2655:        {       fprintf(stderr,"\n\aCan't open compressed file '%s'\n",infile);
                   2656:                return(-1);
                   2657:        }
                   2658: 
                   2659:        fread(&ctb,1,1,f);      /* read and skip over Cipher Type Byte */
                   2660:        if (!is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
                   2661:        {       /* Shouldn't get here, or why were we called to begin with? */
                   2662:                fprintf(stderr,"\a\nBad or missing CTB_COMPRESSED byte.\n");
                   2663:                goto err1;      /* Abandon ship! */
                   2664:        }
                   2665: 
                   2666:        compress_pkt_length = getpastlength(ctb, f); /* read packet length */
                   2667:        /* The packet length is ignored.  Assume it's huge. */
                   2668: 
                   2669:        fread(&ctb,1,1,f);      /* read and skip over compression algorithm byte */
                   2670:        if (ctb != LZH_ALGORITHM_BYTE)
                   2671:        {       /* We only know one compression algorithm */
                   2672:                fprintf(stderr,"\a\nUnrecognized compression algorithm.\n");
                   2673:                goto err1;      /* Abandon ship! */
                   2674:        }
                   2675: 
                   2676:        /*      open file g for write, in binary (not text) mode... */
                   2677:        if ((g = fopen( outfile, "wb" )) == NULL)
                   2678:        {       fprintf(stderr, "\n\aCan't create decompressed file '%s'\n", outfile );
                   2679:                goto err1;
                   2680:        }
                   2681: 
                   2682:        lzhDecode( f, g );
                   2683:        if (verbose) fprintf(stderr, "done.  " );
                   2684:        fclose(g);
                   2685:        fclose(f);
                   2686:        return(1);      /* always indicate output file has nested stuff in it. */
                   2687: err1:
                   2688:        fclose(f);
                   2689:        return(-1);     /* error return */
                   2690: 
                   2691: }      /* decompress_file */
                   2692: 
                   2693: 
                   2694: 
                   2695: int view_keyring(char *mcguffin, char *ringfile)
                   2696: /*     Lists all entries in keyring that have mcguffin string in userid.
                   2697:        mcguffin is a null-terminated C string.
                   2698: */
                   2699: {      FILE *f;
                   2700:        long file_position,fp;
                   2701:        byte ctb;
                   2702:        int status;
                   2703:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2704:        byte keyID[KEYFRAGSIZE];
                   2705:        byte userid[256];               /* key certificate userid */
                   2706:        word32 tstamp;
                   2707:        byte *timestamp = (byte *) &tstamp;             /* key certificate timestamp */
                   2708:        int keycounter = 0;
                   2709: 
                   2710:        /* open file f for read, in binary (not text) mode...*/
                   2711:        if ((f = fopen(ringfile,"rb")) == NULL)
                   2712:        {       fprintf(stderr,"\n\aCan't open key ring file '%s'\n",ringfile);
                   2713:                return(-1);
                   2714:        }
                   2715: 
                   2716: /*     Here's a good format for display of key or signature certificates:
                   2717: Type bits/keyID   Date     User ID
                   2718: pub  990/xxxxxx dd-mmm-yy  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   2719: sec  990/xxxxxx dd-mmm-yy  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   2720: sig  990/xxxxxx dd-mmm-yy  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   2721: com  990/xxxxxx dd-mmm-yy  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                   2722: */
                   2723: 
                   2724:        fprintf(stderr,"\nKey ring: '%s'",ringfile);
                   2725:        if (strlen(mcguffin) > 0)
                   2726:                fprintf(stderr,", looking for user ID \"%s\".",mcguffin);
                   2727:        fprintf(stderr,"\nType bits/keyID   Date     User ID\n");
                   2728:        do
                   2729:        {
                   2730:                status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
                   2731:                                NULL,NULL,NULL,NULL);
                   2732:                /* Note that readkeypacket has called set_precision */
                   2733:                if (status== -1 ) break;        /* eof reached */
                   2734:                if (status < 0)
                   2735:                {       fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
                   2736:                                ringfile);
                   2737:                        fclose(f);      /* close key file */
                   2738:                        return(-1);
                   2739:                }
                   2740: 
                   2741:                if (!is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE)
                   2742:                &&  !is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
                   2743:                {
                   2744:                        fprintf(stderr,"\n\aError in file '%s'.  Not a key certificate.\n",
                   2745:                                ringfile);
                   2746:                        return(-1);
                   2747:                }
                   2748: 
                   2749:                keycounter++;
                   2750: 
                   2751:                extract_keyID(keyID, n);
                   2752:                PascalToC(userid);
                   2753: 
                   2754:                if (strcontains(userid,mcguffin))
                   2755:                {
                   2756:                        if (is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE))
                   2757:                        {
                   2758:                                if (testeq(e,0))        /* e==0 means key compromised */
                   2759:                                        fprintf(stderr,"com "); /* "key compromised" certificate */
                   2760:                                else
                   2761:                                        fprintf(stderr,"pub "); /* public key certificate */
                   2762:                        }
                   2763:                        else if (is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
                   2764:                                fprintf(stderr,"sec ");         /* secret key certificate */
                   2765:                        else
                   2766:                                fprintf(stderr,"??? ");         /* otherwise, who knows? */
                   2767: 
                   2768:                        fprintf(stderr,"%4d/",countbits(n));
                   2769:                        showkeyID(keyID);
                   2770:                        fputc(' ',stderr);
                   2771:                        show_date((long *)timestamp);
                   2772:                        fprintf(stderr,"  ");
                   2773:                        fprintf(stderr,userid);
                   2774:                        fputc('\n',stderr);
                   2775:                }       /* if it has mcguffin */
                   2776:        } while (status >= 0);
                   2777: 
                   2778:        fclose(f);      /* close key file */
                   2779:        fprintf(stderr,"%d key(s) examined. ",keycounter);
                   2780: 
                   2781:        return(0);      /* normal return */
                   2782: 
                   2783: }      /* view_keyring */
                   2784: 
                   2785: 
                   2786: 
                   2787: int remove_from_keyring(byte *keyID, char *mcguffin, char *ringfile)
                   2788: /*     Remove the first entry in key ring that has mcguffin string in userid.
                   2789:        Or it removes the first matching keyID from the ring.
                   2790:        A non-NULL keyID takes precedence over a mcguffin specifier.
                   2791:        mcguffin is a null-terminated C string.
                   2792: */
                   2793: {
                   2794:        FILE *f;
                   2795:        FILE *g;
                   2796:        long file_position,fp,after_key;
                   2797:        int packetlength=0;
                   2798:        byte ctb;
                   2799:        int status;
                   2800:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2801:        byte userid[256];               /* key certificate userid */
                   2802:        word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   2803: 
                   2804:        default_extension(ringfile,PUB_EXTENSION);
                   2805: 
                   2806:        if ((keyID==NULL) && (strlen(mcguffin)==0))
                   2807:                return(-1); /* error, null mcguffin will match everything */
                   2808: 
                   2809:        strcpy(userid,mcguffin);
                   2810: 
                   2811:        fprintf(stderr,"\nRemoving from key ring: '%s'",ringfile);
                   2812:        if (strlen(mcguffin) > 0)
                   2813:                fprintf(stderr,", userid \"%s\".\n",mcguffin);
                   2814: 
                   2815:        status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e);
                   2816:        if (status < 0)
                   2817:        {       fprintf(stderr,"\n\aKey not found in key ring '%s'.\n",ringfile);
                   2818:                return(0);      /* normal return */
                   2819:        }
                   2820:        after_key = fp + packetlength;
                   2821: 
                   2822:        if (testeq(e,0))        /* This is a key compromise certificate. */
                   2823:        {       /* Wish there was a more elegant way to handle this... */
                   2824:                fprintf(stderr,"\n\aWARNING: This is a \"key compromised\" certificate.");
                   2825:                fprintf(stderr,"\nIt should not be removed from the key ring!\n");
                   2826:                if (keyID != NULL) /* Decision requires human confirmation. */
                   2827:                        return(-1);
                   2828:        }
                   2829: 
                   2830:        if (keyID==NULL)        /* Human confirmation is required. */
                   2831:        {       /* Supposedly the key was fully displayed by getpublickey */
                   2832:                fprintf(stderr,"\nAre you sure you want this key removed (y/N)? ");
                   2833:                if (!getyesno('n'))
                   2834:                        return(-1);     /* user said "no" */
                   2835:        }
                   2836: 
                   2837:        /* open file f for read, in binary (not text) mode...*/
                   2838:        if ((f = fopen(ringfile,"rb")) == NULL)
                   2839:        {       fprintf(stderr,"\n\aCan't open key ring file '%s'\n",ringfile);
                   2840:                return(-1);
                   2841:        }
                   2842: 
                   2843:        remove(SCRATCH_KEYRING_FILENAME);
                   2844:        /* open file g for writing, in binary (not text) mode...*/
                   2845:        if ((g = fopen(SCRATCH_KEYRING_FILENAME,"wb")) == NULL)
                   2846:        {       fclose(f);
                   2847:                return(-1);
                   2848:        }
                   2849:        rewind(f);
                   2850:        copyfile(f,g,fp);       /* copy file f to g up to position fp */
                   2851:        fseek(f,after_key,SEEK_SET); /* reposition file to after key */
                   2852:        copyfile(f,g,-1UL);     /* copy rest of file from file f to g */
                   2853:        fclose(g);      /* close scratch file */
                   2854:        fclose(f);      /* close key file */
                   2855:        remove(ringfile); /* dangerous.  sure hope rename works... */
                   2856:        rename(SCRATCH_KEYRING_FILENAME,ringfile);
                   2857:        fprintf(stderr,"\nKey removed from key ring. ");
                   2858: 
                   2859:        return(0);      /* normal return */
                   2860: 
                   2861: }      /* remove_from_keyring */
                   2862: 
                   2863: 
                   2864: 
                   2865: int addto_keyring(char *keyfile, char *ringfile)
                   2866: /*     Adds (prepends) key file to key ring file */
                   2867: {      FILE *f;
                   2868:        FILE *g;
                   2869:        long file_position,fp;
                   2870:        int pktlen;     /* unused, just to satisfy getpublickey */
                   2871:        byte ctb;
                   2872:        int status;
                   2873:        unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
                   2874:        byte keyID[KEYFRAGSIZE];
                   2875:        byte userid[256];               /* key certificate userid */
                   2876:        word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   2877:        boolean keycompromised;
                   2878: 
                   2879:        if (strcontains(ringfile,SEC_EXTENSION))
                   2880:                force_extension(SCRATCH_KEYRING_FILENAME,SEC_EXTENSION);
                   2881:        else
                   2882:                force_extension(SCRATCH_KEYRING_FILENAME,PUB_EXTENSION);
                   2883: 
                   2884:        /* open file f for read, in binary (not text) mode...*/
                   2885:        if ((f = fopen(keyfile,"rb")) == NULL)
                   2886:        {       fprintf(stderr,"\n\aCan't open key file '%s'\n",keyfile);
                   2887:                return(-1);
                   2888:        }
                   2889: 
                   2890:        /*      Check to see if the keyID is already in key ring before we add it in. */
                   2891: 
                   2892:        file_position = ftell(f);
                   2893:        status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
                   2894:                        NULL,NULL,NULL,NULL);
                   2895:        /* Note that readkeypacket has called set_precision */
                   2896:        if (status < 0)
                   2897:        {       fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
                   2898:                        keyfile);
                   2899:                fclose(f);      /* close key file */
                   2900:                return(-1);
                   2901:        }
                   2902: 
                   2903:        if (!is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE)
                   2904:                && !is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
                   2905:        {       fprintf(stderr,"\n\aError in file '%s'.  Not a key certificate.\n",
                   2906:                        keyfile);
                   2907:                return(-1);
                   2908:        }
                   2909: 
                   2910:        extract_keyID(keyID, n);        /* from keyfile, not ringfile */
                   2911: 
                   2912:        if (!file_exists(ringfile))
                   2913:        {       /* ringfile does not exist.  Can it be created? */
                   2914:                /* open file g for writing, in binary (not text) mode...*/
                   2915:                g = fopen(ringfile,"wb");
                   2916:                if (g==NULL)
                   2917:                {       fprintf(stderr,"\n\aKey ring file '%s' cannot be created.\n",ringfile);
                   2918:                        fclose(f);
                   2919:                        return(-1);
                   2920:                }
                   2921:                fclose(g);
                   2922:        }
                   2923: 
                   2924:        /* See if we are adding a "secret key compromised" certificate: */
                   2925:        keycompromised = testeq(e,0);
                   2926: 
                   2927:        /*      If this is a key compromise certificate, maybe we should 
                   2928:                remove the real public key from the key ring if it's on the 
                   2929:                key ring before adding the key compromise certificate.
                   2930:                Probably not, though, because the prepended key compromise 
                   2931:                certificate will take search order precedence.
                   2932:                And it may be nice to keep the original public key certificate
                   2933:                around for its timestamp, to check old signatures.
                   2934:                It should not be possible to later add the same public key to
                   2935:                the ring again if the key compromise certificate was there first.
                   2936: 
                   2937:                These tests for duplicates should have to be applied for all
                   2938:                the keys being added to the ring, in case the added key file
                   2939:                is itself a multikey ring.  Fix this later.
                   2940:        */
                   2941: 
                   2942:        /*      Check for duplicate key in key ring: */
                   2943:        if (getpublickey(TRUE, TRUE, ringfile, &fp, &pktlen, keyID, timestamp, userid, n, e) >= 0)
                   2944:        {       fprintf(stderr,"\n\aKey already included in key ring '%s'.\n",ringfile);
                   2945:                if (!keycompromised) /* allows duplicate if key compromised */
                   2946:                {       fclose(f);      /* close key file */
                   2947:                        return(0);      /* normal return */
                   2948:                }
                   2949:        }
                   2950: 
                   2951:        if (keycompromised)
                   2952:                fprintf(stderr,"\nAdding \"key compromise\" certificate '%s' to key ring '%s'.\n",
                   2953:                        keyfile,ringfile);
                   2954:        else
                   2955:                fprintf(stderr,"\nAdding key certificate '%s' to key ring '%s'.\n",keyfile,ringfile);
                   2956: 
                   2957:        /*      The key is prepended to the ring to give it search precedence 
                   2958:                over other keys with that same userid. */
                   2959: 
                   2960:        fseek(f,file_position,SEEK_SET); /* reposition file to key */
                   2961: 
                   2962:        remove(SCRATCH_KEYRING_FILENAME);
                   2963:        /* open file g for writing, in binary (not text) mode...*/
                   2964:        if ((g = fopen(SCRATCH_KEYRING_FILENAME,"wb")) == NULL)
                   2965:        {       fclose(f);
                   2966:                return(-1);
                   2967:        }
                   2968:        copyfile(f,g,-1UL);     /* copy rest of file from file f to g */
                   2969:        fclose(f);
                   2970: 
                   2971: 
                   2972:        /* open file f for reading, in binary (not text) mode...*/
                   2973:        if ((f = fopen(ringfile,"rb")) != NULL)
                   2974:        {       copyfile(f,g,-1UL);     /* copy rest of file from file f to g */
                   2975:                fclose(f);
                   2976:        }
                   2977:        fclose(g);
                   2978: 
                   2979:        remove(ringfile); /* dangerous.  sure hope rename works... */
                   2980:        rename(SCRATCH_KEYRING_FILENAME,ringfile);
                   2981: 
                   2982:        return(0);      /* normal return */
                   2983: 
                   2984: }      /* addto_keyring */
                   2985: 
                   2986: 
                   2987: /*======================================================================*/
                   2988: 
                   2989: 
                   2990: 
                   2991: int dokeygen(char *keyfile, char *numstr, char *numstr2)
                   2992: /*     Do an RSA key pair generation, and write them out to a pair of files.   
                   2993:        The keyfile filename string must not have a file extension.
                   2994:        numstr is a decimal string, the desired bitcount for the modulus n.
                   2995:        numstr2 is a decimal string, the desired bitcount for the exponent e.
                   2996: */
                   2997: {      unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
                   2998:             p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
                   2999:        char fname[64];
                   3000:        char ringfile[64];
                   3001:        byte iv[256]; /* for BassOmatic CFB mode, to protect RSA secret key */
                   3002:        byte userid[256];
                   3003:        short keybits,ebits,i;
                   3004:        word32 tstamp; byte *timestamp = (byte *) &tstamp;              /* key certificate timestamp */
                   3005:        boolean hidekey;        /* TRUE iff secret key is encrypted */
                   3006: 
                   3007:        strcpy(fname,keyfile); 
                   3008:        if (strlen(fname)==0)
                   3009:        {       fprintf(stderr,"\nKey file name is required for RSA key pair: ");
                   3010:                getstring(fname,sizeof(fname)-4,TRUE);
                   3011:        }
                   3012: 
                   3013:        if (strlen(numstr)==0)
                   3014:        {       fprintf(stderr,"\nPick your RSA key size: "
                   3015:                        "\n     1)      288 bits- Casual grade, fast but less secure"
                   3016:                        "\n     2)      512 bits- Commercial grade, medium speed, good security"
                   3017:                        "\n     3)      992 bits- Military grade, very slow, highest security"
                   3018:                        "\nChoose 1, 2, or 3, or enter desired number of bits: ");
                   3019:                numstr = userid;        /* use userid buffer as scratchpad */
                   3020:                getstring(numstr,5,TRUE);       /* echo keyboard */
                   3021:        }
                   3022: 
                   3023:        keybits = 0;
                   3024:        while ((*numstr>='0') && (*numstr<='9')) 
                   3025:                keybits = keybits*10 + (*numstr++ - '0');
                   3026: 
                   3027:        /* Standard default key sizes: */
                   3028:        if (keybits==1) keybits=286;    /* Casual grade */
                   3029:        if (keybits==2) keybits=510;    /* Commercial grade */
                   3030:        if (keybits==3) keybits=990;    /* Military grade */
                   3031: 
                   3032:        /* minimum RSA keysize for BassOmatic bootstrap: */
                   3033:        if (keybits<286) keybits=286;
                   3034: 
                   3035:        ebits = 0;      /* number of bits in e */
                   3036:        while ((*numstr2>='0') && (*numstr2<='9')) 
                   3037:                ebits = ebits*10 + (*numstr2++ - '0');
                   3038: 
                   3039:        fprintf(stderr,"\nGenerating an RSA key with a %d-bit modulus... ",keybits);
                   3040: 
                   3041:        fprintf(stderr,"\nEnter a user ID for your public key (your name): ");
                   3042:        getstring(userid,255,TRUE);     /* echo keyboard input */
                   3043:        CToPascal(userid);      /* convert to length-prefixed string */
                   3044: 
                   3045:        {       char passphrase[256];
                   3046:                fprintf(stderr,"\nYou need a pass phrase to protect your RSA secret key. ");
                   3047:                hidekey = (getpassword(passphrase,2,0x0f) > 0);
                   3048:                /* init CFB BassOmatic key */
                   3049:                if (hidekey)
                   3050:                {       fill0(iv,256);  /* define initialization vector IV as 0 */
                   3051:                        if ( initcfb(iv,passphrase,string_length(passphrase),FALSE) < 0 )
                   3052:                                return(-1);
                   3053:                        burn(passphrase);       /* burn sensitive data on stack */
                   3054:                }
                   3055:        }
                   3056: 
                   3057:        fprintf(stderr,"\nNote that key generation is a VERY lengthy process.\n");
                   3058: 
                   3059:        if (keygen(n,e,d,p,q,u,keybits,ebits) < 0)
                   3060:        {       fprintf(stderr,"\n\aKeygen failed!\n");
                   3061:                return(-1);     /* error return */
                   3062:        }
                   3063: 
                   3064:        if (verbose)
                   3065:        {
                   3066:                fprintf(stderr,"Key ID ");
                   3067:                showkeyID2(n); fputc('\n',stderr);
                   3068: 
                   3069:                mp_display(" modulus n = ",n);
                   3070:                mp_display("exponent e = ",e);
                   3071: 
                   3072:                mp_display("exponent d = ",d);
                   3073:                mp_display("   prime p = ",p);
                   3074:                mp_display("   prime q = ",q);
                   3075:                mp_display(" inverse u = ",u);
                   3076:        }
                   3077: 
                   3078:        get_timestamp(timestamp);       /* Timestamp when key was generated */
                   3079: 
                   3080:        fputc('\a',stderr);  /* sound the bell when done with lengthy process */
                   3081: 
                   3082:        force_extension(fname,SEC_EXTENSION);
                   3083:        writekeyfile(fname,hidekey,timestamp,userid,n,e,d,p,q,u); 
                   3084:        force_extension(fname,PUB_EXTENSION);
                   3085:        writekeyfile(fname,FALSE,timestamp,userid,n,e,NULL,NULL,NULL,NULL); 
                   3086:        
                   3087:        if (hidekey)    /* done with Bassomatic to protect RSA secret key */
                   3088:                closebass();
                   3089: 
                   3090:        mp_burn(d);     /* burn sensitive data on stack */
                   3091:        mp_burn(p);     /* burn sensitive data on stack */
                   3092:        mp_burn(q);     /* burn sensitive data on stack */
                   3093:        mp_burn(u);     /* burn sensitive data on stack */
                   3094:        mp_burn(e);     /* burn sensitive data on stack */
                   3095:        mp_burn(n);     /* burn sensitive data on stack */
                   3096:        burn(iv);       /* burn sensitive data on stack */
                   3097: 
                   3098:        force_extension(fname,PUB_EXTENSION);
                   3099:        buildfilename(ringfile,PUBLIC_KEYRING_FILENAME);
                   3100:        fprintf(stderr,"\nAdd public key to key ring '%s' (y/N)? ",ringfile);
                   3101:        if (getyesno('n'))
                   3102:                addto_keyring(fname,ringfile);
                   3103:        force_extension(fname,SEC_EXTENSION);
                   3104:        buildfilename(ringfile,SECRET_KEYRING_FILENAME);
                   3105:        fprintf(stderr,"Add secret key to key ring '%s' (y/N)? ",ringfile);
                   3106:        if (getyesno('n'))
                   3107:                addto_keyring(fname,ringfile);
                   3108: 
                   3109:        /*      Force initialization of cryptographically strong pseudorandom
                   3110:                number generator seed file for later use...
                   3111:        */
                   3112:        strong_pseudorandom(iv,1);
                   3113: 
                   3114:        return(0);      /* normal return */
                   3115: }      /* dokeygen */
                   3116: 
                   3117: 
                   3118: /*======================================================================*/
                   3119: 
                   3120: 
                   3121: void main(int argc, char *argv[])
                   3122: {      char keyfile[64], plainfile[64], cipherfile[64], ringfile[64], tempfile[64];
                   3123:        int status,i;
                   3124:        boolean nestflag = FALSE;
                   3125:        boolean uu_emit = FALSE;
                   3126:        boolean wipeflag = FALSE;
                   3127:        byte ctb;
                   3128:        byte header[6]; /* used to classify file type at the end. */
                   3129:        char mcguffin[256];     /* userid search tag */
                   3130: 
                   3131: #ifdef DEBUG1
                   3132:        verbose = TRUE;
                   3133: #endif
                   3134: 
                   3135:        fprintf(stderr,"Pretty Good Privacy 1.0 - RSA public key cryptography for the masses.\n"
                   3136:                "(c) Copyright 1990 Philip Zimmermann, Phil's Pretty Good Software.  5 Jun 91\n");
                   3137: 
                   3138:        if (argc <= 1)
                   3139:        {       fprintf(stderr,
                   3140:                "\nFor details on free licensing and distribution, see the PGP User's Guide."
                   3141:                "\nFor other cryptography products and custom development services, contact:"
                   3142:                "\nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, phone (303)444-4541"
                   3143:                );
                   3144:                goto usage;
                   3145:        }
                   3146: 
                   3147:        /* Make sure arguments will fit into filename strings: */
                   3148:        for (i = 1; i <= argc; i++)
                   3149:        {
                   3150:                if (strlen(argv[i]) >= sizeof(cipherfile)-4)
                   3151:                {
                   3152:                        fprintf(stderr, "\aInvalid filename: [%s] too long\n", argv[i] );
                   3153:                        goto user_error;
                   3154:                }
                   3155:        }
                   3156: 
                   3157:        if (argv[1][0] == '-')
                   3158:        {
                   3159:                if (strhas(argv[1],'l'))
                   3160:                        verbose = TRUE;
                   3161: 
                   3162:                nestflag = strhas(argv[1],'n');
                   3163: 
                   3164:                uu_emit = strhas(argv[1],'u');
                   3165: 
                   3166:                wipeflag = strhas(argv[1],'w');
                   3167: 
                   3168:                /*-------------------------------------------------------*/
                   3169:                if ( (argc >= 3)
                   3170:                &&  strhasany(argv[1],"sS")     &&  strhasany(argv[1],"eE") )
                   3171:                {       /* Sign AND encrypt file */
                   3172:                        /* Arguments: plainfile, her_userid, your_userid, cipherfile */
                   3173:                        boolean separate_signature = FALSE;
                   3174: 
                   3175:                        strcpy( plainfile, argv[2] );
                   3176: 
                   3177:                        if (argc>=6)    /* default signature file extension */
                   3178:                        {       strcpy( cipherfile, argv[5] );
                   3179:                                default_extension( cipherfile, CTX_EXTENSION );
                   3180:                        }
                   3181:                        else
                   3182:                        {       /* Default the signature file name */
                   3183:                                strcpy( cipherfile, plainfile );
                   3184:                                /* ...but replace file extension: */
                   3185:                                force_extension( cipherfile, CTX_EXTENSION );
                   3186:                        }
                   3187: 
                   3188:                        if (strcmp( plainfile, cipherfile ) == 0)
                   3189:                        {       fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
                   3190:                                goto user_error;        /* same filenames for both files */
                   3191:                        }
                   3192: 
                   3193:                        if (argc>=5)
                   3194:                        {       strcpy( mcguffin, argv[4] );    /* Userid of signer */
                   3195:                                translate_spaces( mcguffin );   /* change all '_' to ' ' */
                   3196:                        }
                   3197:                        else
                   3198:                        {       fprintf(stderr, "\nEnter userid to look up your secret key for signature: ");
                   3199:                                getstring( mcguffin, 255, TRUE );       /* echo keyboard */
                   3200:                        }
                   3201: 
                   3202:                        if (nestflag)   /* user thinks this file has nested info */
                   3203:                        {       get_header_info_from_file( plainfile, &ctb, 1);
                   3204:                                if (!legal_ctb(ctb))
                   3205:                                {       nestflag = FALSE;
                   3206:                                        fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
                   3207:                                }
                   3208:                        }
                   3209: 
                   3210:                        status = signfile( nestflag, separate_signature,
                   3211:                                         mcguffin, plainfile, SCRATCH_CTX_FILENAME );
                   3212: 
                   3213:                        if (status < 0)         /* signfile failed */
                   3214:                        {       fprintf(stderr, "\aSignature error\n" );
                   3215:                                goto user_error;
                   3216:                        }
                   3217: 
                   3218:                        if (wipeflag)
                   3219:                        {       wipefile(plainfile); /* destroy every trace of plaintext */
                   3220:                                remove(plainfile);
                   3221:                                fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
                   3222:                        }
                   3223: 
                   3224:                        if (argc>=4)
                   3225:                        {       strcpy( mcguffin, argv[3] );    /* Userid of recipient */
                   3226:                                translate_spaces( mcguffin );   /* change all '_' to ' ' */
                   3227:                        }
                   3228:                        else
                   3229:                        {       fprintf(stderr, "\nEnter userid to look up recipient's public key: ");
                   3230:                                getstring( mcguffin, 255, TRUE );       /* echo keyboard */
                   3231:                        }
                   3232: 
                   3233:                        /* Indicate that encrypted data has nested signature: */
                   3234: 
                   3235:                        status = encryptfile( TRUE, mcguffin, SCRATCH_CTX_FILENAME, cipherfile );
                   3236: 
                   3237:                        wipefile( SCRATCH_CTX_FILENAME );
                   3238:                        remove( SCRATCH_CTX_FILENAME );
                   3239:                        
                   3240:                        if (status < 0)
                   3241:                        {       fprintf(stderr, "\aEncryption error\n" );
                   3242:                                goto user_error;
                   3243:                        }
                   3244: 
                   3245:                        if (uu_emit)
                   3246:                        {       status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
                   3247:                                remove(cipherfile); /* dangerous.  sure hope rename works... */
                   3248:                                rename(SCRATCH_CTX_FILENAME, cipherfile);
                   3249:                        }
                   3250: 
                   3251:                        if (!verbose)   /* if other filename messages were supressed */
                   3252:                                fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
                   3253: 
                   3254:                        exit(0);
                   3255:                }       /* Sign AND encrypt file */
                   3256: 
                   3257: 
                   3258:                /*-------------------------------------------------------*/
                   3259:                if ( (argc >= 3) && strhasany(argv[1],"sS") )
                   3260:                {       /*      Sign file
                   3261:                                Arguments: plaintextfile, your_userid, signedtextfile
                   3262:                                Two kinds of signature:  full signature certificate,
                   3263:                                or just an RSA-signed message digest.
                   3264:                        */
                   3265: 
                   3266:                        boolean separate_signature = FALSE;
                   3267: 
                   3268:                        separate_signature = strhas( argv[1], 'b' );
                   3269: 
                   3270:                        strcpy( plainfile, argv[2] );
                   3271: 
                   3272:                        if (argc>=5)    /* default signature file extension */
                   3273:                        {       strcpy( cipherfile, argv[4] );
                   3274:                                default_extension( cipherfile, CTX_EXTENSION );
                   3275:                        }
                   3276:                        else
                   3277:                        {       /* Default the signature file name */
                   3278:                                strcpy( cipherfile, plainfile );
                   3279:                                /* ...but replace file extension: */
                   3280:                                force_extension( cipherfile, CTX_EXTENSION );
                   3281:                        }
                   3282: 
                   3283:                        if (strcmp( plainfile, cipherfile ) == 0)
                   3284:                        {       fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
                   3285:                                goto user_error;        /* same filenames for both files */
                   3286:                        }
                   3287: 
                   3288:                        if (argc>=4)
                   3289:                        {       strcpy( mcguffin, argv[3] );    /* Userid of signer */
                   3290:                                translate_spaces( mcguffin );   /* change all '_' to ' ' */
                   3291:                        }
                   3292:                        else
                   3293:                        {       fprintf(stderr, "\nEnter userid to look up your secret key for signature: ");
                   3294:                                getstring( mcguffin, 255, TRUE );       /* echo keyboard */
                   3295:                        }
                   3296: 
                   3297:                        if (nestflag)   /* user thinks this file has nested info */
                   3298:                        {       get_header_info_from_file( plainfile, &ctb, 1);
                   3299:                                if (!legal_ctb(ctb))
                   3300:                                {       nestflag = FALSE;
                   3301:                                        fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
                   3302:                                }
                   3303:                        }
                   3304: 
                   3305:                        status = signfile( nestflag, separate_signature,
                   3306:                                         mcguffin, plainfile, cipherfile );
                   3307: 
                   3308:                        if (status < 0)         /* signfile failed */
                   3309:                        {       fprintf(stderr, "\aSignature error\n" );
                   3310:                                goto user_error;
                   3311:                        }
                   3312: 
                   3313:                        if (uu_emit)
                   3314:                        {       status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
                   3315:                                remove(cipherfile); /* dangerous.  sure hope rename works... */
                   3316:                                rename(SCRATCH_CTX_FILENAME, cipherfile);
                   3317:                        }
                   3318: 
                   3319:                        if (!verbose)   /* if other filename messages were supressed */
                   3320:                                fprintf(stderr,"\nSignature file: %s ", cipherfile);
                   3321: 
                   3322:                        exit(0);
                   3323:                }       /* Sign file */
                   3324: 
                   3325: 
                   3326:                /*-------------------------------------------------------*/
                   3327:                if ( (argc >= 3) && strhasany(argv[1],"eE") )
                   3328:                {       /*      Encrypt file
                   3329:                                Arguments: plaintextfile, her_userid, ciphertextfile
                   3330:                        */
                   3331: 
                   3332:                        strcpy( plainfile, argv[2] );
                   3333: 
                   3334:                        if (argc >= 5)  /* default cipher file extension */
                   3335:                        {       strcpy( cipherfile, argv[4] );
                   3336:                                default_extension( cipherfile, CTX_EXTENSION );
                   3337:                        }
                   3338:                        else
                   3339:                        {       /* Default the cipherfile name */
                   3340:                                strcpy( cipherfile, plainfile );
                   3341:                                force_extension( cipherfile, CTX_EXTENSION );
                   3342:                        }
                   3343: 
                   3344:                        if (strcmp( plainfile, cipherfile) == 0)
                   3345:                        {       fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
                   3346:                                goto user_error;        /* same filenames for both files */
                   3347:                        }
                   3348: 
                   3349:                        if (argc >= 4)
                   3350:                        {       strcpy( mcguffin, argv[3] );    /* Userid of recipient */
                   3351:                                translate_spaces( mcguffin );   /* change all '_' to ' ' */
                   3352:                        }
                   3353:                        else
                   3354:                        {       fprintf(stderr, "\nEnter userid to look up recipient's public key: ");
                   3355:                                getstring( mcguffin, 255, TRUE );       /* echo keyboard */
                   3356:                        }
                   3357: 
                   3358:                        if (nestflag)   /* user thinks this file has nested info */
                   3359:                        {       get_header_info_from_file( plainfile, &ctb, 1);
                   3360:                                if (!legal_ctb(ctb))
                   3361:                                {       nestflag = FALSE;
                   3362:                                        fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
                   3363:                                }
                   3364:                        }
                   3365: 
                   3366:                        if (!nestflag)
                   3367:                        {       /*      Prepend CTB_LITERAL byte to plaintext file. 
                   3368:                                        --sure wish this pass could be optimized away. */
                   3369:                                strcpy( tempfile, plainfile );
                   3370:                                strcpy( plainfile, SCRATCH_PTX_FILENAME );
                   3371:                                status = make_literal( tempfile, plainfile );
                   3372:                        }
                   3373:                        status = encryptfile( nestflag, mcguffin, plainfile, cipherfile );
                   3374: 
                   3375:                        if (!nestflag)
                   3376:                        {       wipefile( SCRATCH_PTX_FILENAME );
                   3377:                                remove( SCRATCH_PTX_FILENAME );
                   3378:                                strcpy( plainfile, tempfile );
                   3379:                        }
                   3380: 
                   3381:                        if (status < 0) /* encryptfile failed */
                   3382:                        {       fprintf(stderr, "\aEncryption error\n" );
                   3383:                                goto user_error;
                   3384:                        }
                   3385: 
                   3386:                        if (wipeflag)
                   3387:                        {       wipefile(plainfile); /* destroy every trace of plaintext */
                   3388:                                remove(plainfile);
                   3389:                                fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
                   3390:                        }
                   3391: 
                   3392:                        if (uu_emit)
                   3393:                        {       status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
                   3394:                                remove(cipherfile); /* dangerous.  sure hope rename works... */
                   3395:                                rename(SCRATCH_CTX_FILENAME, cipherfile);
                   3396:                        }
                   3397: 
                   3398:                        if (!verbose)   /* if other filename messages were supressed */
                   3399:                                fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
                   3400: 
                   3401:                        exit(0);
                   3402:                }       /* Encrypt file */
                   3403: 
                   3404: 
                   3405:                /*-------------------------------------------------------*/
                   3406:                if ( (argc >= 3) && strhasany(argv[1],"cC") )
                   3407:                {       /*      Encrypt file with BassOmatic only
                   3408:                                Arguments: plaintextfile, ciphertextfile
                   3409:                        */
                   3410: 
                   3411:                        strcpy( plainfile, argv[2] );
                   3412: 
                   3413:                        if (argc >= 4)  /* default cipher file extension */
                   3414:                        {       strcpy( cipherfile, argv[3] );
                   3415:                                default_extension( cipherfile, CTX_EXTENSION );
                   3416:                        }
                   3417:                        else
                   3418:                        {       /* Default the cipherfile name */
                   3419:                                strcpy( cipherfile, plainfile );
                   3420:                                force_extension( cipherfile, CTX_EXTENSION );
                   3421:                        }
                   3422: 
                   3423:                        if (strcmp( plainfile, cipherfile) == 0)
                   3424:                        {       fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
                   3425:                                goto user_error;        /* same filenames for both files */
                   3426:                        }
                   3427: 
                   3428:                        if (nestflag)   /* user thinks this file has nested info */
                   3429:                        {       get_header_info_from_file( plainfile, &ctb, 1);
                   3430:                                if (!legal_ctb(ctb))
                   3431:                                {       nestflag = FALSE;
                   3432:                                        fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
                   3433:                                }
                   3434:                        }
                   3435: 
                   3436:                        if (!nestflag)
                   3437:                        {       /*      Prepend CTB_LITERAL byte to plaintext file. 
                   3438:                                        --sure wish this pass could be optimized away. */
                   3439:                                strcpy( tempfile, plainfile );
                   3440:                                strcpy( plainfile, SCRATCH_PTX_FILENAME );
                   3441:                                status = make_literal( tempfile, plainfile );
                   3442:                        }
                   3443: 
                   3444:                        status = bass_encryptfile( nestflag, plainfile, cipherfile );
                   3445: 
                   3446:                        if (!nestflag)
                   3447:                        {       wipefile( SCRATCH_PTX_FILENAME );
                   3448:                                remove( SCRATCH_PTX_FILENAME );
                   3449:                                strcpy( plainfile, tempfile );
                   3450:                        }
                   3451: 
                   3452:                        if (status < 0) /* encryptfile failed */
                   3453:                        {       fprintf(stderr, "\aEncryption error\n" );
                   3454:                                goto user_error;
                   3455:                        }
                   3456: 
                   3457:                        if (wipeflag)
                   3458:                        {       wipefile(plainfile); /* destroy every trace of plaintext */
                   3459:                                remove(plainfile);
                   3460:                                fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
                   3461:                        }
                   3462: 
                   3463:                        if (uu_emit)
                   3464:                        {       status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
                   3465:                                remove(cipherfile); /* dangerous.  sure hope rename works... */
                   3466:                                rename(SCRATCH_CTX_FILENAME, cipherfile);
                   3467:                        }
                   3468: 
                   3469:                        if (!verbose)   /* if other filename messages were supressed */
                   3470:                                fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
                   3471: 
                   3472:                        exit(0);
                   3473:                }       /* Encrypt file with BassOmatic only */
                   3474: 
                   3475: 
                   3476:                /*-------------------------------------------------------*/
                   3477:                if (argv[1][1] == 'k')
                   3478:                {       /*      Key generation
                   3479:                                Arguments: keyfile, bitcount, bitcount
                   3480:                        */
                   3481:                        char    keyfile[64], keybits[6], ebits[6];
                   3482: 
                   3483:                        if (argc > 2)
                   3484:                                strcpy( keyfile, argv[2] );
                   3485:                        else
                   3486:                                strcpy( keyfile, "" );
                   3487: 
                   3488:                        if (argc > 3)
                   3489:                                strncpy( keybits, argv[3], sizeof(keybits)-1 );
                   3490:                        else
                   3491:                                strcpy( keybits, "" );
                   3492: 
                   3493:                        if (argc > 4)
                   3494:                                strncpy( ebits, argv[4], sizeof(ebits)-1 );
                   3495:                        else
                   3496:                                strcpy( ebits, "" );
                   3497: 
                   3498:                        status = dokeygen( keyfile, keybits, ebits );
                   3499: 
                   3500:                        if (status < 0)
                   3501:                        {       fprintf(stderr, "\aKeygen error. " );
                   3502:                                goto user_error;
                   3503:                        }
                   3504:                        exit(0);
                   3505:                }       /* Key generation */
                   3506: 
                   3507:                /*-------------------------------------------------------*/
                   3508:                if ((argc >= 3) && (argv[1][1] == 'a'))
                   3509:                {       /*      Add key to key ring
                   3510:                                Arguments: keyfile, ringfile
                   3511:                        */
                   3512:                        if (argc < 4)   /* default key ring filename */
                   3513:                                buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
                   3514:                        else
                   3515:                                strncpy( ringfile, argv[3], sizeof(ringfile)-1 );
                   3516:                        strncpy( keyfile, argv[2], sizeof(keyfile)-1 );
                   3517: 
                   3518:                        strlwr( keyfile  );
                   3519:                        strlwr( ringfile );
                   3520:                        if (! file_exists( keyfile ))
                   3521:                                default_extension( keyfile, PUB_EXTENSION );
                   3522: 
                   3523:                        if (strcontains( keyfile, SEC_EXTENSION ))
                   3524:                                force_extension( ringfile, SEC_EXTENSION );
                   3525:                        else
                   3526:                                force_extension( ringfile, PUB_EXTENSION );
                   3527: 
                   3528:                        if (! file_exists( keyfile ))
                   3529:                        {       fprintf(stderr, "\n\aKey file '%s' does not exist.\n", keyfile );
                   3530:                                goto user_error;
                   3531:                        }
                   3532: 
                   3533:                        status = addto_keyring( keyfile, ringfile );
                   3534: 
                   3535:                        if (status < 0)
                   3536:                        {       fprintf(stderr, "\aKeyring add error. " );
                   3537:                                goto user_error;
                   3538:                        }
                   3539:                        exit(0);
                   3540:                }       /* Add key to key ring */
                   3541: 
                   3542:                /*-------------------------------------------------------*/
                   3543:                if ((argc >= 2)
                   3544:                && strhasany( argv[1], "vr" ) )
                   3545:                {       /*      View or remove key ring entries, with userid match
                   3546:                                Arguments: userid, ringfile
                   3547:                        */
                   3548:                        if (argc < 4)   /* default key ring filename */
                   3549:                                buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
                   3550:                        else
                   3551:                                strcpy( ringfile, argv[3] );
                   3552: 
                   3553:                        strcpy( mcguffin, argv[2] );
                   3554:                        if (strcmp( mcguffin, "*" ) == 0)
                   3555:                                strcpy( mcguffin, "" );
                   3556: 
                   3557:                        translate_spaces( mcguffin );   /* change all '_' to ' ' */
                   3558: 
                   3559:                        if ((argc < 4) 
                   3560:                        && (strcontains( argv[2], PUB_EXTENSION )
                   3561:                        ||  strcontains( argv[2], SEC_EXTENSION )))
                   3562:                        {       strcpy( ringfile, argv[2] );
                   3563:                                strcpy( mcguffin, "" );
                   3564:                        }
                   3565: 
                   3566:                        strlwr( ringfile );
                   3567:                        if (! file_exists( ringfile ))
                   3568:                                default_extension( ringfile, PUB_EXTENSION );
                   3569: 
                   3570:                        if (strhas( argv[1], 'v' ))
                   3571:                                if (view_keyring( mcguffin, ringfile ) < 0)
                   3572:                                {       fprintf(stderr, "\aKeyring view error. " );
                   3573:                                        goto user_error;
                   3574:                                }
                   3575:                        if (strhas( argv[1], 'r' ))
                   3576:                                if (remove_from_keyring( NULL, mcguffin, ringfile ) < 0)
                   3577:                                {       fprintf(stderr, "\aKeyring remove error. " );
                   3578:                                        goto user_error;
                   3579:                                }
                   3580:                        exit(0);
                   3581:                }       /* view or remove key ring entries, with userid match */
                   3582:                /*-------------------------------------------------------*/
                   3583:                
                   3584:                fprintf(stderr, "\aUnrecognizable parameters. " );
                   3585:                goto user_error;
                   3586:        }       /* -options specified */
                   3587: 
                   3588: 
                   3589:        /*---------------------------------------------------------*/
                   3590:        /* no options specified */
                   3591: 
                   3592:        if (argc >= 2)
                   3593:        {       /*      Decrypt file
                   3594:                        Arguments: ciphertextfile, plaintextfile
                   3595:                */
                   3596:                strcpy( cipherfile, argv[1] ); 
                   3597:                default_extension( cipherfile, CTX_EXTENSION );
                   3598:  
                   3599:                if (argc >= 3)
                   3600:                {       strcpy( plainfile, argv[2] );
                   3601:                        default_extension( plainfile, "." );
                   3602:                }
                   3603:                else
                   3604:                {       /* Default the plaintext file name */
                   3605:                        strcpy( plainfile, argv[1] );
                   3606:                        force_extension( plainfile, "." );
                   3607:                }
                   3608: 
                   3609:                if (strcmp( plainfile, cipherfile ) == 0)
                   3610:                {       fprintf(stderr, "\aFile '%s' cannot be both input and output file.\n", plainfile );
                   3611:                        goto user_error;                /*      error: same filenames for both files */
                   3612:                }
                   3613: 
                   3614:                if (! file_exists( cipherfile ))
                   3615:                {       fprintf(stderr, "\a\nError: Cipher or signature file '%s' does not exist.\n",
                   3616:                                cipherfile);
                   3617:                        goto user_error;
                   3618:                }
                   3619: 
                   3620:                get_header_info_from_file( cipherfile, header, 4 );
                   3621:                if (!is_ctb(header[0]) && is_uufile(cipherfile))
                   3622:                {       
                   3623:                        if (verbose) fprintf(stderr,"uudecoding %s...",cipherfile);
                   3624:                        status = uud_file(cipherfile, SCRATCH_CTX_FILENAME);
                   3625:                        if (status==0)
                   3626:                        {       if (verbose) fprintf(stderr,"...done.\n");
                   3627:                                remove( cipherfile ); /* dangerous.  sure hope rename works... */
                   3628:                                rename( SCRATCH_CTX_FILENAME, cipherfile );
                   3629:                        }
                   3630:                        else fprintf(stderr,"\n\aError: uudecode failed for file %s\n",cipherfile);
                   3631:                }
                   3632: 
                   3633:                /*---------------------------------------------------------*/
                   3634:                do      /* while nested parsable info present */ 
                   3635:                {
                   3636:                        if (get_header_info_from_file( cipherfile, &ctb, 1) < 0)
                   3637:                        {       fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",cipherfile);
                   3638:                                goto user_error;
                   3639:                        }
                   3640: 
                   3641:                        if (!is_ctb(ctb))       /* not a real CTB -- complain */
                   3642:                                goto reject;
                   3643: 
                   3644:                        /* PKE is Public Key Encryption */
                   3645:                        if (is_ctb_type( ctb, CTB_PKE_TYPE ))
                   3646:                        {
                   3647:                                fprintf(stderr,"\nFile is encrypted.  Secret key is required to read it. ");
                   3648: 
                   3649:                                status = decryptfile( cipherfile, plainfile );
                   3650: 
                   3651:                                if (status < 0) /* error return */
                   3652:                                        goto user_error; 
                   3653:                                if (status < 1) /* output file has no nested info? */
                   3654:                                        break;  /* no nested parsable info.  exit loop. */
                   3655: 
                   3656:                                /* Nested parsable info indicated.  Process it. */
                   3657:                                wipefile( SCRATCH_CTX_FILENAME );
                   3658:                                remove( SCRATCH_CTX_FILENAME );
                   3659:                                rename( plainfile,  SCRATCH_CTX_FILENAME );
                   3660:                                strcpy( cipherfile, SCRATCH_CTX_FILENAME );
                   3661:                                continue;       /* skip rest of loop */
                   3662:                        }       /* outer CTB is PKE type */
                   3663: 
                   3664: 
                   3665:                        if (is_ctb_type( ctb, CTB_SKE_TYPE ))
                   3666:                        {
                   3667:                                fprintf(stderr,"\nFile has signature.  Public key is required to check signature. ");
                   3668: 
                   3669:                                status = check_signaturefile( cipherfile, plainfile );
                   3670: 
                   3671:                                if (status < 0) /* error return */
                   3672:                                        goto user_error;
                   3673: 
                   3674:                                if (status < 1) /* output file has no nested info? */
                   3675:                                        break;  /* no nested parsable info.  exit loop. */
                   3676: 
                   3677:                                /* Nested parsable info indicated.  Process it. */
                   3678:                                /* Destroy signed plaintext, if it's in a scratchfile. */
                   3679:                                wipefile( SCRATCH_CTX_FILENAME );
                   3680:                                remove( SCRATCH_CTX_FILENAME );
                   3681:                                rename( plainfile,  SCRATCH_CTX_FILENAME );
                   3682:                                strcpy( cipherfile, SCRATCH_CTX_FILENAME );
                   3683:                                continue;       /* skip rest of loop */
                   3684:                        }       /* outer CTB is SKE type */
                   3685: 
                   3686: 
                   3687:                        if (ctb == CTB_CKE)
                   3688:                        {       /* Conventional Key Encrypted ciphertext. */
                   3689:                                fprintf(stderr,"\nFile is conventionally encrypted.  Pass phrase required to read it. ");
                   3690:                                status = bass_decryptfile( cipherfile, plainfile );
                   3691:                                if (status < 0) /* error return */
                   3692:                                        goto user_error; 
                   3693:                                if (status < 1) /* output file has no nested info? */
                   3694:                                        break;  /* no nested parsable info.  exit loop. */
                   3695:                                /* Nested parsable info indicated.  Process it. */
                   3696:                                wipefile( SCRATCH_CTX_FILENAME );
                   3697:                                remove( SCRATCH_CTX_FILENAME );
                   3698:                                rename( plainfile,  SCRATCH_CTX_FILENAME );
                   3699:                                strcpy( cipherfile, SCRATCH_CTX_FILENAME );
                   3700:                                continue;       /* skip rest of loop */
                   3701:                        }       /* CTB is CKE type */
                   3702: 
                   3703: 
                   3704:                        if (is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
                   3705:                        {       /* Compressed text. */
                   3706:                                status = decompress_file( cipherfile, plainfile );
                   3707:                                if (status < 0) /* error return */
                   3708:                                        goto user_error;
                   3709:                                /* Always assume nested information... */ 
                   3710:                                /* Destroy compressed plaintext, if it's in a scratchfile. */
                   3711:                                wipefile( SCRATCH_CTX_FILENAME );
                   3712:                                remove( SCRATCH_CTX_FILENAME );
                   3713:                                rename( plainfile,  SCRATCH_CTX_FILENAME );
                   3714:                                strcpy( cipherfile, SCRATCH_CTX_FILENAME );
                   3715:                                continue;       /* skip rest of loop */
                   3716:                        }       /* CTB is COMPRESSED type */
                   3717: 
                   3718: 
                   3719:                        if (is_ctb_type( ctb, CTB_LITERAL_TYPE ))
                   3720:                        {       /* Raw plaintext.  Just copy it.  No more nesting. */
                   3721:                                /* Strip off CTB_LITERAL prefix byte from file: */
                   3722:                                status = strip_literal( cipherfile, plainfile );
                   3723:                                break;  /* no nested parsable info.  exit loop. */
                   3724:                        }       /* CTB is LITERAL type */
                   3725: 
                   3726: 
                   3727:                        if ((ctb == CTB_CERT_SECKEY)
                   3728:                        ||  (ctb == CTB_CERT_PUBKEY))
                   3729:                        {       /* Key ring.  View it. */
                   3730:                                fprintf(stderr, "\nFile contains key(s).  Contents follow..." );
                   3731: 
                   3732:                                if (view_keyring( NULL, cipherfile ) < 0)
                   3733:                                        goto user_error;
                   3734: 
                   3735:                                /*      No output file--what should we do with plainfile?
                   3736:                                        We know that we have already prevented original 
                   3737:                                        cipher filename from being same as plain filename.
                   3738:                                */
                   3739: 
                   3740:                                if (strcmp( cipherfile, SCRATCH_CTX_FILENAME ) == 0)
                   3741:                                {       /* key was nested in signed or enciphered file */
                   3742:                                        remove( plainfile );
                   3743:                                        rename( cipherfile, plainfile );
                   3744:                                }
                   3745:                                exit(0);        /* no nested parsable info. */
                   3746:                                /* strcpy(plainfile,"");        /* no further nesting */
                   3747:                                /* break;       /* no nested parsable info.  exit loop. */
                   3748:                        }       /* key ring.  view it. */
                   3749: 
                   3750: reject:                fprintf(stderr,"\a\nError: '%s' is not a cipher, signature, or key file.\n",
                   3751:                                cipherfile);
                   3752:                        goto user_error;
                   3753: 
                   3754:                }       while (TRUE);
                   3755: 
                   3756:                /* No more nested parsable information */
                   3757: 
                   3758:                /* Destroy any sensitive information in scratchfile: */
                   3759:                wipefile( SCRATCH_CTX_FILENAME );
                   3760:                remove( SCRATCH_CTX_FILENAME );
                   3761: 
                   3762:                if (!verbose)   /* if other filename messages were supressed */
                   3763:                        fprintf(stderr,"\nPlaintext filename: %s ", plainfile);
                   3764: 
                   3765: 
                   3766:                /*---------------------------------------------------------*/
                   3767: 
                   3768:                /*      One last thing-- let's attempt to classify some of the more 
                   3769:                        frequently occurring cases of plaintext output files, as an 
                   3770:                        aid to the user.  
                   3771: 
                   3772:                        For example, if output file is a public key, it should have
                   3773:                        the right extension on the filename.
                   3774: 
                   3775:                        Also, it will likely be common to encrypt PKZIP files, so
                   3776:                        they should be renamed with the .zip extension.
                   3777:                */
                   3778:                get_header_info_from_file( plainfile, header, 4 );
                   3779: 
                   3780:                if (header[0] == CTB_CERT_PUBKEY)
                   3781:                {       /* Special case--may be public key, worth renaming */
                   3782:                        fprintf(stderr, "\nPlaintext file '%s' looks like it contains a public key.",
                   3783:                                plainfile );
                   3784:                        maybe_force_extension( plainfile, PUB_EXTENSION );
                   3785:                }       /* Possible public key output file */
                   3786: 
                   3787:                else
                   3788:                if (pkzipSignature( header ))
                   3789:                {       /*      Special case--may be a PKZIP file, worth renaming       */
                   3790:                        fprintf(stderr, "\nPlaintext file '%s' looks like a PKZIP file.",
                   3791:                                plainfile );
                   3792:                        maybe_force_extension( plainfile, ".zip" );
                   3793:                }       /*      Possible PKZIP output file      */
                   3794: 
                   3795:                else
                   3796:                if ((header[0] == CTB_PKE) 
                   3797:                 || (header[0] == CTB_SKE) 
                   3798:                 || (header[0] == CTB_CKE))
                   3799:                {       /* Special case--may be another ciphertext file, worth renaming */
                   3800:                        fprintf(stderr, "\n\aOutput file '%s' may contain more ciphertext or signature.",
                   3801:                                plainfile );
                   3802:                        maybe_force_extension( plainfile, ".ctx" );
                   3803:                }       /* Possible ciphertext output file */
                   3804: 
                   3805:                exit(0);        /* no nested parsable info. */
                   3806: 
                   3807:        }       /* Decrypt file, or check signature, or show key */
                   3808: 
                   3809: 
                   3810: user_error:    /* comes here if user made a boo-boo. */
                   3811:        fprintf(stderr,"\nFor more help, consult the PGP User's Guide.");
                   3812: 
                   3813: usage:
                   3814:        fprintf(stderr,"\nUsage summary:");
                   3815:        fprintf(stderr,"\nTo encrypt a plaintext file with recipent's public key, type:");
                   3816:        fprintf(stderr,"\n   pgp -e textfile her_userid      (produces textfile.ctx)");
                   3817:        fprintf(stderr,"\nTo sign a plaintext file with your secret key, type:");
                   3818:        fprintf(stderr,"\n   pgp -s textfile your_userid     (produces textfile.ctx)");
                   3819:        fprintf(stderr,"\nTo sign a plaintext file with your secret key, and then encrypt it "
                   3820:                   "\n   with recipent's public key, producing a .ctx file:");
                   3821:        fprintf(stderr,"\n   pgp -es textfile her_userid your_userid");
                   3822:        fprintf(stderr,"\nTo encrypt with conventional encryption only:  pgp -c textfile");
                   3823:        fprintf(stderr,"\nTo decrypt or check a signature for a ciphertext (.ctx) file:");
                   3824:        fprintf(stderr,"\n   pgp ciphertextfile [plaintextfile]");
                   3825:        fprintf(stderr,"\nTo generate your own unique public/secret key pair, type:  pgp -k");
                   3826:        fprintf(stderr,"\nTo add a public or secret key file's contents to your public "
                   3827:                   "\n   or secret key ring:   pgp -a keyfile [keyring]");
                   3828:        fprintf(stderr,"\nTo remove a key from your public key ring:     pgp -r userid [keyring]");
                   3829:        fprintf(stderr,"\nTo view the contents of your public key ring:  pgp -v [userid] [keyring] ");
                   3830:        exit(1);        /* error exit */
                   3831: 
                   3832: }      /* main */
                   3833: 

unix.superglobalmegacorp.com

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