Annotation of pgp/src/pgp.c, revision 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.