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

1.1     ! 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: extern boolean verbose;        /* Undocumented command mode in PGP.C */
        !           238: extern boolean filter_mode;
        !           239: 
        !           240: /*
        !           241:  * Copy from infilename to outfilename, PEM encoding as you go along,
        !           242:  * and with breaks every
        !           243:  * pem_lines lines.
        !           244:  */
        !           245: int pem_file(char *infilename, char *outfilename)
        !           246: {
        !           247:        char buffer[80];
        !           248:        int i,bytesRead,lines = 0;
        !           249:        int noSections, currentSection = 1;
        !           250:        long fileLen;
        !           251:        crcword crc;
        !           252:        FILE *inFile, *outFile;
        !           253:        char *blocktype = "MESSAGE";
        !           254: 
        !           255:        if (verbose)
        !           256:                fprintf(pgpout,PSTR("Converting output to ASCII armor format.\n"));
        !           257: 
        !           258:        /* open input file as binary */
        !           259:        if ((inFile = fopen(infilename,"rb")) == NULL)
        !           260:        {   
        !           261:                return(1);
        !           262:        }
        !           263: 
        !           264:        if (filter_mode || pem_lines == 0)
        !           265:                noSections = 1;
        !           266:        else
        !           267:        {       /* Evaluate how many parts this file will comprise */
        !           268:                fseek(inFile,0L,SEEK_END);
        !           269:                fileLen = ftell(inFile);
        !           270:                rewind(inFile);
        !           271:                noSections = (fileLen + BYTES_PER_SECTION - 1) / BYTES_PER_SECTION;
        !           272:        }
        !           273:        
        !           274:        if (noSections > 1)
        !           275:        {       force_extension(outfilename, ASC_EXTENSION);
        !           276:                outFile = fopen (numFilename (outfilename, 1), "w");
        !           277:        }
        !           278:        else
        !           279:                outFile = fopen(outfilename,"w");
        !           280: 
        !           281:        if (outFile == NULL)
        !           282:        {       fclose(inFile);
        !           283:                return(1);
        !           284:        }
        !           285: 
        !           286:        if (noSections == 1)
        !           287:        {
        !           288:                byte ctb = 0;
        !           289:                ctb = getc(inFile);
        !           290:                if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
        !           291:                        blocktype = "PUBLIC KEY BLOCK";
        !           292:                fprintf (outFile, "-----BEGIN PGP %s-----\n",blocktype);
        !           293:                rewind(inFile);
        !           294:        }
        !           295:        else
        !           296:                fprintf (outFile, "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           297:                                        1, noSections);
        !           298:        fprintf (outFile, "Version: %s\n",rel_version);
        !           299:        fprintf (outFile, "\n");
        !           300: 
        !           301:        init_crc();
        !           302:        crc = CRCINIT;
        !           303: 
        !           304:        while((bytesRead = fread(buffer,1,LINE_LEN,inFile)) > 0)
        !           305:        {       /* Munge up LINE_LEN characters */
        !           306:                if (bytesRead < LINE_LEN)
        !           307:                        fill0 (buffer+bytesRead, LINE_LEN-bytesRead);
        !           308: 
        !           309:                for (i=0; i<bytesRead-2; i+=3) {
        !           310:                        crc = crcupdate(buffer[i],crc);
        !           311:                        crc = crcupdate(buffer[i+1],crc);
        !           312:                        crc = crcupdate(buffer[i+2],crc);
        !           313:                        outdec(buffer+i,outFile,3);
        !           314:                }
        !           315: 
        !           316:                if (i<bytesRead) {
        !           317:                        outdec(buffer+i,outFile,bytesRead-i);
        !           318:                        while (i<bytesRead)
        !           319:                                crc = crcupdate(buffer[i++],crc);
        !           320:                }
        !           321:                putc('\n',outFile);
        !           322: 
        !           323:                if (++lines == pem_lines && !filter_mode && currentSection < noSections)
        !           324:                {       lines = 0;
        !           325:                        outcrc (crc, outFile);
        !           326:                        fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
        !           327:                                currentSection, noSections);
        !           328:                        fclose (outFile);
        !           329:                        outFile = fopen (numFilename (outfilename, ++currentSection), "w");
        !           330:                        fprintf(outFile,"-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           331:                                        currentSection, noSections);
        !           332:                        fprintf(outFile,"\n");
        !           333:                        crc = CRCINIT;
        !           334:                }
        !           335:        }
        !           336:        outcrc (crc, outFile);
        !           337: 
        !           338:        if (noSections == 1)
        !           339:                fprintf (outFile, "-----END PGP %s-----\n\n",blocktype);
        !           340:        else
        !           341:                fprintf(outFile,"-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
        !           342:                                noSections, noSections);
        !           343: 
        !           344:        /* Done */
        !           345:        if (ferror(outFile) || fclose(outFile))
        !           346:                return(-1);
        !           347:        fclose(inFile);
        !           348: 
        !           349:        if (filter_mode)
        !           350:                return(0);
        !           351: 
        !           352:        if (noSections == 1)
        !           353:                fprintf (pgpout, PSTR("\nTransport armor file: %s\n"), outfilename);
        !           354:        else
        !           355:        {       int i;
        !           356:                fprintf (pgpout, PSTR("\nTransport armor files: "));
        !           357:                for (i=1; i<=noSections; ++i)
        !           358:                        fprintf (pgpout, "%s%s", numFilename(outfilename,i),
        !           359:                                                i==noSections?"\n":", ");
        !           360:        }
        !           361:        return(0);
        !           362: }      /* pem_file */
        !           363: 
        !           364: 
        !           365: 
        !           366: 
        !           367: 
        !           368: /*     End PEM encode routines. */
        !           369: 
        !           370: /*     PEM decode routines.
        !           371: */
        !           372: 
        !           373: #define MAX_RETRY_LINES        100
        !           374: 
        !           375: /* Strip trailing spaces and CR characters */
        !           376: void
        !           377: strip_trailing (char *buf)
        !           378: {
        !           379:        char *bp = buf;
        !           380:        while (*bp++ != '\n')           /* Find end of line */
        !           381:                ;
        !           382:        --bp; --bp;                                     /* And back up... */
        !           383:                                                                /* Back up over spaces & CR */
        !           384:        while (bp >= buf  &&  (*bp == ' '  ||  *bp == '\r'))
        !           385:                --bp;
        !           386:        bp[1] = '\n';                           /* Terminate line cleanly */
        !           387:        bp[2] = '\0';
        !           388: }
        !           389: 
        !           390: 
        !           391: int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
        !           392: {
        !           393:        unsigned char *bp;
        !           394:        int     length;
        !           395:        unsigned int c1,c2,c3,c4;
        !           396:        register int j;
        !           397: 
        !           398:        length = 0;
        !           399:        bp = (unsigned char *)inbuf;
        !           400: 
        !           401:        /* FOUR input characters go into each THREE output charcters */
        !           402: 
        !           403:        while (*bp!='\0' && *bp!='\n' && *bp!='\r')
        !           404:        {       if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
        !           405:                        return -1;
        !           406:                ++bp;
        !           407:                if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
        !           408:                        return -1;
        !           409:                if (*++bp == PAD)
        !           410:                {       c3 = c4 = 0;
        !           411:                        length += 1;
        !           412:                        if (*++bp != PAD)
        !           413:                                return -1;
        !           414:                }
        !           415:                else if (*bp&0x80 || (c3=asctobin[*bp])&0x80)
        !           416:                                return -1;
        !           417:                else
        !           418:                {       if (*++bp == PAD)
        !           419:                        {       c4 = 0;
        !           420:                                length += 2;
        !           421:                        }
        !           422:                        else if (*bp&0x80 || (c4=asctobin[*bp])&0x80)
        !           423:                                return -1;
        !           424:                        else
        !           425:                                length += 3;
        !           426:                }
        !           427:                ++bp;
        !           428:                j = (c1 << 2) | (c2 >> 4);
        !           429:                *outbuf++=j;
        !           430:                j = (c2 << 4) | (c3 >> 2);
        !           431:                *outbuf++=j;
        !           432:                j = (c3 << 6) | c4;
        !           433:                *outbuf++=j;
        !           434:        }
        !           435: 
        !           436:        *outlength = length;
        !           437:        return(0);      /* normal return */
        !           438: 
        !           439: }      /* dpem_buffer */
        !           440: 
        !           441: static char pemfilename[MAX_PATH];
        !           442: /*
        !           443:  * try to open the next file of a multi-part armored file
        !           444:  * the sequence number is expected at the end of the file name
        !           445:  */
        !           446: static FILE *
        !           447: open_next()
        !           448: {
        !           449:        char *p, *s, c;
        !           450:        FILE *fp;
        !           451: 
        !           452:        p = pemfilename + strlen(pemfilename);
        !           453:        while (--p >= pemfilename && isdigit(*p))
        !           454:        {
        !           455:                if (*p != '9')
        !           456:                {
        !           457:                        ++*p;
        !           458:                        return(fopen(pemfilename, "r"));
        !           459:                }
        !           460:                *p = '0';
        !           461:        }
        !           462: 
        !           463:        /* need an extra digit */
        !           464:        if (p >= pemfilename)
        !           465:        {       /* try replacing character ( .as0 -> .a10 ) */
        !           466:                c = *p;
        !           467:                *p = '1';
        !           468:                if ((fp = fopen(pemfilename, "r")) != NULL)
        !           469:                        return(fp);
        !           470:                *p = c; /* restore original character */
        !           471:        }
        !           472:        ++p;
        !           473:        for (s = p + strlen(p); s >= p; --s)
        !           474:                s[1] = *s;
        !           475:        *p = '1'; /* insert digit ( fn0 -> fn10 ) */
        !           476: 
        !           477:        return(fopen(pemfilename, "r"));
        !           478: }
        !           479: 
        !           480: /*
        !           481:  * Copy from in to out, decoding as you go, with handling for multiple
        !           482:  * 500-line blocks of encoded data.
        !           483:  */
        !           484: int pemdecode(FILE *in, FILE *out)
        !           485: {
        !           486: char inbuf[96];
        !           487: char outbuf[64];
        !           488: 
        !           489: int i, n, status;
        !           490: int line;
        !           491: int lineCount = 0;
        !           492: int section, currentSection = 1;
        !           493: int noSections = 0;
        !           494: int gotcrc = 0;
        !           495: long crc=CRCINIT, chkcrc;
        !           496: char crcbuf[4];
        !           497: 
        !           498:        init_crc();
        !           499: 
        !           500:        for (line = 1; ; line++)        /* for each input line */
        !           501:        {
        !           502:                if (fgets(inbuf, sizeof(inbuf), in) == NULL)
        !           503:                {
        !           504:                        fprintf(pgpout,PSTR("ERROR: ASCII armor decode input ended unexpectedly!\n"));
        !           505:                        return(18);
        !           506:                }
        !           507:                ++infile_line;
        !           508: 
        !           509:                if (currentSection!=noSections &&
        !           510:                                strncmp(inbuf,"-----END PGP MESSAGE,", 21) == 0)
        !           511:                {       /* End of this section */
        !           512:                        if (gotcrc)
        !           513:                        {       if (chkcrc != crc)
        !           514:                                {       fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
        !           515:                                        return -1;
        !           516:                                }
        !           517:                        }
        !           518:                        gotcrc = 0;
        !           519:                        crc = CRCINIT;
        !           520:                        lineCount = 0;
        !           521:                        section = 0;
        !           522: 
        !           523:                        /* Try and find start of next section */
        !           524:                        do
        !           525:                        {       if (fgets(inbuf,sizeof(inbuf),in) == NULL || ++lineCount == MAX_RETRY_LINES)
        !           526:                                {       FILE *nextf;
        !           527:                                        if ((nextf = open_next()) != NULL)
        !           528:                                        {
        !           529:                                                fclose(in);
        !           530:                                                in = nextf;
        !           531:                                                lineCount = 0;
        !           532:                                                continue;
        !           533:                                        }
        !           534:                                        fprintf(pgpout,PSTR("Can't find section %d.\n"),currentSection + 1);
        !           535:                                        return(-1);
        !           536:                                }
        !           537:                                ++infile_line;
        !           538:                        }
        !           539:                        while (strncmp(inbuf,"-----BEGIN PGP MESSAGE",22));
        !           540: 
        !           541:                        /* Make sure this section is the correct one */
        !           542:                        lineCount = 0;
        !           543:                        if (2 != sscanf(inbuf,"-----BEGIN PGP MESSAGE, PART %d/%d",
        !           544:                                &section,&noSections))
        !           545:                        {       fprintf(pgpout,PSTR("Badly formed section header, part %d.\n"),
        !           546:                                        currentSection+1);
        !           547:                                return(-1);
        !           548:                        }
        !           549:                        if (section != ++currentSection)
        !           550:                        {       fprintf(pgpout,PSTR("Sections out of order, expected part %d"),currentSection);
        !           551:                                if (section)
        !           552:                                        fprintf(pgpout,PSTR(", got part %d\n"),section);
        !           553:                                else
        !           554:                                        fputc('\n',pgpout);
        !           555:                                return(-1);
        !           556:                        }
        !           557: 
        !           558:                        /* Skip header after BEGIN line */
        !           559:                        do {
        !           560:                                ++infile_line;
        !           561:                                if (fgets(inbuf, sizeof inbuf, in) == NULL)
        !           562:                                {
        !           563:                                        fprintf(pgpout,PSTR("ERROR: Hit EOF in header of section %d.\n"),
        !           564:                                                currentSection);
        !           565:                                        return(-1);
        !           566:                                }
        !           567:                        } while (inbuf[0] != '\n' && inbuf[0] != '\r');
        !           568: 
        !           569:                        /* Continue decoding */
        !           570:                        continue;
        !           571:                }
        !           572: 
        !           573:                /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
        !           574:                        or handle checksum */
        !           575:                if (inbuf[0] == PAD)    /* Checksum lines start with PAD char */
        !           576:                {       status = dpem_buffer (inbuf+1,crcbuf,&n);
        !           577:                        if (status==-1  ||  n!=3)
        !           578:                        {       fprintf(pgpout,PSTR("ERROR: Badly formed ASCII armor checksum, line %d.\n"),line);
        !           579:                                return -1;
        !           580:                        }
        !           581:                        chkcrc = (((long)crcbuf[0]<<16)&0xff0000L) +
        !           582:                                ((crcbuf[1]<<8)&0xff00L) + (crcbuf[2]&0xffL);
        !           583:                        gotcrc = 1;
        !           584:                        continue;
        !           585:                }
        !           586:                if (inbuf[0] == '\n'  ||  inbuf[0] == '\r')
        !           587:                {       fprintf(pgpout,PSTR("WARNING: No ASCII armor `END' line.\n"));
        !           588:                        break;
        !           589:                }
        !           590:                if (strncmp(inbuf, "-----END PGP ", 13) == 0)
        !           591:                        break;
        !           592: 
        !           593:                status = dpem_buffer(inbuf,outbuf,&n);
        !           594: 
        !           595:                if (status == -1)
        !           596:                {       fprintf(pgpout,PSTR("ERROR: Bad ASCII armor character, line %d.\n"), line);
        !           597:                        return -1;
        !           598:                }
        !           599: 
        !           600:                if (n > sizeof outbuf)
        !           601:                {       fprintf(pgpout,PSTR("ERROR: Bad ASCII armor line length %d on line %d.\n"),
        !           602:                                        n, line);
        !           603:                        return -1;
        !           604:                }
        !           605: 
        !           606:                for (i=0; i<n; ++i)
        !           607:                        crc = crcupdate(outbuf[i],crc);
        !           608:                fwrite(outbuf,1,n,out);
        !           609: 
        !           610:        }       /* line */
        !           611: 
        !           612:        if (gotcrc)
        !           613:        {       if (chkcrc != crc)
        !           614:                {       fprintf(pgpout,PSTR("ERROR: Bad ASCII armor checksum"));
        !           615:                        if (noSections > 0)
        !           616:                                fprintf(pgpout,PSTR(" in section %d"), noSections);
        !           617:                        fputc('\n',pgpout);
        !           618:                        return -1;
        !           619:                }
        !           620:        }
        !           621:        else
        !           622:                fprintf(pgpout,PSTR("Warning: Transport armor lacks a checksum.\n"));
        !           623: 
        !           624:        return(0);      /* normal return */
        !           625: }   /* pemdecode */
        !           626: 
        !           627: 
        !           628: boolean is_pemfile(char *infile)
        !           629: {
        !           630:        FILE    *in;
        !           631:        char    inbuf[80];
        !           632:        char    outbuf[80];
        !           633:        int             i, n, status;
        !           634:        long    il;
        !           635: 
        !           636:        if ((in = fopen(infile, "r")) == NULL)
        !           637:        {       /* can't open file */
        !           638:                return(FALSE);
        !           639:        }
        !           640: 
        !           641:        /* Read to infile_line before we begin looking */
        !           642:        for (il=0; il<infile_line; ++il)
        !           643:        {
        !           644:                if (fgets(inbuf, sizeof inbuf, in) == NULL)
        !           645:                        return(FALSE);
        !           646:        }
        !           647: 
        !           648:        /* search file for header line */
        !           649:        for (i=0; i<200; i++)   /* give up after 200 lines of garbage */
        !           650:        {
        !           651:                if (fgets(inbuf, sizeof inbuf, in) == NULL)
        !           652:                        break;
        !           653:                else
        !           654:                {
        !           655:                        if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0)
        !           656:                        {
        !           657:                                do {
        !           658:                                        if (fgets(inbuf, sizeof inbuf, in) == NULL)
        !           659:                                                break;
        !           660: #ifndef STRICT_PEM
        !           661:                                        if (dpem_buffer(inbuf,outbuf,&n) == 0 && n == 48)
        !           662:                                        {       fclose(in);
        !           663:                                                return(TRUE);
        !           664:                                        }
        !           665: #endif
        !           666:                                        strip_trailing(inbuf);
        !           667:                                } while (inbuf[0] != '\n');
        !           668:                                if (fgets(inbuf, sizeof inbuf, in) == NULL)
        !           669:                                        break;
        !           670:                                status = dpem_buffer(inbuf,outbuf,&n);
        !           671:                                if (status < 0)
        !           672:                                        break;
        !           673:                                fclose(in);
        !           674:                                return(TRUE);
        !           675:                        }
        !           676:                }
        !           677:        }
        !           678: 
        !           679:        fclose(in);
        !           680:        return(FALSE);
        !           681: 
        !           682: }      /* is_pemfile */
        !           683: 
        !           684: 
        !           685: int dpem_file(char *infile, char *outfile, boolean *newname)
        !           686: {
        !           687: FILE   *in, *out;
        !           688: char   buf[80];
        !           689: char   outbuf[80];
        !           690: int            status, n;
        !           691: long   il, fpos;
        !           692: 
        !           693:        /* open PEM decode file as text */
        !           694:        if ((in = fopen(infile, "r")) == NULL)
        !           695:        {
        !           696:                fprintf(pgpout,PSTR("ERROR: Can't find file %s\n"), infile);
        !           697:                return(10);
        !           698:        }
        !           699:        strcpy(pemfilename, infile);    /* store filename for multi-parts */
        !           700: 
        !           701:        /* Skip to infile_line */
        !           702:        for (il=0; il<infile_line; ++il)
        !           703:        {
        !           704:                if (fgets(buf, sizeof buf, in) == NULL)
        !           705:                        return(FALSE);
        !           706:        }
        !           707: 
        !           708:        /* Loop through file, searching for header.  Decode anything with a
        !           709:           header, complain if there were no headers. */
        !           710: 
        !           711:        /* search file for header line */
        !           712:     for (;;)
        !           713:        {
        !           714:                ++infile_line;
        !           715:                if (fgets(buf, sizeof buf, in) == NULL)
        !           716:                {
        !           717:                        fprintf(pgpout,PSTR("ERROR: No ASCII armor `BEGIN' line!\n"));
        !           718:                        fclose(in);
        !           719:                        return(12);
        !           720:                }
        !           721:                if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !           722:                        break;
        !           723:        }
        !           724:        /* Skip header after BEGIN line */
        !           725:        do {
        !           726:                ++infile_line;
        !           727:                fpos = ftell(in);
        !           728:                if (fgets(buf, sizeof buf, in) == NULL)
        !           729:                {
        !           730:                        fprintf(pgpout,PSTR("ERROR: Hit EOF in header.\n"));
        !           731:                        fclose(in);
        !           732:                        return(13);
        !           733:                }
        !           734: #ifndef STRICT_PEM
        !           735:                if (dpem_buffer(buf,outbuf,&n) == 0 && n == 48)
        !           736:                {       fseek(in, fpos, SEEK_SET);
        !           737:                        break;
        !           738:                }
        !           739: #endif
        !           740:                strip_trailing(buf);
        !           741:        } while (buf[0] != '\n');
        !           742: 
        !           743:        /* create output file as binary */
        !           744:        out = stdout; /* !NULL */
        !           745:        while (file_exists(outfile)  ||  ((out = fopen(outfile, "wb")) == NULL))
        !           746:        {       if (out != NULL)
        !           747:                {       fprintf(pgpout,PSTR("\n\007Ciphertext output file '%s' already exists.  Overwrite (y/N)? "), outfile);
        !           748:                        if (getyesno('n'))
        !           749:                        {       if ((out = fopen(outfile, "wb")) == NULL)
        !           750:                                        fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"));
        !           751:                                else
        !           752:                                        break;
        !           753:                        }
        !           754:                }
        !           755:                else
        !           756:                        fprintf(pgpout,PSTR("\n\007Unable to write ciphertext output file '%s'.\n"));
        !           757:                fprintf(pgpout, PSTR("Enter new name for ciphertext output file: "));
        !           758:                getstring( outfile, 255, TRUE );
        !           759:                if (*outfile == '\0')
        !           760:                        return(-1);
        !           761:                *newname = TRUE;
        !           762:                out = stdout; /* !NULL */
        !           763:        }
        !           764: 
        !           765:        status = pemdecode(in, out);
        !           766: 
        !           767:        fflush(out);
        !           768:        if (ferror(out))
        !           769:                status = -1;
        !           770:        fclose(out);
        !           771:        fclose(in);
        !           772:        return(status);
        !           773: }   /* dpem_file */
        !           774: 
        !           775: /* Entry points for generic interface names */
        !           776: int
        !           777: armor_file (char *infile, char *outfile, char *filename)
        !           778: {
        !           779:        return pem_file (infile, outfile);
        !           780: }
        !           781: 
        !           782: int
        !           783: de_armor_file(char *infile, char *outfile, boolean *newname)
        !           784: {
        !           785:        *newname = FALSE;
        !           786:        return dpem_file (infile, outfile, newname);
        !           787: }
        !           788: 
        !           789: boolean
        !           790: is_armor_file (char *infile)
        !           791: {
        !           792:        return is_pemfile (infile);
        !           793: }
        !           794: 

unix.superglobalmegacorp.com

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