|
|
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.