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