home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 February / PCO_0298.ISO / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / armor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-17  |  37.7 KB  |  1,345 lines

  1. /*      armor.c  - ASCII/binary encoding/decoding based partly on
  2.    PEM RFC1113 and MIME standards.
  3.    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  4.  
  5.    (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
  6.    The author assumes no liability for damages resulting from the use
  7.    of this software, even if the damage results from defects in this
  8.    software.  No warranty is expressed or implied.
  9.  
  10.    Note that while most PGP source modules bear Philip Zimmermann's
  11.    copyright notice, many of them have been revised or entirely written
  12.    by contributors who frequently failed to put their names in their
  13.    code.  Code that has been incorporated into PGP from other authors
  14.    was either originally published in the public domain or is used with
  15.    permission from the various authors.
  16.  
  17.    PGP is available for free to the public under certain restrictions.
  18.    See the PGP User's Guide (included in the release package) for
  19.    important information about licensing, patent restrictions on
  20.    certain algorithms, trademarks, copyrights, and export controls.
  21.  */
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "mpilib.h"
  26. #include "fileio.h"
  27. #include "mpiio.h"
  28. #include "language.h"
  29. #include "pgp.h"
  30. #include "charset.h"
  31. #include "crypto.h"
  32. #include "armor.h"
  33. #include "keymgmt.h"
  34. #ifdef MACTC5
  35. #include "Macutil2.h"
  36. #include "Macutil3.h"
  37. #endif
  38.  
  39. static int darmor_file(char *infile, char *outfile);
  40. static crcword crchware(byte ch, crcword poly, crcword accum);
  41. static int armordecode(FILE * in, FILE * out, int *warned);
  42. static void mk_crctbl(crcword poly);
  43. static boolean is_armorfile(char *infile);
  44.  
  45. /*      Begin ASCII armor routines.
  46.    This converts a binary file into printable ASCII characters, in a
  47.    radix-64 form mostly compatible with the MIME format.
  48.    This makes it easier to send encrypted files over a 7-bit channel.
  49.  */
  50.  
  51. /* Index this array by a 6 bit value to get the character corresponding
  52.  * to that value.
  53.  */
  54. static
  55. unsigned char bintoasc[] =
  56.     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  57.  
  58. /* Index this array by a 7 bit value to get the 6-bit binary field
  59.  * corresponding to that value.  Any illegal characters return high bit set.
  60.  */
  61. static
  62. unsigned char asctobin[] =
  63. {
  64. #ifdef EBCDIC
  65.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  66.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  67.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  68.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  69.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128, 62,128,
  70.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  71.     128, 63,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  72.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  73.     128, 26, 27, 28, 29, 30, 31, 32,  33, 34,128,128,128,128,128,128,
  74.     128, 35, 36, 37, 38, 39, 40, 41,  42, 43,128,128,128,128,128,128,
  75.     128,128, 44, 45, 46, 47, 48, 49,  50, 51,128,128,128,128,128,128,
  76.     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
  77.     128,  0,  1,  2,  3,  4,  5,  6,   7,  8,128,128,128,128,128,128,
  78.     128,  9, 10, 11, 12, 13, 14, 15,  16, 17,128,128,128,128,128,128,
  79.     128,128, 18, 19, 20, 21, 22, 23,  24, 25,128,128,128,128,128,128,
  80.      52, 53, 54, 55, 56, 57, 58, 59,  60, 61,128,128,128,128,128,128
  81. #else
  82.     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
  83.     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
  84.     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
  85.     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
  86.     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
  87.     0200, 0200, 0200, 0076, 0200, 0200, 0200, 0077,
  88.     0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073,
  89.     0074, 0075, 0200, 0200, 0200, 0200, 0200, 0200,
  90.     0200, 0000, 0001, 0002, 0003, 0004, 0005, 0006,
  91.     0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016,
  92.     0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026,
  93.     0027, 0030, 0031, 0200, 0200, 0200, 0200, 0200,
  94.     0200, 0032, 0033, 0034, 0035, 0036, 0037, 0040,
  95.     0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050,
  96.     0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060,
  97.     0061, 0062, 0063, 0200, 0200, 0200, 0200, 0200
  98. #endif
  99. };
  100.  
  101. /* Current line number for mult decodes */
  102. #ifdef MACTC5
  103. long    infile_line;        /* Current line number for mult decodes */
  104. #else
  105. static long infile_line;
  106. #endif
  107.  
  108. /************************************************************************/
  109.  
  110. /* CRC Routines. */
  111. /*      These CRC functions are derived from code in chapter 19 of the book 
  112.  *    "C Programmer's Guide to Serial Communications", by Joe Campbell.
  113.  *      Generalized to any CRC width by Philip Zimmermann.
  114.  */
  115.  
  116. #define byte unsigned char
  117.  
  118. #define CRCBITS 24        /* may be 16, 24, or 32 */
  119. /* #define maskcrc(crc) ((crcword)(crc)) *//* if CRCBITS is 16 or 32 */
  120. #define maskcrc(crc) ((crc) & 0xffffffL)    /* if CRCBITS is 24 */
  121. #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1)))    /* 0x8000 if CRCBITS is 16 */
  122. #define CRCSHIFTS (CRCBITS-8)
  123.  
  124. /*
  125.  * Notes on making a good 24-bit CRC--
  126.  * The primitive irreducible polynomial of degree 23 over GF(2),
  127.  * 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
  128.  * 2nd edition" by Peterson and Weldon, page 490.  This polynomial was
  129.  * chosen for its uniform density of ones and zeros, which has better
  130.  * error detection properties than polynomials with a minimal number of
  131.  * nonzero terms.  Multiplying this primitive degree-23 polynomial by
  132.  * the polynomial x+1 yields the additional property of detecting any
  133.  * odd number of bits in error, which means it adds parity.  This 
  134.  * approach was recommended by Neal Glover.
  135.  *
  136.  * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
  137.  * bitwise add (xor) the unshifted version back in.  Dropping the unused 
  138.  * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 
  139.  * octal, or 0x864cfb hex.  
  140.  *
  141.  * You can detect spurious leading zeros or framing errors in the 
  142.  * message by initializing the CRC accumulator to some agreed-upon 
  143.  * nonzero value, but the value used is a bit nonstandard.  
  144.  */
  145.  
  146. #define CCITTCRC 0x1021        /* CCITT's 16-bit CRC generator polynomial */
  147. #define PRZCRC 0x864cfbL    /* PRZ's 24-bit CRC generator polynomial */
  148. #define CRCINIT 0xB704CEL    /* Init value for CRC accumulator */
  149.  
  150. static crcword crctable[256];    /* Table for speeding up CRC's */
  151.  
  152. /*
  153.  * mk_crctbl derives a CRC lookup table from the CRC polynomial.
  154.  * The table is used later by the crcbytes function given below.
  155.  * mk_crctbl only needs to be called once at the dawn of time.
  156.  *
  157.  * The theory behind mk_crctbl is that table[i] is initialized
  158.  * with the CRC of i, and this is related to the CRC of i>>1,
  159.  * so the CRC of i>>1 (pointed to by p) can be used to derive
  160.  * the CRC of i (pointed to by q).
  161.  */
  162. static void
  163. mk_crctbl(crcword poly)
  164. {
  165.     int i;
  166.     crcword t, *p, *q;
  167.     p = q = crctable;
  168.     *q++ = 0;
  169.     *q++ = poly;
  170.     for (i = 1; i < 128; i++) {
  171.     t = *++p;
  172.     if (t & CRCHIBIT) {
  173.         t <<= 1;
  174.         *q++ = t ^ poly;
  175.         *q++ = t;
  176.     } else {
  177.         t <<= 1;
  178.         *q++ = t;
  179.         *q++ = t ^ poly;
  180.     }
  181.     }
  182. }
  183.  
  184. /*
  185.  * Accumulate a buffer's worth of bytes into a CRC accumulator,
  186.  * returning the new CRC value.
  187.  */
  188. crcword
  189. crcbytes(byte * buf, unsigned len, register crcword accum)
  190. {
  191.     do {
  192.     accum = accum << 8 ^ crctable[(byte) (accum >> CRCSHIFTS) ^ *buf++];
  193.     } while (--len);
  194.     return maskcrc(accum);
  195. }                /* crcbytes */
  196.  
  197. /* Initialize the CRC table using our codes */
  198. void
  199. init_crc(void)
  200. {
  201.     mk_crctbl(PRZCRC);
  202. }
  203.  
  204.  
  205. /************************************************************************/
  206.  
  207.  
  208. /* ENC is the basic 1 character encoding function to make a char printing */
  209. #define ENC(c) ((int)bintoasc[((c) & 077)])
  210. #define PAD        '='
  211.  
  212. /*
  213.  * output one group of up to 3 bytes, pointed at by p, on file f.
  214.  * if fewer than 3 are present, the 1 or two extras must be zeros.
  215.  */
  216. static void
  217. outdec(char *p, FILE *f, int count)
  218. {
  219.     int c1, c2, c3, c4;
  220.  
  221.     c1 = *p >> 2;
  222.     c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
  223.     c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
  224.     c4 = p[2] & 077;
  225.     putc(ENC(c1), f);
  226.     putc(ENC(c2), f);
  227.     if (count == 1) {
  228.     putc(PAD, f);
  229.     putc(PAD, f);
  230.     } else {
  231.     putc(ENC(c3), f);
  232.     if (count == 2)
  233.         putc(PAD, f);
  234.     else
  235.         putc(ENC(c4), f);
  236.     }
  237. }                /* outdec */
  238.  
  239.  
  240. /* Output the CRC value, MSB first per normal CRC conventions */
  241. static void
  242. outcrc(word32 crc, FILE *outFile)
  243. {
  244.     char crcbuf[4];
  245.     crcbuf[0] = (crc >> 16) & 0xff;
  246.     crcbuf[1] = (crc >> 8) & 0xff;
  247.     crcbuf[2] = (crc >> 0) & 0xff;
  248.     putc(PAD, outFile);
  249.     outdec(crcbuf, outFile, 3);
  250.     putc('\n', outFile);
  251. }                /* outcrc */
  252.  
  253. /* Return filename for output (text mode), but replace last letter(s) of
  254.  * filename with the ascii for num.  It will use the appropriate number
  255.  * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
  256.  * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits.  If its
  257.  * >= 1000, then we have other problems to worry about, and this might do
  258.  * weird things.
  259.  */
  260. static char *
  261. numFilename(char *fname, int num, int ofnum)
  262. {
  263.     static char fnamenum[MAX_PATH];
  264.     int len;
  265.     int offset = 1;
  266.  
  267.     strcpy(fnamenum, fname);
  268.     len = strlen(fnamenum);
  269.     do {
  270.     fnamenum[len - offset] = '0' + (num % 10);
  271.     num /= 10;
  272.     ofnum /= 10;
  273.     offset++;
  274.     } while (ofnum >= 1 && offset < 4);
  275.     return fnamenum;
  276. }
  277.  
  278. /*
  279.  * Reads and discards a line from the given file.  Returns -1 on error or
  280.  * EOF, 0 if the line is blank, and 1 if the line is not blank.
  281.  */
  282. static int
  283. skipline(FILE * f)
  284. {
  285.     int state, flag, c;
  286.  
  287.     state = 0;
  288.     flag = 0;
  289.     for (;;) {
  290.     c = getc(f);
  291.     if (c == '\n')
  292.         return flag;
  293.     if (state) {
  294.         ungetc(c, f);
  295.         return flag;
  296.     }
  297.     if (c == EOF)
  298.         return -1;
  299.     if (c == '\r')
  300.         state = 1;
  301.     else if (c != ' ')
  302.         flag = 1;
  303.     }
  304. }                /* skipline */
  305.  
  306.  
  307. /*
  308.  * Copies a line from the input file to the output.  Does NOT copy the
  309.  * trailing newline.  Returns -1 on EOF or error, 0 if the line was terminated
  310.  * by EOF, and 1 if the line was terminated with a newline sequence.
  311.  */
  312. static int
  313. copyline(FILE * in, FILE * out)
  314. {
  315.     int state, flag, c;
  316.  
  317.     state = 0;
  318.     for (;;) {
  319.     c = getc(in);
  320.     if (c == '\n')
  321.         return 1;
  322.     if (state) {
  323.         ungetc(c, in);
  324.         return 1;
  325.     }
  326.     if (c == EOF)
  327.         return 0;
  328.     if (c == '\r')
  329.         state = 1;
  330.     else
  331.         putc(c, out);
  332.     }
  333. }                /* copyline */
  334.  
  335. /*
  336.  * Reads a line from file f, up to the size of the buffer.  The line in the
  337.  * buffer will NOT include line termination, although any of (CR, LF, CRLF)
  338.  * is accepted on input.  The return value is -1 on error, 0 if the line
  339.  * was terminated abnormally (EOF, error, or out of buffer space), and
  340.  * 1 if the line was terminated normally.
  341.  *
  342.  * Passing in a buffer less than 2 characters long is not a terribly bright
  343.  * idea.
  344.  */
  345. static int
  346. getline(char *buf, int n, FILE * f)
  347. {
  348.     int state;
  349.     char *p;
  350.     int c;
  351.  
  352.     state = 0;
  353.     p = buf;
  354.     for (;;) {
  355.     c = getc(f);
  356.     if (c == '\n') {
  357.         *p = 0;
  358.         return 1;        /* Line terminated with \n or \r\n */
  359.     }
  360.     if (state) {
  361.         ungetc(c, f);
  362.         *p = 0;
  363.         return 1;        /* Line terminated with \r */
  364.     }
  365.     if (c == EOF) {
  366.         *p = 0;
  367.         return (p == buf) ? -1 : 0;        /* Error */
  368.     }
  369.     if (c == '\r')
  370.         state = 1;
  371.     else if (--n > 0) {
  372.         *p++ = c;
  373.     } else {
  374.         ungetc(c, f);
  375.         *p = 0;
  376.         return 0;        /* Out of buffer space */
  377.     }
  378.     }                /* for (;;) */
  379. }                /* getline */
  380.  
  381. #if 1
  382. /* This limit is advisory only; longer lines are handled properly.
  383.  * The only requirement is that this be at least as long as the longest
  384.  * delimiter string used by PGP
  385.  * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
  386.  */
  387. #define MAX_LINE_SIZE 80
  388. #else
  389. #ifdef MSDOS            /* limited stack space */
  390. #define MAX_LINE_SIZE    256
  391. #else
  392. #define MAX_LINE_SIZE    1024
  393. #endif
  394. #endif
  395.  
  396. /*
  397.  * Read a line from file f, buf must be able to hold at least MAX_LINE_SIZE
  398.  * characters.  Anything after that is ignored.  Strips trailing spaces and
  399.  * line terminator, can read LF, CRLF and CR textfiles.  It can't be ASCII
  400.  * armor anyway.
  401.  */
  402. static char *
  403. get_armor_line(char *buf, FILE * f)
  404. {
  405.     int c, n = MAX_LINE_SIZE-1;
  406.     char *p = buf;
  407.  
  408.     do {
  409.     c = getc(f);
  410.     if (c == '\n' || c == '\r' || c == EOF)
  411.         break;
  412.     *p++ = c;
  413.     } while (--n > 0);
  414.     if (p == buf && c == EOF) {
  415.     *buf = '\0';
  416.     return NULL;
  417.     }
  418.     /*
  419.      * Skip to end of line, setting n to non-zero if anything trailing is
  420.      * not a space (meaning that any trailing whitespace in the buffer is
  421.      * not trailing whitespace on the line and should not be stripped).
  422.      */
  423.     n = 0;
  424.     while (c != '\n' && c != '\r' && c != EOF) {
  425.         n |= c ^ ' ';
  426.     c = getc(f);
  427.     }
  428.     if (c == '\r' && (c = getc(f)) != '\n')
  429.     ungetc(c, f);
  430.     if (!n) {    /* Skip trailing whitespace, as described above */
  431.     while (p > buf && p[-1] == ' ')
  432.         --p;
  433.     }
  434.     *p = '\0';
  435.     return buf;
  436. }
  437.  
  438.  
  439. /*
  440.  * Encode a file in sections.  64 ASCII bytes * 720 lines = 46K, 
  441.  * recommended max.  Usenet message size is 50K so this leaves a nice 
  442.  * margin for .signature.  In the interests of orthogonality and 
  443.  * programmer laziness no check is made for a message containing only 
  444.  * a few lines (or even just an 'end')  after a section break. 
  445.  */
  446. #define LINE_LEN    48L
  447. int pem_lines = 720;
  448. #define BYTES_PER_SECTION    (LINE_LEN * pem_lines)
  449.  
  450. #if defined(VMS) || defined(C370)
  451. #define FOPRARMOR    FOPRTXT
  452. #else
  453. /* armored files are opened in binary mode so that CRLF/LF/CR files
  454.    can be handled by all systems */
  455. #define    FOPRARMOR    FOPRBIN
  456. #endif
  457.  
  458. extern boolean verbose;        /* Undocumented command mode in PGP.C */
  459. extern boolean filter_mode;
  460.  
  461. /*
  462.  * Copy from infilename to outfilename, ASCII armoring as you go along,
  463.  * and with breaks every pem_lines lines.
  464.  * If clearfilename is non-NULL, first output that file preceded by a
  465.  * special delimiter line.  filename is the original filename, used
  466.  * only for debugging.
  467.  */
  468. int
  469. armor_file(char *infilename, char *outfilename, char *filename,
  470.     char *clearfilename, boolean kv_label)
  471. {
  472.     char buffer[MAX_LINE_SIZE];
  473.     int i, rc, bytesRead, lines = 0;
  474.     int noSections, currentSection = 1;
  475.     long fileLen;
  476.     crcword crc;
  477.     FILE *inFile, *outFile, *clearFile;
  478.     char *tempf;
  479.     char *blocktype = "MESSAGE";
  480. #ifdef MACTC5
  481.     char curOutFile[256]="";
  482. #endif
  483.  
  484.     if (verbose)
  485.     fprintf(pgpout,
  486. "armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
  487.         infilename, outfilename, filename,
  488.         clearfilename == NULL ? "" : clearfilename);
  489.  
  490.     /* open input file as binary */
  491.     if ((inFile = fopen(infilename, FOPRBIN)) == NULL)
  492.     return 1;
  493.  
  494.     if (!outfilename || pem_lines == 0) {
  495.     noSections = 1;
  496.     } else {
  497.     /* Evaluate how many parts this file will comprise */
  498.     fseek(inFile, 0L, SEEK_END);
  499.     fileLen = ftell(inFile);
  500.     rewind(inFile);
  501.     noSections = (fileLen + BYTES_PER_SECTION - 1) /
  502.         BYTES_PER_SECTION;
  503.     if (noSections > 99) {
  504.         pem_lines = ((fileLen + LINE_LEN - 1) / LINE_LEN + 98) / 99;
  505.         noSections = (fileLen + BYTES_PER_SECTION - 1) /
  506.         BYTES_PER_SECTION;
  507.         fprintf(pgpout,
  508.         "value for \"armorlines\" is too low, using %d\n", pem_lines);
  509.     }
  510.     }
  511.  
  512.     if (clearfilename)
  513.       tempf = tempfile(TMP_WIPE);
  514.     else
  515.       tempf = outfilename;
  516.  
  517.     if (outfilename == NULL) {
  518.     outFile = stdout;
  519.     } else {
  520.     if (noSections > 1) {
  521.             do {
  522.                 char *t;
  523.                 force_extension(outfilename, ASC_EXTENSION);
  524.                 strcpy(outfilename, numFilename(outfilename, 1, noSections));
  525.                 if (!file_exists(outfilename)) break;
  526.                 t = ck_dup_output(outfilename, TRUE, TRUE);
  527.                 if (t==NULL) user_error();
  528.                 strcpy(outfilename,t);
  529.             } while (TRUE);
  530.             outFile = fopen(tempf, FOPWTXT);
  531.     } else
  532.         outFile = fopen(tempf, FOPWTXT);
  533. #ifdef MACTC5
  534.         strcpy(curOutFile,outfilename);
  535. #endif
  536.     }
  537.  
  538.     if (outFile == NULL) {
  539.     fclose(inFile);
  540.     return 1;
  541.     }
  542.     if (clearfilename) {
  543.     if ((clearFile = fopen(clearfilename, FOPRTXT)) == NULL) {
  544.         fclose(inFile);
  545.         if (outFile != stdout)
  546.         fclose(outFile);
  547.         return 1;
  548.     }
  549.     fprintf(outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
  550.     while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0) {
  551.         /* Quote lines beginning with '-' as per RFC1113;
  552.          * Also quote lines beginning with "From "; this is
  553.          * for Unix mailers which add ">" to such lines.
  554.          */
  555.         if (buffer[0] == '-' || strncmp(buffer, "From ", 5) == 0)
  556.         fputs("- ", outFile);
  557.         fputs(buffer, outFile);
  558.         /* If there is more on this line, copy it */
  559.         if (i == 0)
  560.         if (copyline(clearFile, outFile) <= 0)
  561.             break;
  562.         fputc('\n', outFile);
  563.     }
  564.     fclose(clearFile);
  565.     putc('\n', outFile);
  566.     blocktype = "SIGNATURE";
  567.     }
  568.     if (noSections == 1) {
  569.     byte ctb = 0;
  570.         int keycounter = 0;
  571.         int status;
  572.     ctb = getc(inFile);
  573.     if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) {
  574.         blocktype = "PUBLIC KEY BLOCK";
  575.             if (kv_label) {
  576.                 kv_title(outFile);     /* Title line */
  577.                 rewind(inFile);        /* Back over CTB */
  578.                 status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename,
  579.                                             FALSE, FALSE, &keycounter);
  580.             fprintf(outFile, "\n");
  581.             }
  582.     } else if (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
  583.             blocktype = "SECRET KEY BLOCK";
  584.             if (kv_label) {
  585.                 kv_title(outFile);     /* Title line */
  586.                 rewind(inFile);        /* Back over CTB */
  587.                 status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename,
  588.                                             FALSE, FALSE, &keycounter);
  589.             fprintf(outFile, "\n");
  590.             }
  591.     }
  592.     fprintf(outFile, "-----BEGIN PGP %s-----\n", blocktype);
  593.     rewind(inFile);
  594.     } else {
  595.     fprintf(outFile,
  596.         "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
  597.         1, noSections);
  598.     }
  599.     fprintf(outFile, "Version: %s\n", LANG(rel_version));
  600.     if (clearfilename)
  601.     fprintf(outFile, "Charset: %s\n", charset);
  602.     if (globalCommentString[0])
  603.     fprintf(outFile, "Comment: %s\n", globalCommentString);
  604.     fprintf(outFile, "\n");
  605.  
  606.     init_crc();
  607.     crc = CRCINIT;
  608.  
  609.     while ((bytesRead = fread(buffer, 1, LINE_LEN, inFile)) > 0) {
  610.     /* Munge up LINE_LEN characters */
  611.     if (bytesRead < LINE_LEN)
  612.         fill0(buffer + bytesRead, LINE_LEN - bytesRead);
  613.  
  614.     crc = crcbytes((byte *) buffer, bytesRead, crc);
  615.     for (i = 0; i < bytesRead - 3; i += 3)
  616.         outdec(buffer + i, outFile, 3);
  617.     outdec(buffer + i, outFile, bytesRead - i);
  618.     putc('\n', outFile);
  619. #ifdef MACTC5
  620.         mac_poll_for_break();
  621. #endif
  622.  
  623.     if (++lines == pem_lines && currentSection < noSections) {
  624.         lines = 0;
  625.         outcrc(crc, outFile);
  626.         fprintf(outFile,
  627.             "-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
  628.             currentSection, noSections);
  629.         if (write_error(outFile)) {
  630.         fclose(outFile);
  631.         return -1;
  632.          }
  633.         fclose(outFile);
  634. #ifdef MACTC5
  635.         PGPSetFinfo(curOutFile,'TEXT','MPGP');
  636. #endif
  637.         outFile = fopen(numFilename(outfilename,
  638.                     ++currentSection,
  639.                     noSections), FOPWTXT);
  640. #ifdef MACTC5
  641.         strcpy(curOutFile,numFilename (outfilename,currentSection,noSections));
  642. #endif
  643.         if (outFile == NULL) {
  644.         fclose(inFile);
  645.         return -1;
  646.         }
  647.         fprintf(outFile,
  648.             "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
  649.             currentSection, noSections);
  650.         fprintf(outFile, "\n");
  651.         crc = CRCINIT;
  652.     }
  653.     }
  654.     outcrc(crc, outFile);
  655.  
  656.     if (noSections == 1)
  657.     fprintf(outFile, "-----END PGP %s-----\n", blocktype);
  658.     else
  659.     fprintf(outFile, "-----END PGP MESSAGE, PART %02d/%02d-----\n",
  660.         noSections, noSections);
  661.  
  662.     /* Done */
  663.     fclose(inFile);
  664.     rc = write_error(outFile);
  665.     if (outFile == stdout)
  666.     return rc;
  667. #ifdef MACTC5
  668.     PGPSetFinfo(curOutFile,'TEXT','MPGP');
  669. #endif
  670.     fclose(outFile);
  671.     if (clearfilename) {
  672.         remove(outfilename);
  673.         savetemp(tempf,outfilename);
  674.     }
  675.  
  676.     if (rc)
  677.     return -1;
  678.  
  679.     if (clearfilename) {
  680.     fprintf(pgpout,
  681.         LANG("\nClear signature file: %s\n"), outfilename);
  682.     } else if (noSections == 1) {
  683.     fprintf(pgpout,
  684.         LANG("\nTransport armor file: %s\n"), outfilename);
  685.     } else {
  686.     fprintf(pgpout, LANG("\nTransport armor files: "));
  687.     for (i = 1; i <= noSections; ++i)
  688.         fprintf(pgpout, "%s%s",
  689.             numFilename(outfilename, i, noSections),
  690.             i == noSections ? "\n" : ", ");
  691.     }
  692.     return 0;
  693. }                /* armor_file */
  694.  
  695. /*      End ASCII armor encode routines. */
  696.  
  697.  
  698. /*
  699.  * ASCII armor decode routines.
  700.  */
  701. static int
  702. darmor_buffer(char *inbuf, char *outbuf, int *outlength)
  703. {
  704.     unsigned char *bp;
  705.     int length;
  706.     unsigned int c1, c2, c3, c4;
  707.     register int j;
  708.  
  709.     length = 0;
  710.     bp = (unsigned char *) inbuf;
  711.  
  712.     /* FOUR input characters go into each THREE output charcters */
  713.  
  714.     while (*bp != '\0') {
  715. #ifdef EBCDIC
  716.     if ((c1 = asctobin[*bp]) & 0x80)
  717.         return -1;
  718.     ++bp;
  719.     if ((c2 = asctobin[*bp]) & 0x80)
  720.         return -1;
  721. #else
  722.     if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80)
  723.         return -1;
  724.     ++bp;
  725.     if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80)
  726.         return -1;
  727. #endif
  728.     if (*++bp == PAD) {
  729.         c3 = c4 = 0;
  730.         length += 1;
  731.         if (c2 & 15)
  732.         return -1;
  733.         if (strcmp((char *) bp, "==") == 0)
  734.         bp += 1;
  735.         else if (strcmp((char *) bp, "=3D=3D") == 0)
  736.         bp += 5;
  737.         else
  738.         return -1;
  739. #ifdef EBCDIC
  740.     } else if ((c3 = asctobin[*bp]) & 0x80) {
  741. #else
  742.     } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
  743. #endif
  744.         return -1;
  745.     } else {
  746.         if (*++bp == PAD) {
  747.         c4 = 0;
  748.         length += 2;
  749.         if (c3 & 3)
  750.             return -1;
  751.         if (strcmp((char *) bp, "=") == 0);    /* All is well */
  752.         else if (strcmp((char *) bp, "=3D") == 0)
  753.             bp += 2;
  754.         else
  755.             return -1;
  756. #ifdef EBCDIC
  757.         } else if ((c4 = asctobin[*bp]) & 0x80) {
  758. #else
  759.         } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
  760. #endif
  761.         return -1;
  762.         } else {
  763.         length += 3;
  764.         }
  765.     }
  766.     ++bp;
  767.     j = (c1 << 2) | (c2 >> 4);
  768.     *outbuf++ = j;
  769.     j = (c2 << 4) | (c3 >> 2);
  770.     *outbuf++ = j;
  771.     j = (c3 << 6) | c4;
  772.     *outbuf++ = j;
  773.     }
  774.  
  775.     *outlength = length;
  776.     return 0;            /* normal return */
  777.  
  778. }                /* darmor_buffer */
  779.  
  780. static char armorfilename[MAX_PATH];
  781. /*
  782.  * try to open the next file of a multi-part armored file
  783.  * the sequence number is expected at the end of the file name
  784.  */
  785. static FILE *
  786. open_next(void)
  787. {
  788.     char *p, *s, c;
  789.     FILE *fp;
  790.  
  791.     p = armorfilename + strlen(armorfilename);
  792.     while (--p >= armorfilename && isdigit(*p)) {
  793.     if (*p != '9') {
  794.         ++*p;
  795.         return fopen(armorfilename, FOPRARMOR);
  796.     }
  797.     *p = '0';
  798.     }
  799.  
  800.     /* need an extra digit */
  801.     if (p >= armorfilename) {
  802.     /* try replacing character ( .as0 -> .a10 ) */
  803.     c = *p;
  804.     *p = '1';
  805.     if ((fp = fopen(armorfilename, FOPRARMOR)) != NULL)
  806.         return fp;
  807.     *p = c;            /* restore original character */
  808.     }
  809.     ++p;
  810.     for (s = p + strlen(p); s >= p; --s)
  811.     s[1] = *s;
  812.     *p = '1';            /* insert digit ( fn0 -> fn10 ) */
  813.  
  814. #if defined(MSDOS) && !defined(BUG)
  815.     /* if the resulting filename has more than three
  816.        characters after the first dot, don't even try to open it */
  817.     s = strchr(armorfilename, '.');
  818.     if (s != NULL)
  819.        if (strlen(s) > 3)
  820.           return NULL;
  821. #endif /* MSDOS */
  822.  
  823.     return fopen(armorfilename, FOPRARMOR);
  824. }
  825.  
  826. /*
  827.  * Returns -1 if the line given is does not begin as a valid ASCII
  828.  * armor header line (something of the form "Label: ", where "Label"
  829.  * must begin with a letter followed by letters, numbers, or hyphens,
  830.  * followed immediately by a colon and a space), 0 if it is a familiar
  831.  * label, and the length of the label if it is an unfamiliar label
  832.  * (E.g. not "Version" or "Comment");
  833.  */
  834. static int
  835. isheaderline(char const *buf)
  836. {
  837.     int i;
  838.  
  839.     if (!isalpha(*buf))
  840.         return -1;    /* Not a label */
  841.  
  842.     for (i = 1; isalnum(buf[i]) || i == '-'; i++)
  843.         ;
  844.     if (buf[i] != ':' || buf[i+1] != ' ')
  845.         return -1;    /* Not a label */
  846.  
  847.     if (memcmp(buf, "Charset", i) == 0) {
  848.         if (use_charset_header) strcpy(charset_header,buf+9);
  849.         return 0;
  850.     }
  851.     if (memcmp(buf, "Version", i) == 0 ||
  852.         memcmp(buf, "Comment", i) == 0)
  853.         return 0;    /* Familiar label */
  854.     return i;    /* Unfamiliar label */
  855. }
  856.  
  857. /* 
  858.  * Skips a bunch of headers, either returning 0, or printing
  859.  * an error message and returning -1.
  860.  * If it encounters an unfamiliar label and *warned is not set,
  861.  * prints a warning and sets *warned.
  862.  * NOTE that file read errors are NOT printed or reported in the
  863.  * return code.  It is assumed that the following read will
  864.  * notice the error and do something appropriate.
  865.  */
  866. static int
  867. skipheaders(FILE *in, char *buf, int *warned, int armorfollows)
  868. {
  869.     int label_seen = 0;
  870.     int i;
  871. #ifndef STRICT_ARMOR    /* Allow no space */
  872.     long fpos;
  873.     char outbuf[(MAX_LINE_SIZE*3+3)/4];
  874.     int n;
  875. #endif
  876.  
  877.     for (;;) {
  878.     ++infile_line;
  879. #ifndef STRICT_ARMOR
  880.     fpos = ftell(in);
  881. #endif
  882.     if (get_armor_line(buf, in) == NULL)    /* Error */
  883.         return 0;    /* See comment above */
  884.     if (buf[0] == '\0')    /* Blank line */
  885.         return 0;    /* Success */
  886.     if (label_seen && (buf[0] == ' ' || buf[0] == '\t'))
  887.         continue;    /* RFC-822-style continuation line */
  888.     i = isheaderline(buf);
  889.     if (i < 0) {    /* Not a legal header line */
  890. #ifndef STRICT_ARMOR    /* If it's as ASCII armor line, accept it */
  891.         if (armorfollows && darmor_buffer(buf, outbuf, &n) == 0 && n == 48)
  892.         {
  893.         fseek(in, fpos, SEEK_SET);
  894.         --infile_line;
  895.         return 0;    /* Consider this acceptable */
  896.         }
  897. #else
  898.         (void)armorfollows;    /* Stop compiler complaints */
  899. #endif
  900.         fprintf(pgpout,
  901. LANG("Invalid ASCII armor header line: \"%.40s\"\n\
  902. ASCII armor corrupted.\n"), buf);
  903.         return -1;
  904.     }
  905.     if (i > 0 && !*warned) {
  906.         fprintf(pgpout,
  907. LANG("Warning: Unrecognized ASCII armor header label \"%.*s:\" ignored.\n"),
  908.                 i, buf);
  909.         *warned = 1;
  910.     }
  911.     label_seen = 1;    /* Continuation lines are now legal */
  912.     }
  913. }
  914.  
  915. /*
  916.  * Copy from in to out, decoding as you go, with handling for multiple
  917.  * 500-line blocks of encoded data.  This function also knows how to
  918.  * go past the end of one part to the beginning of the next in a multi-part
  919.  * file.  (As you can see from some ugliness below, this is not the best
  920.  * place to do it, since the caller is responsible for closing the
  921.  * "original_in" file.)
  922.  */
  923. static int
  924. armordecode(FILE *original_in, FILE *out, int *warned)
  925. {
  926.     char inbuf[MAX_LINE_SIZE];
  927.     char outbuf[MAX_LINE_SIZE];
  928.  
  929.     int i, n, status;
  930.     int line;
  931.     int section, currentSection = 1;
  932.     int noSections = 0;
  933.     int gotcrc = 0;
  934.     long crc = CRCINIT, chkcrc = -1;
  935.     char crcbuf[4];
  936.     int ret_code = 0;
  937.     int end_of_message;
  938.     FILE *in = original_in;
  939.  
  940.     init_crc();
  941.  
  942.     for (line = 1;; line++) {    /* for each input line */
  943.     if (get_armor_line(inbuf, in) == NULL) {
  944.         end_of_message = 1;
  945.     } else {
  946.         end_of_message =
  947.         (strncmp(inbuf, "-----END PGP MESSAGE,", 21) == 0);
  948.         ++infile_line;
  949.     }
  950.  
  951.     if (currentSection != noSections && end_of_message) {
  952.         /* End of this section */
  953.         if (gotcrc) {
  954.         if (chkcrc != crc) {
  955.             fprintf(pgpout,
  956.  LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
  957. /* continue with decoding to see if there are other bad parts */
  958.             ret_code = -1;
  959.         }
  960.         }
  961.         gotcrc = 0;
  962.         crc = CRCINIT;
  963.         section = 0;
  964.  
  965.         /* Try and find start of next section */
  966.         do {
  967.         if (get_armor_line(inbuf, in) == NULL) {
  968.             if (in != original_in)
  969.             fclose(in);
  970.             if ((in = open_next()) != NULL)
  971.             continue;    /* Keep working on new in */
  972.             fprintf(pgpout,
  973.             LANG("Can't find section %d.\n"), currentSection + 1);
  974.             return -1;
  975.         }
  976.         ++infile_line;
  977.         }
  978.         while (strncmp(inbuf, "-----BEGIN PGP MESSAGE", 22));
  979.  
  980.         /* Make sure this section is the correct one */
  981.         if (2 != sscanf(inbuf,
  982.                 "-----BEGIN PGP MESSAGE, PART %d/%d",
  983.                 §ion, &noSections)) {
  984.         fprintf(pgpout,
  985.             LANG("Badly formed section delimiter, part %d.\n"),
  986.             currentSection + 1);
  987.         goto error;
  988.         }
  989.         if (section != ++currentSection) {
  990.         fprintf(pgpout,
  991. LANG("Sections out of order, expected part %d"), currentSection);
  992.         if (section)
  993.             fprintf(pgpout,
  994.                 LANG(", got part %d\n"), section);
  995.         else
  996.             fputc('\n', pgpout);
  997.         goto error;
  998.         }
  999.         /* Skip header after BEGIN line */
  1000.         if (skipheaders(in, inbuf, warned, 1) < 0)
  1001.         goto error;
  1002.         if (feof(in)) {
  1003.         fprintf(pgpout,
  1004.            LANG("ERROR: Hit EOF in header of section %d.\n"),
  1005.             currentSection);
  1006.         goto error;
  1007.         }
  1008.         
  1009.         /* Continue decoding */
  1010.         continue;
  1011.     }
  1012. #ifdef MACTC5
  1013.     mac_poll_for_break();
  1014. #endif
  1015.  
  1016. /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
  1017.  * or handle checksum
  1018.  */
  1019.     if (inbuf[0] == PAD) {    /* Checksum lines start
  1020.                    with PAD char */
  1021.         /* If the already-armored file is sent through MIME
  1022.          * and gets armored again, '=' will become '=3D'.
  1023.          * To make life easier, we detect and work around this
  1024.          * idiosyncracy.
  1025.          */
  1026.         if (strlen(inbuf) == 7 &&
  1027.         inbuf[1] == '3' && inbuf[2] == 'D')
  1028.         status = darmor_buffer(inbuf + 3, crcbuf, &n);
  1029.         else
  1030.         status = darmor_buffer(inbuf + 1, crcbuf, &n);
  1031.         if (status < 0 || n != 3) {
  1032.         fprintf(pgpout,
  1033. LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"), line);
  1034.                 goto error;
  1035.         }
  1036.         chkcrc = (((long) crcbuf[0] << 16) & 0xff0000L) +
  1037.         ((crcbuf[1] << 8) & 0xff00L) + (crcbuf[2] & 0xffL);
  1038.         gotcrc = 1;
  1039.         continue;
  1040.     }
  1041.     if (inbuf[0] == '\0') {
  1042.         fprintf(pgpout,
  1043.             LANG("WARNING: No ASCII armor `END' line.\n"));
  1044.         break;
  1045.     }
  1046.     if (strncmp(inbuf, "-----END PGP ", 13) == 0)
  1047.         break;
  1048.  
  1049.     status = darmor_buffer(inbuf, outbuf, &n);
  1050.  
  1051.     if (status == -1) {
  1052.         fprintf(pgpout,
  1053.          LANG("ERROR: Bad ASCII armor character, line %d.\n"), line);
  1054.         gotcrc = 1;        /* this will print part number,
  1055.                    continue with next part */
  1056.         ret_code = -1;
  1057.     }
  1058.     if (n > sizeof outbuf) {
  1059.         fprintf(pgpout,
  1060.          LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"),
  1061.             n, line);
  1062.         goto error;
  1063.     }
  1064.     crc = crcbytes((byte *) outbuf, n, crc);
  1065.     if (fwrite(outbuf, 1, n, out) != n) {
  1066.         ret_code = -1;
  1067.         break;
  1068.     }
  1069.     }                /* line */
  1070.  
  1071.     if (gotcrc) {
  1072.     if (chkcrc != crc) {
  1073.         fprintf(pgpout,
  1074.             LANG("ERROR: Bad ASCII armor checksum"));
  1075.         if (noSections > 0)
  1076.         fprintf(pgpout,
  1077.             LANG(" in section %d"), noSections);
  1078.         fputc('\n', pgpout);
  1079.         goto error;
  1080.     }
  1081.     } else {
  1082.     fprintf(pgpout,
  1083.         LANG("Warning: Transport armor lacks a checksum.\n"));
  1084.     }
  1085.  
  1086.     if (in != original_in)
  1087.     fclose(in);
  1088.     return ret_code;        /* normal return */
  1089. error:
  1090.     if (in != original_in)
  1091.     fclose(in);
  1092.     return -1;            /* error return */
  1093. }                /* armordecode */
  1094.  
  1095. static boolean
  1096. is_armorfile(char *infile)
  1097. {
  1098.     FILE *in;
  1099.     char inbuf[MAX_LINE_SIZE];
  1100.     char outbuf[MAX_LINE_SIZE];
  1101.     int n;
  1102.     long il;
  1103.  
  1104.     in = fopen(infile, FOPRARMOR);
  1105.     if (in == NULL)
  1106.     return FALSE;    /* can't open file */
  1107.    
  1108.     /* Read to infile_line before we begin looking */
  1109.     for (il = 0; il < infile_line; ++il) {
  1110.     if (get_armor_line(inbuf, in) == NULL) {
  1111.         fclose(in);
  1112.         return FALSE;
  1113.     }
  1114.     }
  1115.  
  1116.     /* search file for delimiter line */
  1117.     for (;;) {
  1118.     if (get_armor_line(inbuf, in) == NULL)
  1119.         break;
  1120.     if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) {
  1121.         if (strncmp(inbuf,
  1122.             "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
  1123.         fclose(in);
  1124.         return TRUE;
  1125.         }
  1126.         n = 1;    /* Don't print warnings yet */
  1127.         if (skipheaders(in, inbuf, &n, 1) < 0 ||
  1128.             get_armor_line(inbuf, in) == NULL ||
  1129.             darmor_buffer(inbuf, outbuf, &n) < 0)
  1130.         break;
  1131.         fclose(in);
  1132.         return TRUE;
  1133.     }
  1134.     }
  1135.  
  1136.     fclose(in);
  1137.     return FALSE;
  1138. }                /* is_armorfile */
  1139.  
  1140. static int
  1141. darmor_file(char *infile, char *outfile)
  1142. {
  1143.     FILE *in, *out;
  1144.     char buf[MAX_LINE_SIZE];
  1145.     char outbuf[(MAX_LINE_SIZE*3+3)/4];
  1146.     int status, n;
  1147.     long il, fpos;
  1148.     char *litfile = NULL;
  1149.     int header_warned = 0;    /* Complained about unknown header */
  1150.  
  1151.     if ((in = fopen(infile, FOPRARMOR)) == NULL) {
  1152.     fprintf(pgpout, LANG("ERROR: Can't find file %s\n"), infile);
  1153.     return 10;
  1154.     }
  1155.     strcpy(armorfilename, infile);    /* store filename for multi-parts */
  1156.  
  1157.     /* Skip to infile_line */
  1158.     for (il = 0; il < infile_line; ++il) {
  1159.     if (get_armor_line(buf, in) == NULL) {
  1160.         fclose(in);
  1161.         return -1;
  1162.     }
  1163.     }
  1164.  
  1165.     /* Loop through file, searching for delimiter.  Decode anything with a
  1166.        delimiter, complain if there were no delimiter. */
  1167.  
  1168.     /* search file for delimiter line */
  1169.     for (;;) {
  1170.     ++infile_line;
  1171.     if (get_armor_line(buf, in) == NULL) {
  1172.         fprintf(pgpout,
  1173.             LANG("ERROR: No ASCII armor `BEGIN' line!\n"));
  1174.         fclose(in);
  1175.         return 12;
  1176.     }
  1177.     if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
  1178.         break;
  1179.     }
  1180.     if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
  1181.     FILE *litout;
  1182.     char *p;
  1183.     int nline;
  1184.  
  1185.     /*
  1186.      * It would be nice to allow headers here, as we could add
  1187.      * additional information to PGP messages, but it appears to
  1188.      * be too easy to spoof, given standard text viewers.  So,
  1189.      * forbid it outright until we sit down and figure out how to
  1190.      * thwart all the ways of faking an end-of-headers.  The
  1191.      * possibilities are:
  1192.      * - Enough trailing whitespace on a valid-looking line to force a
  1193.      *   line wrap.  The 80 column case is tricky, as the classical
  1194.      *   Big Iron IBM mainframe pads to 80 columns, and some terminal
  1195.      *   and text viewer combinations cause a blank line, while others
  1196.      *   don't.  A line that is exactly 80 columns wide but ends in
  1197.      *   a non-blank would do, too.
  1198.      * - A big pile of whitespace within a line, enough to 
  1199.      *   produce something that looks like a blank line between
  1200.      *   the beginning and end parts.
  1201.      * - Various cursor-control sequences.
  1202.      * Basically, it's a nasty problem.  A very strong case can be made
  1203.      * for the argument that it's the text viewer's problem, and outside
  1204.      * PGP's jurisdiction, but that has a few conflicts with reality.
  1205.      */
  1206.     charset_header[0] = '\0';
  1207.     if (get_armor_line(buf, in) == NULL) {
  1208.         fprintf(pgpout,
  1209. LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
  1210.         fclose(in);
  1211.         return 12;
  1212.     }
  1213.     if (buf[0] != '\0') {
  1214.         fprintf(pgpout,
  1215. LANG("ERROR: Header line added to ASCII armor: \"%s\"\n\
  1216. ASCII armor corrupted.\n"), buf);
  1217.         fclose(in);
  1218.         return -1;
  1219.         
  1220.     }
  1221.         
  1222.     litfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  1223.     if ((litout = fopen(litfile, FOPWTXT)) == NULL) {
  1224.         fprintf(pgpout,
  1225. LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
  1226.         fclose(in);
  1227.         return -1;
  1228.     }
  1229.  
  1230.     status = 0;
  1231.     for (;;) {
  1232.         ++infile_line;
  1233.         nline = status;
  1234.         status = getline(buf, sizeof buf, in);
  1235.         if (status < 0) {
  1236.         fprintf(pgpout,
  1237. LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
  1238.         fclose(in);
  1239.         fclose(litout);
  1240.         rmtemp(litfile);
  1241.         return 12;
  1242.         }
  1243.         if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
  1244.         break;
  1245.         if (nline)
  1246.         putc('\n', litout);
  1247.         /* De-quote lines starting with '- ' */
  1248.         fputs(buf + ((buf[0] == '-' && buf[1] == ' ') ? 2 : 0), litout);
  1249.         /* Copy trailing part of line, if any. */
  1250.         if (!status)
  1251.         status = copyline(in, litout);
  1252.         /* Ignore error; getline will discover it again */
  1253.     }
  1254.     fflush(litout);
  1255.     if (ferror(litout)) {
  1256.         fclose(litout);
  1257.         fclose(in);
  1258.         rmtemp(litfile);
  1259.         return -1;
  1260.     }
  1261.     fclose(litout);
  1262.     }
  1263.     /* Skip header after BEGIN line */
  1264.     if (skipheaders(in, buf, &header_warned, 1) < 0) {
  1265.     fclose(in);
  1266.     return -1;
  1267.     }
  1268.     if (feof(in)) {
  1269.     fprintf(pgpout, LANG("ERROR: Hit EOF in header.\n"));
  1270.     fclose(in);
  1271.     return 13;
  1272.     }
  1273.  
  1274.     if ((out = fopen(outfile, FOPWBIN)) == NULL) {
  1275.     fprintf(pgpout,
  1276. LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
  1277.     fclose(in);
  1278.     return -1;
  1279.     }
  1280.     status = armordecode(in, out, &header_warned);
  1281.  
  1282.     if (litfile) {
  1283.     char *canonfile, hold_charset[16];
  1284.     char lit_mode = MODE_TEXT;
  1285.     word32 dummystamp = 0;
  1286.     FILE *f;
  1287.  
  1288.     /* Convert clearsigned message to internal character set */
  1289.     canonfile = tempfile(TMP_WIPE | TMP_TMPDIR);
  1290.     strip_spaces = TRUE;
  1291.         if (charset_header[0]) {
  1292.             strcpy(hold_charset, charset);
  1293.             strcpy(charset, charset_header);
  1294.             init_charset();
  1295.         }
  1296.     make_canonical(litfile, canonfile);
  1297.     rmtemp(litfile);
  1298.     litfile = canonfile;
  1299.         if (charset_header[0]) {
  1300.             strcpy(charset, hold_charset);
  1301.             init_charset();
  1302.     }
  1303.     /* Glue the literal file read above to the signature */
  1304.         f = fopen(litfile, FOPRBIN);
  1305.  
  1306.     write_ctb_len(out, CTB_LITERAL2_TYPE, fsize(f) + 6, FALSE);
  1307.     fwrite(&lit_mode, 1, 1, out);    /* write lit_mode */
  1308.     fputc('\0', out);    /* No filename */
  1309.     fwrite(&dummystamp, 1, sizeof(dummystamp), out);
  1310.     /* dummy timestamp */
  1311.     copyfile(f, out, -1L);    /* Append literal file */
  1312.     fclose(f);
  1313.     rmtemp(litfile);
  1314.     }
  1315.     if (write_error(out))
  1316.     status = -1;
  1317.     fclose(out);
  1318.     fclose(in);
  1319.     return status;
  1320. }                /* darmor_file */
  1321.  
  1322. /* Entry points for generic interface names */
  1323.  
  1324. int de_armor_file(char *infile, char *outfile, long *curline)
  1325. {
  1326.     int status;
  1327.  
  1328.     if (verbose)
  1329.     fprintf(pgpout,
  1330.          "de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
  1331.         infile, outfile, *curline);
  1332.     infile_line = (curline ? *curline : 0);
  1333.     status = darmor_file(infile, outfile);
  1334.     if (curline)
  1335.     *curline = infile_line;
  1336.     return status;
  1337. }
  1338.  
  1339. boolean
  1340. is_armor_file(char *infile, long startline)
  1341. {
  1342.     infile_line = startline;
  1343.     return is_armorfile(infile);
  1344. }
  1345.