|
|
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: §ion,&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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.