home *** CD-ROM | disk | FTP | other *** search
/ Hacker Chronicles 2 / HACKER2.BIN / 1226.PGP.C < prev    next >
C/C++ Source or Header  |  1991-06-04  |  120KB  |  3,834 lines

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