Annotation of pgp/src/armor.c, revision 1.1.1.6

1.1.1.6 ! root        1: /*     armor.c  - ASCII/binary encoding/decoding based partly on PEM RFC1113.
        !             2:        PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
        !             3: 
        !             4:         (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
        !             5:         The author assumes no liability for damages resulting from the use
        !             6:         of this software, even if the damage results from defects in this
        !             7:         software.  No warranty is expressed or implied.
        !             8: 
        !             9:         Note that while most PGP source modules bear Philip Zimmermann's
        !            10:         copyright notice, many of them have been revised or entirely written
        !            11:         by contributors who frequently failed to put their names in their
        !            12:         code.  Code that has been incorporated into PGP from other authors
        !            13:         was either originally published in the public domain or is used with
        !            14:         permission from the various authors.
        !            15: 
        !            16:         PGP is available for free to the public under certain restrictions.
        !            17:         See the PGP User's Guide (included in the release package) for
        !            18:         important information about licensing, patent restrictions on
        !            19:         certain algorithms, trademarks, copyrights, and export controls.
        !            20: */
        !            21: 
        !            22: 
        !            23: #include <ctype.h>
        !            24: #include <stdio.h>
        !            25: #include <string.h>
        !            26: #include "mpilib.h"
        !            27: #include "fileio.h"
        !            28: #include "mpiio.h"
        !            29: #include "language.h"
        !            30: #include "pgp.h"
        !            31: #include "crypto.h"
        !            32: #include "armor.h"
        !            33: 
        !            34: static int dpem_file(char *infile, char *outfile);
        !            35: static crcword crchware(byte ch, crcword poly, crcword accum);
        !            36: static int pem_file(char *infilename, char *outfilename, char *clearfilename);
        !            37: static int pemdecode(FILE *in, FILE *out);
        !            38: static void mk_crctbl(crcword poly);
        !            39: static boolean is_pemfile(char *infile);
        !            40: 
        !            41: /*     Begin PEM routines.
        !            42:        This converts a binary file into printable ASCII characters, in a
        !            43:        radix-64 form mostly compatible with the PEM RFC1113 format.
        !            44:        This makes it easier to send encrypted files over a 7-bit channel.
        !            45: */
        !            46: 
        !            47: /* Index this array by a 6 bit value to get the character corresponding
        !            48:  * to that value.
        !            49:  */
        !            50: static
        !            51: unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
        !            52: abcdefghijklmnopqrstuvwxyz0123456789+/";
        !            53: 
        !            54: /* Index this array by a 7 bit value to get the 6-bit binary field
        !            55:  * corresponding to that value.  Any illegal characters return high bit set.
        !            56:  */
        !            57: static
        !            58: unsigned char asctobin[] = {
        !            59:        0200,0200,0200,0200,0200,0200,0200,0200,
        !            60:        0200,0200,0200,0200,0200,0200,0200,0200,
        !            61:        0200,0200,0200,0200,0200,0200,0200,0200,
        !            62:        0200,0200,0200,0200,0200,0200,0200,0200,
        !            63:        0200,0200,0200,0200,0200,0200,0200,0200,
        !            64:        0200,0200,0200,0076,0200,0200,0200,0077,
        !            65:        0064,0065,0066,0067,0070,0071,0072,0073,
        !            66:        0074,0075,0200,0200,0200,0200,0200,0200,
        !            67:        0200,0000,0001,0002,0003,0004,0005,0006,
        !            68:        0007,0010,0011,0012,0013,0014,0015,0016,
        !            69:        0017,0020,0021,0022,0023,0024,0025,0026,
        !            70:        0027,0030,0031,0200,0200,0200,0200,0200,
        !            71:        0200,0032,0033,0034,0035,0036,0037,0040,
        !            72:        0041,0042,0043,0044,0045,0046,0047,0050,
        !            73:        0051,0052,0053,0054,0055,0056,0057,0060,
        !            74:        0061,0062,0063,0200,0200,0200,0200,0200
        !            75: };
        !            76: static long    infile_line;            /* Current line number for mult decodes */
        !            77: 
        !            78: /************************************************************************/
        !            79: 
        !            80: /* CRC Routines. */
        !            81: /*     These CRC functions are derived from code in chapter 19 of the book 
        !            82:        "C Programmer's Guide to Serial Communications", by Joe Campbell.
        !            83:        Generalized to any CRC width by Philip Zimmermann.
        !            84: */
        !            85: 
        !            86: #define byte unsigned char
        !            87: 
        !            88: #define CRCBITS 24     /* may be 16, 24, or 32 */
        !            89: /* #define maskcrc(crc) ((crcword)(crc)) */    /* if CRCBITS is 16 or 32 */
        !            90: #define maskcrc(crc) ((crc) & 0xffffffL)       /* if CRCBITS is 24 */
        !            91: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */
        !            92: #define CRCSHIFTS (CRCBITS-8)
        !            93: 
        !            94: /*
        !            95:  * Notes on making a good 24-bit CRC--
        !            96:  * The primitive irreducible polynomial of degree 23 over GF(2),
        !            97:  * 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
        !            98:  * 2nd edition" by Peterson and Weldon, page 490.  This polynomial was
        !            99:  * chosen for its uniform density of ones and zeros, which has better
        !           100:  * error detection properties than polynomials with a minimal number of
        !           101:  * nonzero terms.  Multiplying this primitive degree-23 polynomial by
        !           102:  * the polynomial x+1 yields the additional property of detecting any
        !           103:  * odd number of bits in error, which means it adds parity.  This 
        !           104:  * approach was recommended by Neal Glover.
        !           105:  *
        !           106:  * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
        !           107:  * bitwise add (xor) the unshifted version back in.  Dropping the unused 
        !           108:  * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 
        !           109:  * octal, or 0x864cfb hex.  
        !           110:  *
        !           111:  * You can detect spurious leading zeros or framing errors in the 
        !           112:  * message by initializing the CRC accumulator to some agreed-upon 
        !           113:  * nonzero "random-like" value, but this is a bit nonstandard.  
        !           114:  */
        !           115: 
        !           116: #define CCITTCRC 0x1021 /* CCITT's 16-bit CRC generator polynomial */
        !           117: #define PRZCRC 0x864cfbL /* PRZ's 24-bit CRC generator polynomial */
        !           118: #define CRCINIT 0xB704CEL      /* Init value for CRC accumulator */
        !           119: 
        !           120: static
        !           121: crcword crctable[256];         /* Table for speeding up CRC's */
        !           122: 
        !           123: /*
        !           124:  * mk_crctbl derives a CRC lookup table from the CRC polynomial.
        !           125:  * The table is used later by the crcbytes function given below.
        !           126:  * mk_crctbl only needs to be called once at the dawn of time.
        !           127:  *
        !           128:  * The theory behind mk_crctbl is that table[i] is initialized
        !           129:  * with the CRC of i, and this is related to the CRC of i>>1,
        !           130:  * so the CRC of i>>1 (pointed to by p) can be used to derive
        !           131:  * the CRC of i (pointed to by q).
        !           132:  */
        !           133: static
        !           134: void mk_crctbl(crcword poly)
        !           135: {
        !           136:        int i;
        !           137:        crcword t, *p, *q;
        !           138:        p = q = crctable;
        !           139:        *q++ = 0;
        !           140:        *q++ = poly;
        !           141:        for (i = 1; i < 128; i++) {
        !           142:                t = *++p;
        !           143:                if (t & CRCHIBIT) {
        !           144:                        t <<= 1;
        !           145:                        *q++ = t ^ poly;
        !           146:                        *q++ = t;
        !           147:                } else {
        !           148:                        t <<= 1;
        !           149:                        *q++ = t;
        !           150:                        *q++ = t ^ poly;
        !           151:                }
        !           152:        }
        !           153: }
        !           154: 
        !           155: /*
        !           156:  * Accumulate a buffer's worth of bytes into a CRC accumulator,
        !           157:  * returning the new CRC value.
        !           158:  */
        !           159: crcword
        !           160: crcbytes(byte *buf, unsigned len, register crcword accum)
        !           161: {
        !           162:        do {
        !           163:                accum = accum<<8 ^ crctable[(byte)(accum>>CRCSHIFTS) ^ *buf++];
        !           164:        } while (--len);
        !           165:        return maskcrc(accum);
        !           166: } /* crcbytes */
        !           167: 
        !           168: /* Initialize the CRC table using our codes */
        !           169: void init_crc(void)
        !           170: {
        !           171:        mk_crctbl(PRZCRC);
        !           172: }
        !           173: 
        !           174: 
        !           175: /************************************************************************/
        !           176: 
        !           177: 
        !           178: /* ENC is the basic 1 character encoding function to make a char printing */
        !           179: #define ENC(c) ((int)bintoasc[((c) & 077)])
        !           180: #define PAD            '='
        !           181: 
        !           182: /*
        !           183:  * output one group of up to 3 bytes, pointed at by p, on file f.
        !           184:  * if fewer than 3 are present, the 1 or two extras must be zeros.
        !           185:  */
        !           186: static void outdec(char *p, FILE *f, int count)
        !           187: {
        !           188:        int c1, c2, c3, c4;
        !           189: 
        !           190:        c1 = *p >> 2;
        !           191:        c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
        !           192:        c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
        !           193:        c4 = p[2] & 077;
        !           194:        putc(ENC(c1), f);
        !           195:        putc(ENC(c2), f);
        !           196:        if (count == 1) {
        !           197:                putc(PAD, f);
        !           198:                putc(PAD, f);
        !           199:        } else {
        !           200:                putc(ENC(c3), f);
        !           201:                if (count == 2)
        !           202:                        putc(PAD, f);
        !           203:                else
        !           204:                        putc(ENC(c4), f);
        !           205:        }
        !           206: }      /* outdec */
        !           207: 
        !           208: 
        !           209: /* Output the CRC value, MSB first per normal CRC conventions */
        !           210: static void outcrc (word32 crc, FILE *outFile)
        !           211: {
        !           212:        char crcbuf[4];
        !           213:        crcbuf[0] = (crc>>16) & 0xff;
        !           214:        crcbuf[1] = (crc>>8) & 0xff;
        !           215:        crcbuf[2] = (crc>>0) & 0xff;
        !           216:        putc(PAD,outFile);
        !           217:        outdec (crcbuf,outFile,3);
        !           218:        putc('\n',outFile);
        !           219: }      /* outcrc */
        !           220: 
        !           221: /* Return filename for output (text mode), but replace last letter(s) of
        !           222:  * filename with the ascii for num.  It will use the appropriate number
        !           223:  * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
        !           224:  * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits.  If its
        !           225:  * >= 1000, then we have other problems to worry about, and this might do
        !           226:  * weird things.
        !           227:  */
        !           228: static char *numFilename( char *fname, int num, int ofnum)
        !           229: {
        !           230:        static char     fnamenum[MAX_PATH];
        !           231:        int             len;
        !           232:        int             offset = 1;
        !           233: 
        !           234:        strcpy (fnamenum, fname);
        !           235:        len = strlen (fnamenum);
        !           236:        do {
        !           237:                fnamenum[len-offset] = '0' + (num%10);
        !           238:                num /= 10;
        !           239:                ofnum /= 10;
        !           240:                offset++;
        !           241:        } while (ofnum >= 1 && offset < 4);
        !           242:        return fnamenum;
        !           243: }
        !           244: 
        !           245: /*
        !           246:  * Reads and discards a line from the given file.  Returns -1 on error or
        !           247:  * EOF, 0 if the line is blank, and 1 if the line is not blank.
        !           248:  */
        !           249: static int
        !           250: skipline(FILE *f)
        !           251: {
        !           252:        int state, flag, c;
        !           253: 
        !           254:        state = 0;
        !           255:        flag = 0;
        !           256:        for (;;) {
        !           257:                c = getc(f);
        !           258:                if (c == '\n')
        !           259:                        return flag;
        !           260:                if (state) {
        !           261:                        ungetc(c, f);
        !           262:                        return flag;
        !           263:                }
        !           264:                if (c == EOF)
        !           265:                        return -1;
        !           266:                if (c == '\r')
        !           267:                        state = 1;
        !           268:                else if (c != ' ')
        !           269:                        flag = 1;
        !           270:        }
        !           271: } /* skipline */
        !           272: 
        !           273: /*
        !           274:  * Copies a line from the input file to the output.  Does NOT copy the
        !           275:  * trailing newline.  Returns -1 on EOF or error, 0 if the line was terminated
        !           276:  * by EOF, and 1 if the line was terminated with a newline sequence.
        !           277:  */
        !           278: static int
        !           279: copyline(FILE *in, FILE *out)
        !           280: {
        !           281:        int state, flag, c;
        !           282: 
        !           283:        state = 0;
        !           284:        for (;;) {
        !           285:                c = getc(in);
        !           286:                if (c == '\n')
        !           287:                        return 1;
        !           288:                if (state) {
        !           289:                        ungetc(c, in);
        !           290:                        return 1;
        !           291:                }
        !           292:                if (c == EOF)
        !           293:                        return 0;
        !           294:                if (c == '\r')
        !           295:                        state = 1;
        !           296:                else
        !           297:                        putc(c, out);
        !           298:        }
        !           299: } /* copyline */
        !           300: 
        !           301: /*
        !           302:  * Reads a line from file f, up to the size of the buffer.  The line in the
        !           303:  * buffer will NOT include line termination, although any of (CR, LF, CRLF)
        !           304:  * is accepted on input.  The return value is -1 on error, 0 if the line
        !           305:  * was terminated abnormally (EOF, error, or out of buffer space), and
        !           306:  * 1 if the line was terminated normally.
        !           307:  *
        !           308:  * Passing in a buffer less than 2 characters long is not a terribly bright
        !           309:  * idea.
        !           310:  */
        !           311: static int
        !           312: getline(char *buf, int n, FILE *f)
        !           313: {
        !           314:        int state;
        !           315:        char *p;
        !           316:        int c;
        !           317: 
        !           318:        state = 0;
        !           319:        p = buf;
        !           320:        for (;;) {
        !           321:                c = getc(f);
        !           322:                if (c == '\n') {
        !           323:                        *p = 0;
        !           324:                        return 1;       /* Line terminated with \n or \r\n */
        !           325:                }
        !           326:                if (state) {
        !           327:                        ungetc(c, f);
        !           328:                        *p = 0;
        !           329:                        return 1;       /* Line terminated with \r */
        !           330:                }
        !           331:                if (c == EOF) {
        !           332:                        *p = 0;
        !           333:                        return (p == buf) ? -1 : 0;     /* Error */
        !           334:                }
        !           335:                if (c == '\r')
        !           336:                        state = 1;
        !           337:                else if (--n > 0) {
        !           338:                        *p++ = c;
        !           339:                } else {
        !           340:                        ungetc(c, f);
        !           341:                        *p = 0;
        !           342:                        return 0;       /* Out of buffer space */
        !           343:                }
        !           344:        } /* for (;;) */
        !           345: } /* getline */
        !           346: 
        !           347: /*
        !           348:  * Read a line from file f, buf must be able to hold at least 80 characters.
        !           349:  * Strips trailing spaces and line terminator, can read LF, CRLF and CR
        !           350:  * textfiles.  Anything after 80 characters is ignored.  It can't be ASCII
        !           351:  * armor anyway.
        !           352:  */
        !           353: static char *
        !           354: get_armor_line(char *buf, FILE *f)
        !           355: {
        !           356:        int c, n = 79;
        !           357:        char *p = buf;
        !           358: 
        !           359:        do {
        !           360:                c = getc(f);
        !           361:                if (c == '\n' || c == '\r' || c == EOF)
        !           362:                        break;
        !           363:                *p++ = c;
        !           364:        } while (--n > 0);
        !           365:        if (p == buf && c == EOF) {
        !           366:                *buf = '\0';
        !           367:                return NULL;
        !           368:        }
        !           369:        /* skip to end of line */
        !           370:        while (c != '\n' && c != '\r' && c != EOF)
        !           371:                c = getc(f);
        !           372:        if (c == '\r' && (c = getc(f)) != '\n')
        !           373:                ungetc(c, f);
        !           374:        while (--p >= buf && *p == ' ')
        !           375:                ;
        !           376:        *++p = '\0';
        !           377:        return buf;
        !           378: }
        !           379: 
        !           380: 
        !           381: /*
        !           382:  * Encode a file in sections.  64 ASCII bytes * 720 lines = 46K, 
        !           383:  * recommended max.  Usenet message size is 50K so this leaves a nice 
        !           384:  * margin for .signature.  In the interests of orthogonality and 
        !           385:  * programmer laziness no check is made for a message containing only 
        !           386:  * a few lines (or even just an 'end') after a section break. 
        !           387:  */
        !           388: #define LINE_LEN       48L
        !           389: int pem_lines = 720;
        !           390: #define BYTES_PER_SECTION      (LINE_LEN * pem_lines)
        !           391: 
        !           392: #if 1
        !           393: /* This limit is advisory only; longer lines are handled properly.
        !           394:  * The only requirement is that this be at least as long as the longest
        !           395:  * delimiter string used by PGP
        !           396:  * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
        !           397:  */
        !           398: #define MAX_LINE_SIZE 80
        !           399: #else
        !           400: #ifdef MSDOS   /* limited stack space */
        !           401: #define MAX_LINE_SIZE  256
        !           402: #else
        !           403: #define MAX_LINE_SIZE  1024
        !           404: #endif
        !           405: #endif
        !           406: 
        !           407: #ifndef VMS
        !           408: /* armored files are opened in binary mode so that CRLF/LF/CR files
        !           409:    can be handled by all systems */
        !           410: #define        FOPRPEM FOPRBIN
        !           411: #else
        !           412: #define        FOPRPEM FOPRTXT
        !           413: #endif
        !           414: 
        !           415: extern boolean verbose;        /* Undocumented command mode in PGP.C */
        !           416: extern boolean filter_mode;
        !           417: 
        !           418: /*
        !           419:  * Copy from infilename to outfilename, PEM encoding as you go along,
        !           420:  * and with breaks every
        !           421:  * pem_lines lines.
        !           422:  * If clearfilename is non-NULL, first output that file preceded by a
        !           423:  * special header line.
        !           424:  */
        !           425: static
        !           426: int pem_file(char *infilename, char *outfilename, char *clearfilename)
        !           427: {
        !           428:        char buffer[MAX_LINE_SIZE];
        !           429:        int i, rc, bytesRead, lines = 0;
        !           430:        int noSections, currentSection = 1;
        !           431:        long fileLen;
        !           432:        crcword crc;
        !           433:        FILE *inFile, *outFile, *clearFile;
        !           434:        char *blocktype = "MESSAGE";
        !           435: 
        !           436:        /* open input file as binary */
        !           437:        if ((inFile = fopen(infilename,FOPRBIN)) == NULL)
        !           438:                return 1;
        !           439: 
        !           440:        if (!outfilename || pem_lines == 0) {
        !           441:                noSections = 1;
        !           442:        } else {
        !           443:                /* Evaluate how many parts this file will comprise */
        !           444:                fseek(inFile,0L,SEEK_END);
        !           445:                fileLen = ftell(inFile);
        !           446:                rewind(inFile);
        !           447:                noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
        !           448:                if (noSections > 99) {
        !           449:                        pem_lines = ((fileLen+LINE_LEN-1)/LINE_LEN + 98) / 99;
        !           450:                        noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
        !           451:                        fprintf(pgpout, "value for \"armorlines\" is too low, using %d\n", pem_lines);
        !           452:                }
        !           453:        }
        !           454:        
        !           455:        if (outfilename == NULL) {
        !           456:                outFile = stdout;
        !           457:        } else {
        !           458:                if (noSections > 1) {
        !           459:                        force_extension(outfilename, ASC_EXTENSION);
        !           460:                        outFile = fopen (numFilename (outfilename, 1, noSections), FOPWTXT);
        !           461:                } else {
        !           462:                        outFile = fopen(outfilename,FOPWTXT);
        !           463:                }
        !           464:        }
        !           465: 
        !           466:        if (outFile == NULL) {
        !           467:                fclose(inFile);
        !           468:                return 1;
        !           469:        }
        !           470: 
        !           471:        if (clearfilename) {
        !           472:                if ((clearFile = fopen(clearfilename,FOPRTXT)) == NULL) {
        !           473:                        fclose (inFile);
        !           474:                        if (outFile != stdout)
        !           475:                                fclose (outFile);
        !           476:                        return 1;
        !           477:                }
        !           478:                fprintf (outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
        !           479:                while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0)
        !           480:                {
        !           481:                        /* Quote lines beginning with '-' as per RFC1113;
        !           482:                         * Also quote lines beginning with "From "; this is
        !           483:                         * for Unix mailers which add ">" to such lines.
        !           484:                         */
        !           485:                        if (buffer[0] == '-' || strncmp(buffer, "From ", 5)==0)
        !           486:                                fputs("- ", outFile);
        !           487:                        fputs(buffer, outFile);
        !           488:                        /* If there is more on this line, copy it */
        !           489:                        if (i == 0)
        !           490:                                if (copyline(clearFile, outFile) <= 0)
        !           491:                                        break;
        !           492:                        fputc('\n', outFile);
        !           493:                }
        !           494:                fclose (clearFile);
        !           495:                putc('\n', outFile);
        !           496:                blocktype = "SIGNATURE";
        !           497:        }
        !           498: 
        !           499: 
        !           500:        if (noSections == 1) {
        !           501:                byte ctb = 0;
        !           502:                ctb = getc(inFile);
        !           503:                if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
        !           504:                        blocktype = "PUBLIC KEY BLOCK";
        !           505:                fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype);
        !           506:                rewind(inFile);
        !           507:        } else {
        !           508:                fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           509:                                        1, noSections);
        !           510:        }
        !           511:        fprintf (outFile, "Version: %s\n",LANG (rel_version));
        !           512:        if (globalCommentString[0])
        !           513:                fprintf (outFile, "Comment: %s\n", globalCommentString);
        !           514:        fprintf (outFile, "\n");
        !           515: 
        !           516:        init_crc();
        !           517:        crc = CRCINIT;
        !           518: 
        !           519:        while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0) {
        !           520:                /* Munge up LINE_LEN characters */
        !           521:                if (bytesRead < LINE_LEN)
        !           522:                        fill0 (buffer+bytesRead, LINE_LEN-bytesRead);
        !           523: 
        !           524:                crc = crcbytes((byte *)buffer, bytesRead, crc);
        !           525:                for (i=0; i<bytesRead-3; i+=3)
        !           526:                        outdec(buffer+i, outFile, 3);
        !           527:                outdec(buffer+i, outFile, bytesRead-i);
        !           528:                putc('\n',outFile);
        !           529: 
        !           530:                if (++lines == pem_lines && currentSection < noSections) {
        !           531:                        lines = 0;
        !           532:                        outcrc (crc, outFile);
        !           533:                        fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
        !           534:                                currentSection, noSections);
        !           535:                        if (write_error(outFile)) {
        !           536:                                fclose(outFile);
        !           537:                                return -1;
        !           538:                        }
        !           539:                        fclose (outFile);
        !           540:                        outFile = fopen (numFilename (outfilename, ++currentSection, noSections), FOPWTXT);
        !           541:                        if (outFile == NULL) {
        !           542:                                fclose(inFile);
        !           543:                                return -1;
        !           544:                        }
        !           545:                        fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           546:                                        currentSection, noSections);
        !           547:                        fprintf(outFile,"\n");
        !           548:                        crc = CRCINIT;
        !           549:                }
        !           550:        }
        !           551:        outcrc (crc, outFile);
        !           552: 
        !           553:        if (noSections == 1)
        !           554:                fprintf (outFile, "-----END PGP %s-----\n",blocktype);
        !           555:        else
        !           556:                fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n",
        !           557:                                noSections, noSections);
        !           558: 
        !           559:        /* Done */
        !           560:        fclose(inFile);
        !           561:        rc = write_error(outFile);
        !           562:        if (outFile == stdout)
        !           563:                return rc;
        !           564:        fclose(outFile);
        !           565: 
        !           566:        if (rc)
        !           567:                return -1;
        !           568: 
        !           569:        if (clearfilename) {
        !           570:                fprintf (pgpout, LANG("\nClear signature file: %s\n"), outfilename);
        !           571:        } else if (noSections == 1) {
        !           572:                fprintf (pgpout, LANG("\nTransport armor file: %s\n"), outfilename);
        !           573:        } else {
        !           574:                fprintf (pgpout, LANG("\nTransport armor files: "));
        !           575:                for (i=1; i<=noSections; ++i)
        !           576:                        fprintf (pgpout, "%s%s", numFilename(outfilename, i, noSections),
        !           577:                                                i==noSections?"\n":", ");
        !           578:        }
        !           579:        return 0;
        !           580: }      /* pem_file */
        !           581: 
        !           582: /*     End PEM encode routines. */
        !           583: 
        !           584: 
        !           585: /*     PEM decode routines.
        !           586: */
        !           587: 
        !           588: static
        !           589: int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
        !           590: {
        !           591:        unsigned char *bp;
        !           592:        int     length;
        !           593:        unsigned int c1,c2,c3,c4;
        !           594:        register int j;
        !           595: 
        !           596:        length = 0;
        !           597:        bp = (unsigned char *)inbuf;
        !           598: 
        !           599:        /* FOUR input characters go into each THREE output charcters */
        !           600: 
        !           601:        while (*bp != '\0') {
        !           602:                if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
        !           603:                        return -1;
        !           604:                ++bp;
        !           605:                if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
        !           606:                        return -1;
        !           607:                if (*++bp == PAD) {
        !           608:                        c3 = c4 = 0;
        !           609:                        length += 1;
        !           610:                        if (c2 & 15)
        !           611:                                return -1;
        !           612:                        if (strcmp((char *)bp, "==") == 0)
        !           613:                                bp += 1;
        !           614:                        else if (strcmp((char *)bp, "=3D=3D") == 0)
        !           615:                                bp += 5;
        !           616:                        else
        !           617:                                return -1;
        !           618:                } else if (*bp&0x80 || (c3=asctobin[*bp])&0x80) {
        !           619:                                return -1;
        !           620:                } else {
        !           621:                        if (*++bp == PAD) {
        !           622:                                c4 = 0;
        !           623:                                length += 2;
        !           624:                                if (c3 & 3)
        !           625:                                        return -1;
        !           626:                                if (strcmp((char *)bp, "=") == 0)
        !           627:                                        ; /* All is well */
        !           628:                                else if (strcmp((char *)bp, "=3D") == 0)
        !           629:                                        bp += 2;
        !           630:                                else
        !           631:                                        return -1;
        !           632:                        } else if (*bp&0x80 || (c4=asctobin[*bp])&0x80) {
        !           633:                                return -1;
        !           634:                        } else {
        !           635:                                length += 3;
        !           636:                        }
        !           637:                }
        !           638:                ++bp;
        !           639:                j = (c1 << 2) | (c2 >> 4);
        !           640:                *outbuf++=j;
        !           641:                j = (c2 << 4) | (c3 >> 2);
        !           642:                *outbuf++=j;
        !           643:                j = (c3 << 6) | c4;
        !           644:                *outbuf++=j;
        !           645:        }
        !           646: 
        !           647:        *outlength = length;
        !           648:        return 0;       /* normal return */
        !           649: 
        !           650: }      /* dpem_buffer */
        !           651: 
        !           652: static char pemfilename[MAX_PATH];
        !           653: /*
        !           654:  * try to open the next file of a multi-part armored file
        !           655:  * the sequence number is expected at the end of the file name
        !           656:  */
        !           657: static FILE *
        !           658: open_next(void)
        !           659: {
        !           660:        char *p, *s, c;
        !           661:        FILE *fp;
        !           662: 
        !           663:        p = pemfilename + strlen(pemfilename);
        !           664:        while (--p >= pemfilename && isdigit(*p)) {
        !           665:                if (*p != '9') {
        !           666:                        ++*p;
        !           667:                        return fopen(pemfilename, FOPRPEM);
        !           668:                }
        !           669:                *p = '0';
        !           670:        }
        !           671: 
        !           672:        /* need an extra digit */
        !           673:        if (p >= pemfilename) {
        !           674:                /* try replacing character ( .as0 -> .a10 ) */
        !           675:                c = *p;
        !           676:                *p = '1';
        !           677:                if ((fp = fopen(pemfilename, FOPRPEM)) != NULL)
        !           678:                        return fp;
        !           679:                *p = c; /* restore original character */
        !           680:        }
        !           681:        ++p;
        !           682:        for (s = p + strlen(p); s >= p; --s)
        !           683:                s[1] = *s;
        !           684:        *p = '1'; /* insert digit ( fn0 -> fn10 ) */
        !           685: 
        !           686:        return fopen(pemfilename, FOPRPEM);
        !           687: }
        !           688: 
        !           689: /*
        !           690:  * Copy from in to out, decoding as you go, with handling for multiple
        !           691:  * 500-line blocks of encoded data.
        !           692:  */
        !           693: static
        !           694: int pemdecode(FILE *in, FILE *out)
        !           695: {
        !           696:        char inbuf[80];
        !           697:        char outbuf[80];
        !           698: 
        !           699:        int i, n, status;
        !           700:        int line;
        !           701:        int section, currentSection = 1;
        !           702:        int noSections = 0;
        !           703:        int gotcrc = 0;
        !           704:        long crc=CRCINIT, chkcrc = -1;
        !           705:        char crcbuf[4];
        !           706:        int ret_code = 0;
        !           707:        int end_of_message;
        !           708: 
        !           709:        init_crc();
        !           710: 
        !           711:        for (line = 1; ; line++) {      /* for each input line */
        !           712:                if (get_armor_line(inbuf, in) == NULL) {
        !           713:                        end_of_message = 1;
        !           714:                } else {
        !           715:                        end_of_message = (strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0);
        !           716:                        ++infile_line;
        !           717:                }
        !           718: 
        !           719:                if (currentSection!=noSections && end_of_message) {
        !           720:                        /* End of this section */
        !           721:                        if (gotcrc) {
        !           722:                                if (chkcrc != crc) {
        !           723:                                        fprintf(pgpout,LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
        !           724:                                        ret_code = -1;  /* continue with decoding to see if there are other bad parts */
        !           725:                                }
        !           726:                        }
        !           727:                        gotcrc = 0;
        !           728:                        crc = CRCINIT;
        !           729:                        section = 0;
        !           730: 
        !           731:                        /* Try and find start of next section */
        !           732:                        do {
        !           733:                                if (get_armor_line(inbuf,in) == NULL) {
        !           734:                                        FILE *nextf;
        !           735:                                        if ((nextf = open_next()) != NULL) {
        !           736:                                                fclose(in);
        !           737:                                                in = nextf;
        !           738:                                                continue;
        !           739:                                        }
        !           740:                                        fprintf(pgpout,LANG("Can't find section %d.\n"),currentSection + 1);
        !           741:                                        return -1;
        !           742:                                }
        !           743:                                ++infile_line;
        !           744:                        }
        !           745:                        while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22));
        !           746: 
        !           747:                        /* Make sure this section is the correct one */
        !           748:                        if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d",
        !           749:                                &section,&noSections))
        !           750:                        {
        !           751:                                fprintf(pgpout,LANG("Badly formed section header, part %d.\n"),
        !           752:                                        currentSection+1);
        !           753:                                return -1;
        !           754:                        }
        !           755:                        if (section != ++currentSection) {
        !           756:                                fprintf(pgpout,LANG("Sections out of order, expected part %d"),currentSection);
        !           757:                                if (section)
        !           758:                                        fprintf(pgpout,LANG(", got part %d\n"),section);
        !           759:                                else
        !           760:                                        fputc('\n',pgpout);
        !           761:                                return -1;
        !           762:                        }
        !           763: 
        !           764:                        /* Skip header after BEGIN line */
        !           765:                        do {
        !           766:                                ++infile_line;
        !           767:                                if (get_armor_line(inbuf, in) == NULL) {
        !           768:                                        fprintf(pgpout,LANG("ERROR: Hit EOF in header of section %d.\n"),
        !           769:                                                currentSection);
        !           770:                                        return -1;
        !           771:                                }
        !           772:                        } while (inbuf[0] != '\0');
        !           773: 
        !           774:                        /* Continue decoding */
        !           775:                        continue;
        !           776:                }
        !           777: 
        !           778:                /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
        !           779:                        or handle checksum */
        !           780:                if (inbuf[0] == PAD) {  /* Checksum lines start with PAD char */
        !           781:                        /* If the already-armored file is sent through MIME
        !           782:                         * and gets armored again, '=' will become '=3D'.
        !           783:                         * To make life easier, we detect and work around this
        !           784:                         * idiosyncracy.
        !           785:                         */
        !           786:                        if (strlen(inbuf) == 7 &&
        !           787:                            inbuf[1] == '3' && inbuf[2] == 'D')
        !           788:                                status = dpem_buffer(inbuf+3, crcbuf, &n);
        !           789:                        else
        !           790:                                status = dpem_buffer(inbuf+1, crcbuf, &n);
        !           791:                        if ( status < 0 || n != 3 ) {
        !           792:                                fprintf(pgpout,LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line);
        !           793:                                return -1;
        !           794:                        }
        !           795:                        chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) +
        !           796:                                ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL);
        !           797:                        gotcrc = 1;
        !           798:                        continue;
        !           799:                }
        !           800:                if (inbuf[0] == '\0') {
        !           801:                        fprintf(pgpout,LANG("WARNING: No ASCII armor `END' line.\n"));
        !           802:                        break;
        !           803:                }
        !           804:                if (strncmp(inbuf, "-----END PGP ", 13) == 0)
        !           805:                        break;
        !           806: 
        !           807:                status = dpem_buffer(inbuf,outbuf,&n);
        !           808: 
        !           809:                if (status == -1) {
        !           810:                        fprintf(pgpout,LANG("ERROR: Bad ASCII armor character, line %d.\n"), line);
        !           811:                        gotcrc = 1;     /* this will print part number, continue with next part */
        !           812:                        ret_code = -1;
        !           813:                }
        !           814: 
        !           815:                if (n > sizeof outbuf) {
        !           816:                        fprintf(pgpout,LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"),
        !           817:                                        n, line);
        !           818:                        return -1;
        !           819:                }
        !           820: 
        !           821:                crc = crcbytes((byte *)outbuf, n, crc);
        !           822:                if (fwrite(outbuf,1,n,out) != n) {
        !           823:                        ret_code = -1;
        !           824:                        break;
        !           825:                }
        !           826: 
        !           827:        }       /* line */
        !           828: 
        !           829:        if (gotcrc) {
        !           830:                if (chkcrc != crc) {
        !           831:                        fprintf(pgpout,LANG("ERROR: Bad ASCII armor checksum"));
        !           832:                        if (noSections > 0)
        !           833:                                fprintf(pgpout,LANG(" in section %d"), noSections);
        !           834:                        fputc('\n',pgpout);
        !           835:                        return -1;
        !           836:                }
        !           837:        } else {
        !           838:                fprintf(pgpout,LANG("Warning: Transport armor lacks a checksum.\n"));
        !           839:        }
        !           840: 
        !           841:        return ret_code;        /* normal return */
        !           842: }   /* pemdecode */
        !           843: 
        !           844: 
        !           845: static
        !           846: boolean is_pemfile(char *infile)
        !           847: {
        !           848:        FILE    *in;
        !           849:        char    inbuf[80];
        !           850:        char    outbuf[80];
        !           851:        int     n, status;
        !           852:        long    il;
        !           853: 
        !           854:        if ((in = fopen(infile, FOPRPEM)) == NULL) {
        !           855:                /* can't open file */
        !           856:                return FALSE;
        !           857:        }
        !           858: 
        !           859:        /* Read to infile_line before we begin looking */
        !           860:        for (il=0; il<infile_line; ++il) {
        !           861:                if (get_armor_line(inbuf, in) == NULL) {
        !           862:                        fclose(in);
        !           863:                        return FALSE;
        !           864:                }
        !           865:        }
        !           866: 
        !           867:        /* search file for header line */
        !           868:        for (;;) {
        !           869:                if (get_armor_line(inbuf, in) == NULL) {
        !           870:                        break;
        !           871:                } else {
        !           872:                        if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) {
        !           873:                                if (strncmp(inbuf,"-----BEGIN PGP SIGNED MESSAGE-----",34)==0) {
        !           874:                                        fclose(in);
        !           875:                                        return TRUE;
        !           876:                                }
        !           877:                                do {
        !           878:                                        if (get_armor_line(inbuf, in) == NULL)
        !           879:                                                break;
        !           880: #ifndef STRICT_PEM
        !           881:                                        if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48)
        !           882:                                        {
        !           883:                                                fclose(in);
        !           884:                                                return TRUE;
        !           885:                                        }
        !           886: #endif
        !           887:                                } while (inbuf[0] != '\0');
        !           888:                                if (get_armor_line(inbuf, in) == NULL)
        !           889:                                        break;
        !           890:                                status = dpem_buffer(inbuf,outbuf,&n);
        !           891:                                if (status < 0)
        !           892:                                        break;
        !           893:                                fclose(in);
        !           894:                                return TRUE;
        !           895:                        }
        !           896:                }
        !           897:        }
        !           898: 
        !           899:        fclose(in);
        !           900:        return FALSE;
        !           901: 
        !           902: }      /* is_pemfile */
        !           903: 
        !           904: 
        !           905: static
        !           906: int dpem_file(char *infile, char *outfile)
        !           907: {
        !           908:        FILE    *in, *out;
        !           909:        char    buf[MAX_LINE_SIZE];
        !           910:        char    outbuf[80];
        !           911:        int     status, n;
        !           912:        long    il, fpos;
        !           913:        char    *litfile = NULL;
        !           914: 
        !           915:        if ((in = fopen(infile, FOPRPEM)) == NULL) {
        !           916:                fprintf(pgpout,LANG("ERROR: Can't find file %s\n"), infile);
        !           917:                return 10;
        !           918:        }
        !           919:        strcpy(pemfilename, infile);    /* store filename for multi-parts */
        !           920: 
        !           921:        /* Skip to infile_line */
        !           922:        for (il=0; il<infile_line; ++il) {
        !           923:                if (get_armor_line(buf, in) == NULL) {
        !           924:                        fclose(in);
        !           925:                        return -1;
        !           926:                }
        !           927:        }
        !           928: 
        !           929:        /* Loop through file, searching for header.  Decode anything with a
        !           930:           header, complain if there were no headers. */
        !           931: 
        !           932:        /* search file for header line */
        !           933:        for (;;) {
        !           934:                ++infile_line;
        !           935:                if (get_armor_line(buf, in) == NULL) {
        !           936:                        fprintf(pgpout,LANG("ERROR: No ASCII armor `BEGIN' line!\n"));
        !           937:                        fclose(in);
        !           938:                        return 12;
        !           939:                }
        !           940:                if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !           941:                        break;
        !           942:        }
        !           943:        if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
        !           944:                FILE    *litout;
        !           945:                char    *canonfile, *p;
        !           946:                int     nline;
        !           947: 
        !           948:                litfile = tempfile(TMP_WIPE|TMP_TMPDIR);
        !           949:                if ((litout = fopen (litfile, FOPWTXT)) == NULL) {
        !           950:                        fprintf(pgpout,LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
        !           951:                        fclose(in);
        !           952:                        return -1;
        !           953:                }
        !           954:                /* Skip header lines until a blank is hit */
        !           955:                do {
        !           956:                        ++infile_line;
        !           957:                        status = skipline(in);
        !           958:                } while (status != 0);
        !           959:                /* Ignore error; getline will discover it again */
        !           960:                status = 0;
        !           961:                for (;;) {
        !           962:                        ++infile_line;
        !           963:                        nline = status;
        !           964:                        status = getline(buf, sizeof buf, in);
        !           965:                        if (status < 0) {
        !           966:                                fprintf(pgpout,LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
        !           967:                                fclose(in);
        !           968:                                fclose(litout);
        !           969:                                rmtemp (litfile);
        !           970:                                return 12;
        !           971:                        }
        !           972: 
        !           973:                        if (strncmp(buf,"-----BEGIN PGP ", 15) == 0)
        !           974:                                break;
        !           975:                        if (nline)
        !           976:                                putc('\n', litout);
        !           977:                        /* De-quote lines starting with '- ' */
        !           978:                        fputs(buf + ((buf[0]=='-'&&buf[1]==' ')?2:0), litout);
        !           979:                        /* Copy trailing part of line, if any. */
        !           980:                        if (!status)
        !           981:                                status = copyline(in, litout);
        !           982:                        /* Ignore error; getline will discover it again */
        !           983:                }
        !           984:                fflush (litout);
        !           985:                if (ferror(litout)) {
        !           986:                        fclose(litout);
        !           987:                        fclose(in);
        !           988:                        rmtemp (litfile);
        !           989:                        return -1;
        !           990:                }
        !           991:                fclose (litout);
        !           992:                canonfile = tempfile(TMP_WIPE|TMP_TMPDIR);
        !           993:                strip_spaces = TRUE;
        !           994:                make_canonical (litfile, canonfile);
        !           995:                rmtemp (litfile);
        !           996:                litfile = canonfile;
        !           997:        }
        !           998: 
        !           999:        /* Skip header after BEGIN line */
        !          1000:        do {
        !          1001:                ++infile_line;
        !          1002:                fpos = ftell(in);
        !          1003:                if (get_armor_line(buf, in) == NULL) {
        !          1004:                        fprintf(pgpout,LANG("ERROR: Hit EOF in header.\n"));
        !          1005:                        fclose(in);
        !          1006:                        return 13;
        !          1007:                }
        !          1008: #ifndef STRICT_PEM
        !          1009:                if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48) {
        !          1010:                        fseek(in, fpos, SEEK_SET);
        !          1011:                        --infile_line;
        !          1012:                        break;
        !          1013:                }
        !          1014: #endif
        !          1015:        } while (buf[0] != '\0');
        !          1016: 
        !          1017:        if ((out = fopen(outfile, FOPWBIN)) == NULL) {
        !          1018:                fprintf(pgpout,LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
        !          1019:                fclose(in);
        !          1020:                return -1;
        !          1021:        }
        !          1022: 
        !          1023:        status = pemdecode(in, out);
        !          1024: 
        !          1025:        if (litfile) {
        !          1026:                /* Glue the literal file read above to the signature */
        !          1027:                char lit_mode=MODE_TEXT;        
        !          1028:                word32 dummystamp = 0;
        !          1029:                FILE *f = fopen(litfile,FOPRBIN);
        !          1030:                write_ctb_len (out, CTB_LITERAL2_TYPE, fsize(f)+6, FALSE);
        !          1031:                fwrite ( &lit_mode, 1, 1, out );        /*      write lit_mode */
        !          1032:                fputc ('\0', out);                      /* No filename */
        !          1033:                fwrite ( &dummystamp, 1, sizeof(dummystamp), out); /* dummy timestamp */
        !          1034:                copyfile(f,out,-1L);            /* Append literal file */
        !          1035:                fclose (f);
        !          1036:                rmtemp(litfile);
        !          1037:        }
        !          1038: 
        !          1039:        if (write_error(out))
        !          1040:                status = -1;
        !          1041:        fclose(out);
        !          1042:        fclose(in);
        !          1043:        return status;
        !          1044: }   /* dpem_file */
        !          1045: 
        !          1046: /* Entry points for generic interface names */
        !          1047: int
        !          1048: armor_file (char *infile, char *outfile, char *filename, char *clearname)
        !          1049: {
        !          1050:        if (verbose)
        !          1051:                fprintf(pgpout,"armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
        !          1052:                        infile, outfile, filename, clearname);
        !          1053:        return pem_file (infile, outfile, clearname);
        !          1054: }
        !          1055: 
        !          1056: int
        !          1057: de_armor_file(char *infile, char *outfile, long *curline)
        !          1058: {
        !          1059:        int status;
        !          1060: 
        !          1061:        if (verbose)
        !          1062:                fprintf(pgpout,"de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
        !          1063:                        infile, outfile, *curline);
        !          1064:        infile_line = (curline ? *curline : 0);
        !          1065:        status = dpem_file (infile, outfile);
        !          1066:        if (curline)
        !          1067:                *curline = infile_line;
        !          1068:        return status;
        !          1069: }
        !          1070: 
        !          1071: boolean
        !          1072: is_armor_file (char *infile, long startline)
        !          1073: {
        !          1074:        infile_line = startline;
        !          1075:        return is_pemfile (infile);
        !          1076: }

unix.superglobalmegacorp.com

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