Annotation of pgp/src/armor.c, revision 1.1.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.