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

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

unix.superglobalmegacorp.com

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