|
|
1.1 root 1: /*
2: Pretty Good(tm) Privacy - RSA public key cryptography for the masses
3: Written by Philip Zimmermann, Phil's Pretty Good(tm) Software.
4: Beta test version 1.0 - Last revised 5 Jun 91 by PRZ
5:
6: PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
7: public key cryptosystem with the speed of fast conventional
8: cryptographic algorithms, fast message digest algorithms, data
9: compression, and sophisticated key management. And PGP performs
10: the RSA functions faster than most other software implementations.
11: PGP is RSA public key cryptography for the masses.
12:
13: Uses RSA Data Security, Inc. MD4 Message Digest Algorithm
14: for signatures. Uses the LZHUF algorithm for compression.
15: Uses my own algorithm, BassOmatic, for conventional encryption.
16:
17: (c) Copyright 1990 by Philip Zimmermann. All rights reserved.
18: The author assumes no liability for damages resulting from the use
19: of this software, even if the damage results from defects in this
20: software. No warranty is expressed or implied.
21:
22: All the source code I wrote for PGP is available for free under
23: the "Copyleft" General Public License from the Free Software
24: Foundation. A copy of that license agreement is included in the
25: source release package of PGP. The source code for the MD4
26: functions and the LZHUF functions were separately placed in the
27: public domain by their respective authors. See the PGP User's
28: Guide for more complete information about licensing, patent
29: restrictions on the RSA algorithm, trademarks, copyrights, and
30: export controls. Technical assistance from me is available for
31: an hourly fee.
32:
33:
34: PGP generally zeros its used stack and memory areas before exiting.
35: This avoids leaving sensitive information in RAM where other users
36: could find it later. The RSA library and keygen routines also
37: sanitize their own stack areas. This stack sanitizing has not been
38: checked out under all the error exit conditions, when routines exit
39: abnormally. Also, we must find a way to clear the C I/O library
40: file buffers, and the MSDOS disk buffers.
41:
42: The code in this source file (pgp.c) was hastily written, and it
43: shows. It has a lot of redundant code, developed by ad-hoc
44: "accretion" rather than by well-planned design. It isn't buggy, but
45: it needs to be reorganized to make it cleaner, clearer, and more
46: succinct. Maybe someday. Better and more typical examples of my
47: programming style can be seen in the RSA library code in rsalib.c
48: and keygen.c, and in the BassOmatic conventional encryption routines
49: in basslib.c and related files.
50:
51: If you modify this code, PLEASE preserve the style of indentation
52: used for {begin...end} blocks. It drives me bats to have to deal
53: with more than one style in the same program.
54:
55: */
56:
57:
58: #include <stdlib.h> /* for exit(), malloc(), free(), etc. */
59: #include <stdio.h> /* for printf(), tmpfile(), etc. */
60: #include <time.h> /* for timestamps and performance measurement */
61: #include <string.h> /* for strcat(), etc. */
62: #include <io.h>
63: #include <conio.h> /* for kbhit() */
64:
65: #include "md4.h" /* for MD4 message digest stuff */
66: #include "rsalib.h"
67: #include "rsaio.h"
68: #include "keygen.h"
69: #include "random.h"
70: #include "basslib.h"
71: #include "basslib2.h"
72:
73: #define KEYFRAGSIZE 8 /* # of bytes in key ID modulus fragment */
74: #define SIZEOF_TIMESTAMP 4 /* 32-bit timestamp */
75:
76: /* This macro is for burning sensitive data (byte arrays only) on stack */
77: #define burn(x) fill0(x,sizeof(x))
78:
79: /*
80: **********************************************************************
81: */
82:
83: /* Cipher Type Byte (CTB) definitions follow...*/
84: #define CTB_DESIGNATOR 0x80
85: #define is_ctb(c) (((c) & CTB_DESIGNATOR)==CTB_DESIGNATOR)
86: #define CTB_TYPE_MASK 0x7c
87: #define CTB_LLEN_MASK 0x03
88:
89: /* length of length field of packet, in bytes (1, 2, 4, 8 bytes): */
90: #define ctb_llength(ctb) ((int) 1 << (int) ((ctb) & CTB_LLEN_MASK))
91:
92: #define is_ctb_type(ctb,type) (((ctb) & CTB_TYPE_MASK)==(4*type))
93: #define CTB_BYTE(type,llen) (CTB_DESIGNATOR + (4*type) + llen)
94:
95: #define CTB_PKE_TYPE 1 /* packet encrypted with RSA public key */
96: #define CTB_SKE_TYPE 2 /* packet signed with RSA secret key */
97: #define CTB_MD_TYPE 3 /* message digest packet */
98: #define CTB_CONKEY_TYPE 4 /* conventional key packet */
99: #define CTB_CERT_SECKEY_TYPE 5 /* secret key certificate */
100: #define CTB_CERT_PUBKEY_TYPE 6 /* public key certificate */
101: #define CTB_COMPRESSED_TYPE 8 /* compressed data packet */
102: #define CTB_CKE_TYPE 9 /* conventional-key-encrypted data */
103: #define CTB_LITERAL_TYPE 12 /* raw data */
104:
105: /* Unimplemented CTB packet types follow... */
106: /* #define CTB_RAW1_TYPE 13 /* raw data, with filename, date, crc32 prefix */
107: /* #define CTB_PATTERN_TYPE 14 /* unique file prefix autorecognition pattern */
108: /* #define CTB_EXTENDED_TYPE 15 /* 2-byte CTB, 256 extra CTB types */
109:
110: #define CTB_PKE CTB_BYTE(CTB_PKE_TYPE,1)
111: /* CTB_PKE len16 keyID mpi(RSA(CONKEYPKT)) */
112: /* 1 2 SIZE countbytes()+2 */
113: #define CTB_SKE CTB_BYTE(CTB_SKE_TYPE,1)
114: /* CTB_SKE len16 keyID mpi(RSA(MDPKT)) */
115: /* 1 2 SIZE countbytes()+2 */
116: #define CTB_MD CTB_BYTE(CTB_MD_TYPE,0)
117: /* CTB_MD len8 algorithm MD timestamp */
118: #define CTB_CONKEY CTB_BYTE(CTB_CONKEY_TYPE,0)
119: /* CTB_CONKEY len8 algorithm key */
120: #define CTB_CERT_SECKEY CTB_BYTE(CTB_CERT_SECKEY_TYPE,1)
121: /* CTB_CERT_SECKEY len16 timestamp userID mpi(n) mpi(e) mpi(d) mpi(p) mpi(q) mpi(u) crc16 */
122: #define CTB_CERT_PUBKEY CTB_BYTE(CTB_CERT_PUBKEY_TYPE,1)
123: /* CTB_CERT_PUBKEY len16 timestamp userID mpi(n) mpi(e) crc16 */
124:
125: /* Note that a "secret key compromised" certificate is exactly the same
126: as a public key certificate, but with mpi(e)==0. */
127:
128: #define CTB_CKE CTB_BYTE(CTB_CKE_TYPE,3)
129: /* CTB_CKE ciphertext */
130:
131: #define CTB_LITERAL CTB_BYTE(CTB_LITERAL_TYPE,3)
132: /* CTB_LITERAL data */
133:
134: #define CTB_COMPRESSED CTB_BYTE(CTB_COMPRESSED_TYPE,3)
135: /* CTB_COMPRESSED compressedtext */
136:
137: #define CTB_PATTERN CTB_BYTE(CTB_PATTERN_TYPE,0)
138: /* Unique 40-bit auto-recognition prefix pattern: B8 03 'P' 'R' 'Z' */
139:
140: /* Conventional encryption algorithm selector bytes. */
141: #define DES_ALGORITHM_BYTE 1 /* use the DES (unimplemented) */
142: #define BASS_ALGORITHM_BYTE 2 /* use the BassOmatic */
143:
144: /* Message digest algorithm selector bytes. */
145: #define MD4_ALGORITHM_BYTE 1 /* MD4 message digest algorithm */
146:
147: /* Data compression algorithm selector bytes. */
148: #define LZH_ALGORITHM_BYTE 1 /* LZH compression algorithm */
149:
150: #define is_secret_key(ctb) is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE)
151:
152: #define MAX_SIGCERT_LENGTH (1+2 + KEYFRAGSIZE + 2+MAX_BYTE_PRECISION)
153:
154: #define MAX_KEYCERT_LENGTH (1+2+4+256 + 5*(2+MAX_BYTE_PRECISION))
155:
156:
157: /* Global filenames and system-wide file extensions... */
158: char CTX_EXTENSION[] = ".ctx";
159: char PUB_EXTENSION[] = ".pub";
160: char SEC_EXTENSION[] = ".sec";
161: char SCRATCH_CTX_FILENAME[] = "_pgptemp.ctx";
162: char SCRATCH_PTX_FILENAME[] = "_pgptemp.ptx";
163: char SCRATCH_KEYRING_FILENAME[] = "_tmpring.pub"; /* gets modified */
164: char PGPPATH[] = "PGPPATH"; /* environmental variable */
165:
166: /* These files use the environmental variable PGPPATH as a default path: */
167: char PUBLIC_KEYRING_FILENAME[32] = "keyring.pub";
168: char SECRET_KEYRING_FILENAME[32] = "keyring.sec";
169: char RANDSEED_FILENAME[32] = "randseed.pgp";
170:
171: boolean verbose = FALSE; /* -l option: display maximum information */
172:
173: /*
174: **********************************************************************
175: */
176:
177:
178:
179: boolean pkzipSignature( byte *header )
180: {
181: /*
182: ** Return TRUE if header begins with the PKzip signature
183: ** Useful for MSDOS only.
184: */
185:
186: if ((header[0] == 'P') && (header[1] == 'K')
187: && (header[2] == '\03') && (header[3] == '\04'))
188: return(TRUE);
189: return(FALSE);
190: } /* pkzipSignature */
191:
192:
193: /*
194: ** Convert to or from external byte order.
195: ** Note that hilo_swap does nothing if this is a LSB-first CPU.
196: */
197:
198: #define convert2(x,lx) hilo_swap( (byteptr)&(x), (lx) )
199: #define convert(x) convert2( (x), sizeof(x) )
200:
201: word16 fetch_word16(byte *buf)
202: /* Fetches a 16-bit word from where byte pointer is pointing.
203: buf points to external-format byteorder array, assuming LSB-first.
204: */
205: { word16 w0,w1;
206: w0 = *buf++;
207: w1 = *buf++;
208: return((w1<<8) + w0);
209: } /* fetch_word16 */
210:
211:
212: void get_timestamp(byte *timestamp)
213: /* Returns timestamp byte array, in internal byteorder */
214: { word32 t;
215: t = time(0);
216: timestamp[0] = t; /* fill array in external byte order */
217: timestamp[1] = t>>8;
218: timestamp[2] = t>>16;
219: timestamp[3] = t>>24;
220: /* Note that hilo_swap does nothing if this is a LSB-first CPU. */
221: hilo_swap(timestamp,4); /* convert to internal byteorder */
222: } /* get_timestamp */
223:
224:
225: void CToPascal(char *s)
226: { /* "xyz\0" --> "\3xyz" ... converts C string to Pascal string */
227: int i,j;
228: j = string_length(s);
229: for (i=j; i!=0; i--)
230: s[i] = s[i-1]; /* move everything 1 byte to the right */
231: s[0] = j; /* Pascal length byte at beginning */
232: } /* CToPascal */
233:
234:
235: void PascalToC( char *s )
236: { /* "\3xyz" --> "xyz\0" ... converts Pascal string to C string */
237: int i,j;
238: for (i=0,j=s[0]; i<j; i++)
239: s[i] = s[i+1]; /* move everything 1 byte to the left */
240: s[i] = '\0'; /* append C string terminator */
241: } /* PascalToC */
242:
243:
244:
245: int date_ymd(word32 *tstamp, int *year, int *month, int *day)
246: /* Given timestamp as seconds elapsed since 1970 Jan 1 00:00:00,
247: returns year (1970-2106), month (1-12), day (1-31).
248: Not valid for dates after 2100 Feb 28 (no leap day that year).
249: Also returns day of week (0-6) as functional return.
250: */
251: { word32 days,y;
252: int m,d,i;
253: static short mdays[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
254: days = (*tstamp)/86400UL; /* day 0 is 1970/1/1 */
255: days -= 730UL; /* align days relative to 1st leap year, 1972 */
256: y = ((days*4UL)/1461UL); /* 1972 is year 0 */
257: /* reduce to days elapsed since 1/1 last leap year: */
258: d = days - ((y/4UL)*1461UL);
259: *year = y+1972;
260: for (i=0; i<48; i++) /* count months 0-47 */
261: { m = i % 12;
262: d -= mdays[m] + (i==1); /* i==1 is the only leap month */
263: if (d < 0)
264: { d += mdays[m] + (i==1);
265: break;
266: }
267: }
268: *month = m+1;
269: *day = d+1;
270: i = (days-2UL) % 7UL; /* compute day of week 0-6 */
271: return(i); /* returns weekday 0-6; 0=Sunday, 6=Saturday */
272: } /* date_ymd */
273:
274:
275:
276: void show_date(word32 *tstamp)
277: { int m,d,y;
278: static char *month[12] =
279: {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
280: date_ymd(tstamp,&y,&m,&d);
281: fprintf(stderr,"%2d-%s-%02d", d, month[m-1], y % 100);
282: } /* show_date */
283:
284:
285:
286: boolean file_exists(char *filename)
287: /* Returns TRUE iff file is can be opened for reading. */
288: { FILE *f;
289: /* open file f for read, in binary (not text) mode...*/
290: if ((f = fopen(filename,"rb")) == NULL)
291: return(FALSE);
292: fclose(f);
293: return(TRUE);
294: } /* file_exists */
295:
296:
297:
298: #define diskbufsize 1024
299:
300: int wipeout(FILE *f)
301: { /* Completely overwrite and erase file, so that no sensitive
302: information is left on the disk.
303: NOTE: File MUST be open for read/write.
304: */
305:
306: long flength;
307: int count;
308: byte textbuf[diskbufsize];
309:
310: fseek(f, 0L, SEEK_END);
311: flength = ftell(f);
312: rewind(f);
313:
314: fill0(textbuf,diskbufsize);
315: while (flength > 0L)
316: { /* write zeros to the whole file... */
317: if (flength < (word32) diskbufsize)
318: count = flength;
319: else
320: count = diskbufsize;
321: fwrite(textbuf,1,count,f);
322: flength -= count;
323: }
324: rewind(f); /* maybe this isn't necessary */
325: return(0); /* normal return */
326: } /* wipeout */
327:
328:
329: int wipefile(char *filename)
330: { /* Completely overwrite and erase file, so that no sensitive
331: information is left on the disk.
332: */
333: FILE *f;
334: /* open file f for read/write, in binary (not text) mode...*/
335: if ((f = fopen(filename,"rb+")) == NULL)
336: return(-1); /* error - file can't be opened */
337: wipeout(f);
338: fclose(f);
339: return(0); /* normal return */
340: } /* wipefile */
341:
342:
343:
344: #define strhas(s,c) (strchr((s),(c)) != NULL)
345:
346: boolean strhasany( char *s1, char *s2 )
347: { /* Searches s1 for any of the characters in s2.
348: Returns TRUE if found.
349: */
350: while (*s2)
351: { if (strhas(s1,*s2))
352: return(TRUE);
353: s2++;
354: }
355: return(FALSE);
356: } /* strhasany */
357:
358:
359: boolean strcontains( char *s1, char *s2 )
360: { /*
361: ** Searches s1 for s2, without case sensitivity.
362: ** Return TRUE if found.
363: **
364: ** If s2 is an empty string then return TRUE. This is because,
365: ** at least in the world of mathematics, the empty set is contained
366: ** in all other sets. The Microsoft C version 6.0 strstr function
367: ** behaves this way but version 5.1 does not, so we need to
368: ** explicitly test for the situation. -- ALH 91/2/17
369: */
370:
371: if (s2[0] != '\0')
372: {
373: char buf1[256], buf2[256]; /* scratch buffers */
374:
375: strncpy( buf1, s1, 256 ); strlwr( buf1 ); /* converts to lower case */
376: strncpy( buf2, s2, 256 ); strlwr( buf2 ); /* converts to lower case */
377:
378: if (strstr( buf1, buf2 ) == NULL)
379: return( FALSE ); /* string not found */
380: }
381: return(TRUE);
382: } /* strcontains */
383:
384:
385: void translate_spaces(char *s)
386: /* Changes all the underlines to spaces in a string. */
387: { while (strchr(s,'_') != NULL)
388: *strchr(s,'_') = ' ';
389: }
390:
391:
392: boolean no_extension(char *filename)
393: /* Returns TRUE if user left off file extension, allowing default. */
394: { if (strrchr(filename,'.')==NULL)
395: return(TRUE);
396: /* see if the last '.' is followed by a backslash...*/
397: if (*(strrchr(filename,'.')+1) == '\\')
398: return(TRUE); /* just a "..\filename" construct */
399: return(FALSE); /* user specified extension, even if a blank one */
400: } /* no_extension */
401:
402:
403: void drop_extension(char *filename)
404: { /* deletes trailing ".xxx" file extension after the period. */
405: if (!no_extension(filename))
406: *strrchr(filename,'.') = '\0';
407: } /* drop_extension */
408:
409:
410: void default_extension(char *filename, char *extension)
411: { /* append filename extension if there isn't one already. */
412: if (no_extension(filename))
413: strcat(filename,extension);
414: } /* default_extension */
415:
416:
417: void force_extension(char *filename, char *extension)
418: { /* change the filename extension. */
419: drop_extension(filename); /* out with the old */
420: strcat(filename,extension); /* in with the new */
421: } /* force_extension */
422:
423:
424: boolean getyesno(char default_answer)
425: { /* Get yes/no answer from user, returns TRUE for yes, FALSE for no. */
426: char buf[8];
427: while (keypress()) /* flush typahead buffer */
428: getkey();
429: getstring(buf,6,TRUE); /* echo keyboard input */
430: if (strlen(buf)==0) /* if user didn't give an answer... */
431: buf[0] = default_answer; /* assume default answer */
432: buf[0] = tolower(buf[0]);
433: return(buf[0]=='y');
434: } /* getyesno */
435:
436:
437: void maybe_force_extension(char *filename, char *extension)
438: { /* if user consents to it, change the filename extension. */
439: char newname[64];
440: if (!strcontains(filename,extension))
441: { strcpy(newname,filename);
442: force_extension(newname,extension);
443: if (!file_exists(newname))
444: { fprintf(stderr,"\nShould '%s' be renamed to '%s' [Y/n]? ",
445: filename,newname);
446: if (getyesno('y'))
447: rename(filename,newname);
448: }
449: }
450: } /* maybe_force_extension */
451:
452:
453: /*---------------------------------------------------------------------*/
454: /* Begin uuencode routines.
455: This converts a binary file into printable ASCII characters, in a
456: form compatible with the Unix uuencode utility.
457: This makes it easier to send encrypted files over a 7-bit channel.
458: */
459:
460: /* ENC is the basic 1 character encoding function to make a char printing */
461: #define ENC(c) (((c) & 077) + ' ')
462:
463: /*
464: * output one group of 3 bytes, pointed at by p, on file f.
465: */
466: void outdec(char *p, FILE *f)
467: {
468: int c1, c2, c3, c4;
469:
470: c1 = *p >> 2;
471: c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
472: c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
473: c4 = p[2] & 077;
474: putc(ENC(c1), f);
475: putc(ENC(c2), f);
476: putc(ENC(c3), f);
477: putc(ENC(c4), f);
478: } /* outdec */
479:
480:
481: /* fr: like read but stdio */
482: int fr(FILE *fd, char *buf, int cnt)
483: {
484: int c, i;
485:
486: for (i=0; i<cnt; i++)
487: {
488: c = getc(fd);
489: if (c == EOF)
490: return(i);
491: buf[i] = c;
492: }
493: return (cnt);
494: } /* fr */
495:
496:
497: /*
498: * copy from in to out, uuencoding as you go along.
499: */
500: void uuencode(FILE *in, FILE *out)
501: {
502: char buf[80];
503: int i, n;
504:
505: for (;;)
506: { /* 1 (up to) 45 character line */
507: n = fr(in, buf, 45);
508: putc(ENC(n), out);
509:
510: for (i=0; i<n; i += 3)
511: outdec(&buf[i], out);
512:
513: putc('\n', out);
514: if (n <= 0)
515: break;
516: }
517: } /* uuencode */
518:
519:
520: int uue_file(char *infile, char *outfile)
521: { /* translates infile to uuencode format, writing to outfile */
522: FILE *in,*out;
523: int mode;
524:
525: if (verbose)
526: fprintf(stderr,"Converting output to uuecode format.\n");
527:
528: /* open input file as binary */
529: if ((in = fopen(infile,"rb")) == NULL)
530: {
531: return(1);
532: }
533:
534: /* open output file as text */
535: if ((out = fopen(outfile,"w")) == NULL)
536: { fclose(in);
537: return(1);
538: }
539:
540: mode = 0666; /* Assume a reasonable dummy default for file mode */
541:
542: fprintf(out,"begin %o %s\n", mode, infile);
543:
544: uuencode(in, out);
545:
546: fprintf(out,"end\n");
547: fclose(out);
548: fclose(in);
549:
550: return(0);
551: } /* uue_file */
552:
553:
554: /* End uuencode routines. */
555:
556: /* uudecode routines.
557: Portions derived from unix uudecode utility by Mark Horton.
558: */
559:
560: #define SUMSIZE 64
561: #define DEC(c) (((c) - ' ') & 077) /* single character decode */
562:
563:
564: int uud_buffer(char *inbuf, char *outbuf, int *outlength)
565: {
566: char *bp;
567: boolean has_checksum=FALSE;
568:
569: register int j;
570: register int n;
571: int checksum;
572: int status;
573:
574:
575: status = 0;
576: *outlength = 0;
577:
578: /* Pad end of lines in case some editor truncated trailing
579: spaces */
580:
581: for (n=0; n<79; n++) /* search for first \r, \n or \000 */
582: {
583: if (inbuf[n]=='\176') /* If BITNET made a twiddle, */
584: inbuf[n]='\136'; /* we make a caret */
585: if (inbuf[n]=='\r' || inbuf[n]=='\n' || inbuf[n]=='\000')
586: break;
587: if ((inbuf[n] < '\040') || (inbuf[n] > '\137'))
588: status = -1; /* illegal uudecode character */
589: }
590: for (; n<79; n++) /* when found, fill rest of line with space */
591: inbuf[n]=' ';
592:
593: inbuf[79]=0; /* terminate new string */
594:
595: checksum = 0;
596: n = DEC(inbuf[0]);
597: if (n == 0)
598: return(0); /* 0 bytes on a line?? Must be the last line */
599:
600: if (status)
601: return(status); /* bad character, out of range */
602:
603: bp = &inbuf[1];
604:
605: /* FOUR input characters go into each THREE output charcters */
606:
607: while (n >= 4)
608: {
609: j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
610: checksum += j;
611: outbuf[(*outlength)++]=j;
612: j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
613: checksum += j;
614: outbuf[(*outlength)++]=j;
615: j = DEC(bp[2]) << 6 | DEC(bp[3]);
616: checksum += j;
617: outbuf[(*outlength)++]=j;
618: checksum = checksum % SUMSIZE;
619: bp += 4;
620: n -= 3;
621: }
622:
623: j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
624: checksum += j;
625: if (n >= 1)
626: outbuf[(*outlength)++]=j;
627: j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
628: checksum += j;
629: if (n >= 2)
630: outbuf[(*outlength)++]=j;
631: j = DEC(bp[2]) << 6 | DEC(bp[3]);
632: checksum += j;
633: if (n >= 3)
634: outbuf[(*outlength)++]=j;
635: checksum = checksum % SUMSIZE;
636: bp += 4;
637: n -= 3;
638:
639: /* The line has been decoded; now check that sum */
640:
641: has_checksum |= !isspace(*bp);
642: if (has_checksum) /* Is there a checksum at all?? */
643: if (checksum != DEC(*bp)) /* Does that checksum match? */
644: return(-2); /* checksum error */
645:
646: return(status); /* normal return */
647:
648: } /* uud_buffer */
649:
650: /*
651: * Copy from in to out, decoding as you go.
652: * If a return or newline is encountered too early in a line, it is
653: * assumed that means that some editor has truncated trailing spaces.
654: */
655: int uudecode(FILE *in, FILE *out)
656: {
657: char inbuf[81];
658: char outbuf[81];
659: char *bp;
660: boolean has_checksum=FALSE;
661:
662: register int j;
663: int n, status;
664: int checksum, line;
665:
666: for (line = 1; ; line++) /* for each input line */
667: {
668: if (fgets(inbuf, sizeof inbuf, in) == NULL)
669: {
670: fprintf(stderr,"ERROR: uudecode input ended unexpectedly!\n");
671: return(18);
672: }
673:
674: status = uud_buffer(inbuf,outbuf,&n);
675:
676: if (status == -1)
677: fprintf(stderr,"ERROR: bad uudecode character decoding line %d.\n", line);
678: if (status == -2)
679: fprintf(stderr,"ERROR: checksum mismatch decoding line %d.\n", line);
680: if (n==0) /* zero-length line is the end. */
681: break;
682:
683: fwrite(outbuf,1,n,out);
684:
685: } /* line */
686:
687: return(0); /* normal return */
688: } /* uudecode */
689:
690:
691: boolean is_uufile(char *infile)
692: {
693: FILE *in;
694: char inbuf[80];
695: char outbuf[80];
696: int i, n, status;
697:
698: if ((in = fopen(infile, "r")) == NULL)
699: { /* can't open file */
700: return(FALSE);
701: }
702:
703: /* search file for header line */
704: for (i=0; i<50; i++) /* give up after 50 lines of garbage */
705: {
706: if (fgets(inbuf, sizeof inbuf, in) == NULL)
707: break;
708: else
709: {
710: if (strncmp(inbuf, "begin ", 6) == 0)
711: {
712: if (fgets(inbuf, sizeof inbuf, in) == NULL)
713: break;
714: status = uud_buffer(inbuf,outbuf,&n);
715: if (status < 0)
716: break;
717: fclose(in);
718: return(TRUE);
719: }
720: }
721: }
722:
723: fclose(in);
724: return(FALSE);
725:
726: } /* is_uufile */
727:
728:
729: int uud_file(char *infile, char *outfile)
730: {
731: FILE *in, *out;
732: int mode; /* file's mode (from header) */
733: long filesize; /* theoretical file size (from header) */
734: char buf[80];
735: int status;
736:
737: if ((in = fopen(infile, "r")) == NULL)
738: {
739: fprintf(stderr,"ERROR: can't find %s\n", infile);
740: return(10);
741: }
742:
743: /* Loop through file, searching for header. Decode anything with a
744: header, complain if there where no headers. */
745:
746: /* search file for header line */
747: for (;;)
748: {
749: if (fgets(buf, sizeof buf, in) == NULL)
750: {
751: fprintf(stderr,"ERROR: no `begin' line!\n");
752: fclose(in);
753: return(12);
754: }
755: if (strncmp(buf, "begin ", 6) == 0)
756: break;
757: }
758:
759: /* Ignore filename and mode. Use outfile instead of dest. */
760: /* sscanf(buf, "begin %o %s", &mode, dest); */
761:
762: /* create output file */
763: if ((out = fopen(outfile, "wb")) == NULL)
764: {
765: fprintf(stderr,"ERROR: can't open output file %s\n", outfile);
766: fclose(in);
767: return(15);
768: }
769:
770: status = uudecode(in, out);
771: if (status != 0)
772: { fclose(in);
773: fclose(out);
774: return(status);
775: }
776:
777: if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
778: { /* don't be overly picky about newline ^ */
779: fprintf(stderr,"ERROR: no `end' line\n");
780: fclose(in);
781: fclose(out);
782: return(16);
783: }
784:
785: if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
786: {
787: sscanf(buf, "size %ld", &filesize);
788: if (ftell(out) != filesize)
789: {
790: fprintf(stderr,"ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out));
791: return(17);
792: }
793: }
794: fclose(out);
795: fclose(in);
796: return(0); /* normal return */
797: } /* uud_file */
798:
799:
800: /* End uudecode routines. */
801: /*---------------------------------------------------------------------*/
802:
803:
804:
805: boolean legal_ctb(byte ctb)
806: { /* Used to determine if nesting should be allowed. */
807: boolean legal;
808: byte ctbtype;
809: if (!is_ctb(ctb)) /* not even a bonafide CTB */
810: return(FALSE);
811: /* Sure hope CTB internal bit definitions don't change... */
812: ctbtype = (ctb & CTB_TYPE_MASK) >> 2;
813: /* Only allow these CTB types to be nested... */
814: legal = (
815: (ctbtype==CTB_PKE_TYPE)
816: || (ctbtype==CTB_SKE_TYPE)
817: || (ctbtype==CTB_CERT_SECKEY_TYPE)
818: || (ctbtype==CTB_CERT_PUBKEY_TYPE)
819: || (ctbtype==CTB_LITERAL_TYPE)
820: || (ctbtype==CTB_COMPRESSED_TYPE)
821: || (ctbtype==CTB_CKE_TYPE)
822: /* || (ctbtype==CTB_CONKEY_TYPE) */
823: /* || (ctbtype==CTB_MD_TYPE) */
824: );
825: return(legal);
826: } /* legal_ctb */
827:
828:
829: /*======================================================================*/
830:
831: /* MDfile0(MD, f)
832: ** Computes and returns the message digest from a file position to eof.
833: ** Uses RSA Data Security, Inc. MD4 Message Digest Algorithm.
834: */
835: int MDfile0(MDstruct *MD, FILE *f)
836: { byte X[64];
837: int bytecount;
838:
839: MDbegin(MD);
840: /* Process 512 bits, or 64 bytes, at a time... */
841: while ((bytecount = fread(X, 1, 64, f)) != 0)
842: MDupdate(MD, X, bytecount<<3); /* pass bitcount */
843: MDupdate(MD, X, 0); /* finish with a bitcount of 0 */
844: /* MDprint(MD); */
845:
846: return(0); /* normal return */
847: } /* MDfile0 */
848:
849:
850: /* MDfile(MD, filename)
851: ** Computes and returns the message digest for a specified file.
852: */
853: int MDfile(MDstruct *MD, char *filename)
854: { FILE *f;
855: f = fopen(filename,"rb");
856: if (f == NULL)
857: { fprintf(stderr,"Can't open file '%s'\n",filename);
858: return(-1); /* error return */
859: }
860: MDfile0(MD, f);
861: fclose(f);
862: return(0); /* normal return */
863: } /* MDfile */
864:
865:
866: /* MD_of_buffer(MD, s, len)
867: ** Computes and returns the message digest for buffer s.
868: ** len is the length in bytes of buffer s.
869: ** Uses RSA Data Security, Inc. MD4 Message Digest Algorithm.
870: */
871: void MD_of_buffer(MDstruct *MD, byte *s, int len)
872: { int i;
873:
874: MDbegin(MD);
875: /* Process 512 bits, or 64 bytes, at a time... */
876: for (i=0; i+64<=len; i+=64)
877: MDupdate(MD, s+i, 512);
878: MDupdate(MD, s+i, (len-i)<<3); /* finish with short block */
879: /* MDprint(MD); */
880:
881: } /* MD_of_buffer */
882:
883:
884: boolean equal_buffers(byte *buf1, byte *buf2, word16 count)
885: /* Compares two byte buffers. */
886: { while (count--)
887: if (*buf1++ != *buf2++)
888: return(FALSE); /* mismatch. */
889: return(TRUE); /* compares OK */
890: } /* equal_buffers */
891:
892:
893: char *buildfilename(char *result, char *fname)
894: /* Builds a filename with a complete path specifier from the environmental
895: variable PGPPATH. Assumes MSDOS pathname conventions.
896: */
897: { char *s = getenv(PGPPATH);
898: if (strlen(s) > 50) /* too long to use */
899: s = "";
900: strcpy(result,s);
901: if (strlen(result) != 0)
902: if (result[strlen(result)-1] != '\\')
903: strcat(result,"\\");
904: strcat(result,fname);
905: return(result);
906: } /* buildfilename */
907:
908:
909: int strong_pseudorandom(byte *buf, int bufsize)
910: /* Reads BassOmatic random key and random number seed from file,
911: cranks the the seed through the bassrand strong pseudorandom
912: number generator, and writes them back out. This is used for
913: generation of cryptographically strong pseudorandom numbers.
914: This is mainly to save the user the trouble of having to
915: type in lengthy keyboard sequences for generation of truly
916: random numbers every time we want to make a random BassOmatic
917: session key. This pseudorandom generator will only work if
918: the file containing the random seed exists and is not empty.
919: If it doesn't exist, it will be automatically created.
920: If it exists and is empty or nearly empty, it will not be used.
921: */
922: { char seedfile[64]; /* Random seed filename */
923: FILE *f;
924: byte key[64]; /* not to exceed 256 byes in length */
925: byte seed[256]; /* not to exceed 256 byes in length */
926: int i;
927: word32 tstamp; byte *timestamp = (byte *) &tstamp;
928:
929: buildfilename(seedfile,RANDSEED_FILENAME);
930:
931: if (!file_exists(seedfile)) /* No seed file. Start one... */
932: { f = fopen(seedfile,"wb"); /* open for writing binary */
933: if (f==NULL) /* failed to create seedfile */
934: return(-1); /* error: no random number seed file available */
935: fclose(f); /* close new empty seed file */
936: /* kickstart the generator with true random numbers */
937: fprintf(stderr,"Initializing random seed file...");
938: randaccum(8*(sizeof(key)+32));
939: for (i=1; i<sizeof(key); i++)
940: key[i] ^= randombyte();
941: for (i=0; i<sizeof(seed); i++)
942: seed[i] ^= randombyte();
943: } /* seedfile does not exist */
944:
945: else /* seedfile DOES exist. Open it and read it. */
946: { f = fopen(seedfile,"rb"); /* open for reading binary */
947: if (f==NULL) /* did open fail? */
948: return(-1); /* error: no random number seed file available */
949: /* read BassOmatic random generator key */
950: if (fread(key,1,sizeof(key),f) < sizeof(key)) /* empty file? */
951: { /* Empty or nearly empty file means don't use it. */
952: fclose(f);
953: return(-1); /* error: no random number seed file available */
954: }
955: else
956: fread(seed,1,sizeof(seed),f); /* read pseudorandom seed */
957: fclose(f);
958: } /* seedfile exists */
959:
960:
961: get_timestamp(timestamp);
962: for (i=0; i<4; i++)
963: key[i+1] ^= timestamp[i];
964:
965: key[0] = 0x0f; /* BassOmatic key control byte */
966:
967: /* Initialize, key, and seed the BassOmatic pseudorandom generator: */
968: initbassrand(key, sizeof(key), seed, sizeof(seed));
969:
970: /* Note that the seed will be cycled thru BassOmatic once before use */
971:
972: /* Now fill the user's buffer with gobbledygook... */
973: while (bufsize--)
974: *buf++ = bassrand() ^ randombyte();
975:
976: /* now cover up evidence of what user got */
977: for (i=1; i<sizeof(key); i++)
978: key[i] ^= bassrand() ^ randombyte();
979: for (i=0; i<sizeof(seed); i++)
980: seed[i] = bassrand() ^ randombyte();
981:
982: closebass(); /* close BassOmatic random number generator */
983:
984: f = fopen(seedfile,"wb"); /* open for writing binary */
985: if (f==NULL) /* did open fail? */
986: return(-1); /* error: no random number seed file available */
987: /* Now at start of file again */
988: fwrite(key,1,sizeof(key),f);
989: fwrite(seed,1,sizeof(seed),f);
990: fclose(f);
991: burn(key); /* burn sensitive data on stack */
992: burn(seed); /* burn sensitive data on stack */
993: return(0); /* normal return */
994: } /* strong_pseudorandom */
995:
996:
997:
998: int make_random_basskey(byte *key, int keybytes)
999: /* Make a keybytes-byte random BassOmatic key, plus 1 key control byte.
1000: The byte count returned includes key control byte.
1001: */
1002: { int count;
1003:
1004: key[0] = 0x1f; /* Default is Military grade BassOmatic key control byte */
1005: if (keybytes <= 24)
1006: key[0] = 0x12; /* Commercial grade BassOmatic key control byte */
1007: if (keybytes <= 16)
1008: key[0] = 0x00; /* Casual grade BassOmatic key control byte */
1009:
1010: if (strong_pseudorandom(key+1, keybytes) == 0)
1011: return(keybytes+1); /* return length of key, including control byte */
1012:
1013: fprintf(stderr,"Preparing random conventional crypto session key...");
1014:
1015: randaccum(keybytes*8); /* get some random key bits */
1016:
1017: count=0;
1018: while (++count <= keybytes)
1019: key[count] = randombyte();
1020:
1021: return(count+1); /* return length of key, including control byte */
1022:
1023: } /* make_random_basskey */
1024:
1025:
1026:
1027: void copyfile(FILE *f, FILE *g, word32 longcount)
1028: { /* copy file f to file g, for longcount bytes */
1029: int count;
1030: byte textbuf[diskbufsize];
1031: do /* read and write the whole file... */
1032: {
1033: if (longcount < (word32) diskbufsize)
1034: count = longcount;
1035: else
1036: count = diskbufsize;
1037: count = fread(textbuf,1,count,f);
1038: if (count>0)
1039: { fwrite(textbuf,1,count,g);
1040: longcount -= count;
1041: }
1042: /* if text block was short, exit loop */
1043: } while (count==diskbufsize);
1044: burn(textbuf); /* burn sensitive data on stack */
1045: } /* copyfile */
1046:
1047:
1048: word32 getpastlength(byte ctb, FILE *f)
1049: /* Returns the length of a packet according to the CTB and
1050: the length field. */
1051: { word32 length;
1052: int llength; /* length of length */
1053: byte buf[8];
1054:
1055: fill0(buf,sizeof(buf));
1056: length = 0L;
1057: /* Use ctb length-of-length field... */
1058: llength = ctb_llength(ctb); /* either 1, 2, 4, or 8 */
1059: if (llength==8) /* 8 means no length field, assume huge length */
1060: return(-1L); /* return huge length */
1061:
1062: /* now read in the actual length field... */
1063: if (fread((byteptr) buf,1,llength,f) < llength)
1064: return (-2L); /* error -- read failure or premature eof */
1065: /* convert length from external LSB-first format... */
1066: while (llength--)
1067: { length <<= 8;
1068: length += buf[llength];
1069: }
1070: return(length);
1071: } /* getpastlength */
1072:
1073:
1074:
1075: int bass_file(byte *basskey, int lenbasskey, boolean decryp,
1076: FILE *f, FILE *g)
1077: /* Use BassOmatic in cipher feedback (CFB) mode to encrypt
1078: or decrypt a file. Encrypted key check bytes determine
1079: if correct BassOmatic key was used to decrypt ciphertext.
1080: */
1081: { int count;
1082: byte textbuf[diskbufsize], iv[256];
1083: #define KEYCHECKLENGTH 4
1084:
1085: /* init CFB BassOmatic key */
1086: fill0(iv,256); /* define initialization vector IV as 0 */
1087: if ( initcfb(iv,basskey,lenbasskey,decryp) < 0 )
1088: return(-1); /* Error return should be impossible. */
1089:
1090: if (!decryp) /* encrypt-- insert key check bytes */
1091: { /* key check bytes are 2 copies of 16 random bits */
1092: textbuf[0] = randombyte();
1093: textbuf[1] = randombyte();
1094: textbuf[2] = textbuf[0];
1095: textbuf[3] = textbuf[1];
1096: basscfb(textbuf,KEYCHECKLENGTH);
1097: fwrite(textbuf,1,KEYCHECKLENGTH,g);
1098: }
1099: else /* decrypt-- check for key check bytes */
1100: { /* See if there are 2 copies of 16 random bits */
1101: count = fread(textbuf,1,KEYCHECKLENGTH,f);
1102: if (count==KEYCHECKLENGTH)
1103: { basscfb(textbuf,KEYCHECKLENGTH);
1104: if ((textbuf[0] != textbuf[2])
1105: || (textbuf[1] != textbuf[3]))
1106: { return(-2); /* bad key error */
1107: }
1108: }
1109: else /* file too short for key check bytes */
1110: return(-3); /* error of the weird kind */
1111: }
1112:
1113:
1114: do /* read and write the whole file in CFB mode... */
1115: { count = fread(textbuf,1,diskbufsize,f);
1116: if (count>0)
1117: { basscfb(textbuf,count);
1118: fwrite(textbuf,1,count,g);
1119: }
1120: /* if text block was short, exit loop */
1121: } while (count==diskbufsize);
1122:
1123: closebass(); /* release BassOmatic resources */
1124: burn(textbuf); /* burn sensitive data on stack */
1125: return(0); /* should always take normal return */
1126: } /* bass_file */
1127:
1128:
1129:
1130: int read_mpi(unitptr r, FILE *f, boolean adjust_precision, boolean scrambled)
1131: /* Read a mutiprecision integer from a file.
1132: adjust_precision is TRUE iff we should call set_precision to the
1133: size of the number read in.
1134: scrambled is TRUE iff field is encrypted (protects secret key fields).
1135: Returns the bitcount of the number read in, or returns a negative
1136: number if an error is detected.
1137: */
1138: { byte buf[MAX_BYTE_PRECISION+2];
1139: int count;
1140: word16 bytecount,bitcount,lowcount,highcount;
1141:
1142: mp_init(r,0);
1143:
1144: if ((count = fread(buf,1,2,f)) < 2)
1145: return (-1); /* error -- read failure or premature eof */
1146:
1147: /* Assumes external format is LSB-first */
1148: bitcount = (((word16) buf[1]) << 8) + (word16) buf[0];
1149: if (bits2units(bitcount) > global_precision)
1150: return(-1); /* error -- possible corrupted bitcount */
1151:
1152: bytecount = bits2bytes(bitcount);
1153:
1154: count = fread(buf+2,1,bytecount,f);
1155: if (count < bytecount)
1156: return(-1); /* error -- premature eof */
1157:
1158: if (scrambled) /* decrypt the field */
1159: basscfb(buf+2,bytecount);
1160:
1161: /* We assume that the bitcount prefix we read is an exact
1162: bitcount, not rounded up to the next byte boundary.
1163: Otherwise we would have to call mpi2reg, then call
1164: countbits, then call set_precision, then recall mpi2reg
1165: again.
1166: */
1167: if (adjust_precision && bytecount)
1168: { /* set the precision to that specified by the number read. */
1169: set_precision(bits2units(bitcount+SLOP_BITS));
1170: /* Now that precision is optimally set, call mpi2reg */
1171: }
1172:
1173: mpi2reg(r,buf); /* convert to internal format */
1174: burn(buf); /* burn sensitive data on stack */
1175: return (bitcount);
1176: } /* read_mpi */
1177:
1178:
1179:
1180: void write_mpi(unitptr n, FILE *f, boolean scrambled)
1181: /* Write a multiprecision integer to a file.
1182: scrambled is TRUE iff we should scramble field on the way out,
1183: which is used to protect secret key fields.
1184: */
1185: { byte buf[MAX_BYTE_PRECISION+2];
1186: short bytecount;
1187: bytecount = reg2mpi(buf,n);
1188: if (scrambled) /* encrypt the field, skipping over the bitcount */
1189: basscfb(buf+2,bytecount);
1190: fwrite(buf,1,bytecount+2,f);
1191: burn(buf); /* burn sensitive data on stack */
1192: } /* write_mpi */
1193:
1194:
1195:
1196: void showkeyID(byte *buf)
1197: /* Print key fragment, which is an abbreviation or "fingerprint"
1198: of the key.
1199: Show LEAST significant 64 bits (KEYFRAGSIZE bytes) of modulus,
1200: LSB last. Yes, that's LSB LAST.
1201: */
1202: { short i,j;
1203: /* fputc('[',stderr); */
1204: j = KEYFRAGSIZE;
1205: for (i=KEYFRAGSIZE-1; i>=0; i--) /* print LSB last */
1206: { if (--j < 3) /* only show bottom 3 bytes of keyID */
1207: fprintf(stderr,"%02X",buf[i]);
1208: }
1209: /* fputc(']',stderr); */
1210: } /* showkeyID */
1211:
1212:
1213:
1214: void extract_keyID(byteptr keyID, unitptr n)
1215: /* Extract key fragment from modulus n. keyID byte array must be
1216: at least KEYFRAGSIZE bytes long.
1217: */
1218: { byte buf[MAX_BYTE_PRECISION+2];
1219: short i, j;
1220:
1221: fill0(buf,KEYFRAGSIZE+2); /* in case n is too short */
1222: reg2mpi(buf,n); /* MUST be at least KEYFRAGSIZE long */
1223: /* For low-byte-first keyID format, start of keyID is: */
1224: i = 2; /* skip over the 2 bytes of bitcount */
1225: for (j=0; j<KEYFRAGSIZE; )
1226: keyID[j++] = buf[i++];
1227:
1228: } /* extract_keyID */
1229:
1230:
1231:
1232: void writekeyID(unitptr n, FILE *f)
1233: /* Write message prefix keyID to a file.
1234: n is key modulus from which to extract keyID.
1235: */
1236: { byte keyID[KEYFRAGSIZE];
1237: extract_keyID(keyID, n);
1238: fwrite(keyID,1,KEYFRAGSIZE,f);
1239: } /* writekeyID */
1240:
1241:
1242:
1243: void showkeyID2(unitptr n)
1244: /* Derive the key abbreviation fragment from the modulus n, and print it.
1245: n is key modulus from which to extract keyID.
1246: */
1247: { byte keyID[KEYFRAGSIZE];
1248: extract_keyID(keyID, n);
1249: showkeyID(keyID);
1250: } /* showkeyID2 */
1251:
1252:
1253:
1254: boolean checkkeyID(byte *keyID, unitptr n)
1255: /* Compare specified keyID with one derived from actual key modulus n. */
1256: {
1257: byte keyID0[KEYFRAGSIZE];
1258: if (keyID==NULL) /* no key ID -- assume a good match */
1259: return (TRUE);
1260: extract_keyID(keyID0, n);
1261: return(equal_buffers(keyID,keyID0,KEYFRAGSIZE));
1262: } /* checkkeyID */
1263:
1264:
1265:
1266: /* external function prototype, from rsaio.c */
1267: void dump_unit_array(string s, unitptr r);
1268:
1269:
1270: short writekeyfile(char *fname, boolean hidekey, byte *timestamp, byte *userid,
1271: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
1272: /* Write key components p, q, n, e, d, and u to specified file.
1273: hidekey is TRUE iff key should be encrypted.
1274: userid is a length-prefixed Pascal-type character string.
1275: */
1276: { FILE *f;
1277: byte ctb,c;
1278: word16 cert_length;
1279: /* open file f for write, in binary (not text) mode...*/
1280: if ((f = fopen(fname,"wb")) == NULL)
1281: { fprintf(stderr,"\n\aCan't create key file '%s'\n",fname);
1282: return(-1);
1283: }
1284: else
1285: {
1286: /*** Begin key certificate header fields ***/
1287: if (d==NULL)
1288: { /* public key certificate */
1289: ctb = CTB_CERT_PUBKEY;
1290: cert_length = SIZEOF_TIMESTAMP + userid[0]+1 + (countbytes(n)+2)
1291: + (countbytes(e)+2); /* no crc16 */
1292: } /* public key certificate */
1293: else
1294: { /* secret key certificate */
1295: ctb = CTB_CERT_SECKEY;
1296: cert_length = SIZEOF_TIMESTAMP + userid[0]+1
1297: + (countbytes(n)+2)
1298: + (countbytes(e)+2) + (countbytes(d)+2)
1299: + (countbytes(p)+2) + (countbytes(q)+2)
1300: + (countbytes(u)+2); /* no crc16 */
1301:
1302: } /* secret key certificate */
1303:
1304: fwrite(&ctb,1,1,f); /* write key certificate header byte */
1305: convert(cert_length); /* convert to external byteorder */
1306: fwrite(&cert_length,1,sizeof(cert_length),f);
1307: hilo_swap(timestamp,4); /* convert to external LSB-first form */
1308: fwrite(timestamp,1,4,f); /* write certificate timestamp */
1309: hilo_swap(timestamp,4); /* convert back to internal form */
1310: fwrite(userid,1,userid[0]+1,f); /* write user ID */
1311: write_mpi(n,f,FALSE);
1312: write_mpi(e,f,FALSE);
1313:
1314: if (is_secret_key(ctb)) /* secret key */
1315: {
1316: write_mpi(d,f,hidekey);
1317: write_mpi(p,f,hidekey);
1318: write_mpi(q,f,hidekey);
1319: write_mpi(u,f,hidekey);
1320: }
1321: fclose(f);
1322: #ifdef DEBUG
1323: fprintf(stderr,"\n%d-bit %s key written to file '%s'.\n",
1324: countbits(n),
1325: is_secret_key(ctb) ? "secret" : "public" ,
1326: fname);
1327: #endif
1328: return(0);
1329: }
1330: } /* writekeyfile */
1331:
1332:
1333: /*======================================================================*/
1334:
1335:
1336: int get_header_info_from_file(char *infile, byte *header, int count)
1337: /* Reads the first count bytes from infile into header. */
1338: { FILE *f;
1339: fill0(header,count);
1340: /* open file f for read, in binary (not text) mode...*/
1341: if ((f = fopen(infile,"rb")) == NULL)
1342: return(-1);
1343: /* read Cipher Type Byte, and maybe more */
1344: count = fread(header,1,count,f);
1345: fclose(f);
1346: return(count); /* normal return */
1347: } /* get_header_info_from_file */
1348:
1349:
1350:
1351: short readkeypacket(FILE *f, boolean hidekey, byte *ctbyte,
1352: byte *timestamp, char *userid,
1353: unitptr n ,unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
1354: /* Reads a key certificate from the current file position of file f.
1355: It will return the ctb, timestamp, userid, public key components
1356: n and e, and if the secret key components are present in the
1357: certificate and d is not a NULL, it will read and return d, p, q,
1358: and u. The file pointer is left positioned after the certificate.
1359: hidekey is TRUE iff key is expected to be encrypted.
1360: */
1361: {
1362: byte ctb;
1363: word32 cert_length;
1364: long file_position;
1365: int count;
1366:
1367: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1368:
1369: /*** Begin certificate header fields ***/
1370: *ctbyte = 0; /* assume no ctbyte for caller at first */
1371: count = fread(&ctb,1,1,f); /* read key certificate CTB byte */
1372: if (count==0) return(-1); /* premature eof */
1373: *ctbyte = ctb; /* returns type to caller */
1374: if ((ctb != CTB_CERT_PUBKEY) && (ctb != CTB_CERT_SECKEY))
1375: return(-2); /* not a key certificate */
1376:
1377: cert_length = getpastlength(ctb, f); /* read certificate length */
1378:
1379: if (cert_length > MAX_KEYCERT_LENGTH-3)
1380: return(-3); /* bad length */
1381:
1382: fread(timestamp,1,4,f); /* read certificate timestamp */
1383: /* note that hilo_swap does nothing if this is a LSB-first CPU */
1384: hilo_swap(timestamp,4); /* convert from external LSB-first form */
1385: count = fread(userid,1,1,f); /* read user ID length byte */
1386: if (count==0) return(-1); /* premature eof */
1387: fread(userid+1,1,userid[0],f); /* read rest of user ID */
1388: /*** End certificate header fields ***/
1389:
1390: /* We're past certificate headers, now look at some key material...*/
1391:
1392: if (read_mpi(n,f,TRUE,FALSE) < 0)
1393: return(-4); /* data corrupted, return error */
1394:
1395: /* Note that precision was adjusted for n */
1396:
1397: if (read_mpi(e,f,FALSE,FALSE) < 0)
1398: return(-4); /* data corrupted, error return */
1399:
1400: cert_length -= SIZEOF_TIMESTAMP + userid[0]+1 +
1401: (countbytes(n)+2) + (countbytes(e)+2);
1402:
1403: if (d==NULL) /* skip rest of this key certificate */
1404: { fseek(f, cert_length, SEEK_CUR);
1405: cert_length = 0; /* because we are skipping secret fields */
1406: }
1407: else /* d is not NULL */
1408: { if (is_secret_key(ctb))
1409: {
1410: if (read_mpi(d,f,FALSE,hidekey) < 0)
1411: return(-4); /* data corrupted, error return */
1412: if (read_mpi(p,f,FALSE,hidekey) < 0)
1413: return(-4); /* data corrupted, error return */
1414: if (read_mpi(q,f,FALSE,hidekey) < 0)
1415: return(-4); /* data corrupted, error return */
1416:
1417: /* use register 'u' briefly as scratchpad */
1418: mp_mult(u,p,q); /* compare p*q against n */
1419: if (mp_compare(n,u)!=0) /* bad pass phrase? */
1420: return(-5); /* possible bad pass phrase, error return */
1421: /* now read in real u */
1422: if (read_mpi(u,f,FALSE,hidekey) < 0)
1423: return(-4); /* data corrupted, error return */
1424:
1425: cert_length -= (countbytes(d)+2) + (countbytes(p)+2)
1426: + (countbytes(q)+2) + (countbytes(u)+2);
1427:
1428: } /* secret key */
1429: else /* not a secret key */
1430: { mp_init(d,0);
1431: mp_init(p,0);
1432: mp_init(q,0);
1433: mp_init(u,0);
1434: }
1435: } /* d != NULL */
1436:
1437: if (cert_length != 0)
1438: { fprintf(stderr,"\n\aCorrupted key. Bad length, off by %d bytes.\n",
1439: (signed int) cert_length);
1440: return(-4); /* data corrupted, error return */
1441: }
1442:
1443: return(0); /* normal return */
1444:
1445: } /* readkeypacket */
1446:
1447:
1448:
1449: int getpublickey(boolean giveup, boolean showkey, char *keyfile,
1450: long *file_position, int *pktlen, byte *keyID, byte *timestamp,
1451: byte *userid, unitptr n, unitptr e)
1452: /* keyID contains key fragment we expect to find in keyfile.
1453: If keyID is NULL, then userid contains a C string search target of
1454: userid to find in keyfile.
1455: keyfile is the file to begin search in, and it may be modified
1456: to indicate true filename of where the key was found. It can be
1457: either a public key file or a secret key file.
1458: file_position is returned as the byte offset within the keyfile
1459: that the key was found at.
1460: giveup is TRUE iff we are just going to do a single file search only.
1461: */
1462: {
1463: int keytype; /* 1 for secret key, 0 for public key */
1464: byte ctb; /* returned by readkeypacket */
1465: FILE *f;
1466: int status;
1467: boolean keyfound = FALSE;
1468: boolean secret; /* indicates we are called by getsecretkey */
1469: char userid0[256]; /* C string format */
1470:
1471: userid0[0] = '\0';
1472: secret = strcontains(keyfile,SEC_EXTENSION);
1473:
1474: if (keyID==NULL) /* then userid has search target */
1475: strcpy(userid0,userid);
1476:
1477: top:
1478: if (secret)
1479: default_extension(keyfile,SEC_EXTENSION);
1480: else
1481: default_extension(keyfile,PUB_EXTENSION);
1482:
1483: if (!file_exists(keyfile))
1484: { if (giveup)
1485: return(-1); /* give up, error return */
1486: fprintf(stderr,"\nKeyring file '%s' does not exist. ",keyfile);
1487: goto nogood;
1488: }
1489: if (verbose) fprintf(stderr,"\nSearching key ring file '%s'.\n",keyfile);
1490:
1491: /* open file f for read, in binary (not text) mode...*/
1492: if ((f = fopen(keyfile,"rb")) == NULL)
1493: return(-1); /* error return */
1494:
1495: while (TRUE)
1496: {
1497: *file_position = ftell(f);
1498: status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
1499: NULL,NULL,NULL,NULL);
1500: /* Note that readkeypacket has called set_precision */
1501:
1502: if (status == -1) /* end of file */
1503: break;
1504:
1505: if (status < -1)
1506: { fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
1507: keyfile);
1508: fclose(f); /* close key file */
1509: return(-1);
1510: }
1511:
1512: /* keyID contains key fragment. Check it against n from keyfile. */
1513: if (keyID!=NULL)
1514: keyfound = checkkeyID(keyID,n);
1515: else
1516: { /* userid0 is already a C string */
1517: PascalToC(userid); /* for C string functions */
1518: keyfound = strcontains(userid,userid0); /* any matching subset? */
1519: /* keyfound = (strcmp(userid,userid0)==0); /* exact match? */
1520: CToPascal(userid);
1521: }
1522:
1523: if (keyfound)
1524: { *pktlen = (ftell(f) - *file_position);
1525: if (showkey)
1526: { PascalToC(userid); /* for display */
1527: fprintf(stderr,"\nKey for user ID: %s\n",userid);
1528: CToPascal(userid);
1529: fprintf(stderr,"%d-bit key, Key ID ",countbits(n));
1530: showkeyID2(n);
1531: fprintf(stderr,", created %s",ctime((long *)timestamp));
1532: }
1533: fclose(f);
1534: return(0); /* normal return */
1535: }
1536: } /* while TRUE */
1537:
1538: fclose(f); /* close key file */
1539:
1540: if (giveup)
1541: return(-1); /* give up, error return */
1542:
1543: if (keyID!=NULL)
1544: {
1545: fprintf(stderr,"\n\aKey matching expected Key ID ");
1546: showkeyID(keyID);
1547: fprintf(stderr," not found in file '%s'.\n",keyfile);
1548: }
1549: else
1550: { fprintf(stderr,"\n\aKey matching userid '%s' not found in file '%s'.\n",
1551: userid0,keyfile);
1552: }
1553:
1554: nogood:
1555: if (giveup)
1556: return(-1); /* give up, error return */
1557:
1558: if (secret)
1559: fprintf(stderr,"Enter secret key filename: ");
1560: else
1561: fprintf(stderr,"Enter public key filename: ");
1562:
1563: getstring(keyfile,59,TRUE); /* echo keyboard input */
1564: if (strlen(keyfile) > 0)
1565: goto top;
1566:
1567: return(-1); /* give up, error return */
1568:
1569: } /* getpublickey */
1570:
1571:
1572:
1573: int getsecretkey(byte *keyID, byte *timestamp, byte *userid,
1574: unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u)
1575: /* keyID contains key fragment we expect to find in keyfile.
1576: If keyID is NULL, then userid contains search target of
1577: userid to find in keyfile.
1578: */
1579: {
1580: byte ctb; /* returned by readkeypacket */
1581: FILE *f;
1582: char keyfile[64]; /* for getpublickey */
1583: long file_position;
1584: int pktlen; /* unused, just to satisfy getpublickey */
1585: int status;
1586: boolean hidekey = FALSE; /* TRUE iff secret key is encrypted */
1587: char passphrase[256];
1588: byte iv[256]; /* for BassOmatic CFB mode */
1589: int guesses = 3;
1590:
1591: buildfilename(keyfile,SECRET_KEYRING_FILENAME); /* use default pathname */
1592:
1593: status = getpublickey(FALSE, TRUE, keyfile, &file_position, &pktlen,
1594: keyID, timestamp, userid, n, e);
1595: if (status < 0)
1596: return(status); /* error return */
1597:
1598: /* open file f for read, in binary (not text) mode...*/
1599: if ((f = fopen(keyfile,"rb")) == NULL)
1600: return(-1); /* error return */
1601:
1602: /* First guess is null password, so hidekey is FALSE */
1603:
1604: do /* until good password */
1605: { /* init CFB BassOmatic key */
1606: if (hidekey)
1607: { fill0(iv,256); /* define initialization vector IV as 0 */
1608: if ( initcfb(iv,passphrase,string_length(passphrase),TRUE) < 0 )
1609: { fclose(f); /* close key file */
1610: return(-1);
1611: }
1612: }
1613: burn(passphrase); /* burn sensitive data on stack */
1614: fseek(f,file_position,SEEK_SET); /* reposition file to key */
1615: status = readkeypacket(f,hidekey,&ctb,timestamp,userid,n,e,d,p,q,u);
1616: if (hidekey)
1617: closebass(); /* release BassOmatic resources */
1618:
1619: if (status == -5) /* bad pass phrase status */
1620: { if (guesses!=3) /* not first guess of null password? */
1621: fprintf(stderr,"\n\aUnreadable secret key. Possible bad pass phrase.\n");
1622: if (--guesses) /* not ran out of guesses yet */
1623: { fprintf(stderr,"\nYou need a pass phrase to unlock your RSA secret key. ");
1624: hidekey = (getpassword(passphrase,1,0x0f) > 0);
1625: continue; /* take it from the top */
1626: } /* more guesses to go */
1627: }
1628: if (status < 0)
1629: { fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
1630: keyfile);
1631: fclose(f); /* close key file */
1632: return(-1);
1633: }
1634: } while (status < 0); /* until key reads OK, with good password */
1635:
1636: fclose(f); /* close key file */
1637:
1638: if (!hidekey)
1639: fprintf(stderr,"\nAdvisory warning: This RSA secret key is not protected by a passphrase.\n");
1640: else
1641: fprintf(stderr,"Pass phrase is good. ");
1642:
1643: /* Note that readkeypacket has called set_precision */
1644:
1645: if (testeq(d,0)) /* didn't get secret key components */
1646: { fprintf(stderr,"\n\aKey file '%s' is not a secret key file.\n",keyfile);
1647: return(-1);
1648: }
1649:
1650: return(0); /* normal return */
1651:
1652: } /* getsecretkey */
1653:
1654:
1655:
1656: int make_signature_certificate(byte *certificate, MDstruct *MD,
1657: byte *userid, unitptr n, unitptr d, unitptr p, unitptr q, unitptr u)
1658: /* Constructs a signed message digest in a signature certificate.
1659: Returns total certificate length in bytes, or returns negative
1660: error status.
1661: */
1662: {
1663: byte inbuf[MAX_BYTE_PRECISION], outbuf[MAX_BYTE_PRECISION];
1664: byte mdpacket[32];
1665: byte *mdbufptr;
1666: int i,j,certificate_length,blocksize,bytecount;
1667: word16 useridlength,certsig_length,mdp_length,ske_length;
1668: word32 tstamp; byte *timestamp = (byte *) &tstamp;
1669: byte keyID[KEYFRAGSIZE];
1670:
1671: /* Note that RSA key must be at least big enough to encipher a
1672: complete message digest packet in a single RSA block. */
1673:
1674: blocksize = countbytes(n)-1; /* size of a plaintext block */
1675: if (blocksize < 31)
1676: { fprintf(stderr,"\n\aError: RSA key length must be at least 256 bits.\n");
1677: return(-1);
1678: }
1679:
1680: get_timestamp(timestamp); /* Timestamp when signature was made */
1681: hilo_swap(timestamp,4); /* convert to external LSB-first form */
1682:
1683: fill0(mdpacket,sizeof(mdpacket));
1684: mdpacket[0] = CTB_MD; /* Message Digest type */
1685: /* mdp_length includes algorithm byte, MD, and timestamp. */
1686: mdp_length = 1+16+4; /* message digest packet length */
1687: /* MD packet length does not include itself or CTB prefix: */
1688: mdpacket[1] = mdp_length;
1689: mdpacket[2] = MD4_ALGORITHM_BYTE; /* select MD4 algorithm */
1690:
1691: mdbufptr = (byte *) (MD->buffer); /* point at actual message digest */
1692: for (i=0; i<16; i++)
1693: mdpacket[i+3] = *mdbufptr++; /* Assumes LSB-first order */
1694: /* Stick a timestamp in here, before signing... */
1695: /* timestamp already in external format */
1696: for (j=0; j<SIZEOF_TIMESTAMP; j++,i++)
1697: mdpacket[i+3] = timestamp[j];
1698:
1699: /* Pre-block mdpacket, and convert to INTERNAL byte order: */
1700: preblock((unitptr)inbuf, mdpacket, mdp_length+2, n, TRUE, NULL);
1701:
1702: fprintf(stderr,"Just a moment-- "); /* RSA will take a while. */
1703:
1704: /* do RSA signature calculation: */
1705: rsa_decrypt((unitptr)outbuf,(unitptr)inbuf,d,p,q,u);
1706:
1707: bytecount = reg2mpi(outbuf,(unitptr)outbuf); /* convert to external format */
1708: /* outbuf now contains a MDSB in external byteorder form.
1709: Now make a complete signature certificate from this.
1710: */
1711:
1712: certificate_length = 0;
1713:
1714: /* SKE is Secret Key Encryption (signed). Append CTB for signed msg. */
1715: certificate[certificate_length++] = CTB_SKE;
1716:
1717: ske_length = KEYFRAGSIZE + bytecount+2;
1718: /* SKE packet length does not include itself or CTB prefix: */
1719: certificate[certificate_length++] = ske_length & 0xff;
1720: certificate[certificate_length++] = (ske_length >> 8) & 0xff;
1721:
1722: /* Now append keyID... */
1723: extract_keyID(keyID, n); /* gets keyID */
1724: for (i=0; i<KEYFRAGSIZE; i++)
1725: certificate[certificate_length++] = keyID[i];
1726:
1727: /* Now append the RSA-signed message digest packet: */
1728: for (i=0; i<bytecount+2; i++)
1729: certificate[certificate_length++] = outbuf[i];
1730:
1731: fputc('.',stderr); /* Signal RSA signature completion. */
1732:
1733: burn(inbuf); /* burn sensitive data on stack */
1734: burn(outbuf); /* burn sensitive data on stack */
1735:
1736: return(certificate_length); /* return length of certificate in bytes */
1737:
1738: } /* make_signature_certificate */
1739:
1740:
1741: /*======================================================================*/
1742:
1743:
1744: int signfile(boolean nested, boolean separate_signature,
1745: char *mcguffin, char *infile, char *outfile)
1746: /* Write an RSA-signed message digest of input file to specified
1747: output file, and append input file to output file.
1748: separate_signature is TRUE iff we should not append the
1749: plaintext to the output signature certificate.
1750: */
1751: {
1752: FILE *f;
1753: FILE *g;
1754: byte ctb; /* Cipher Type Byte */
1755: int certificate_length; /* signature certificate length */
1756: byte certificate[MAX_SIGCERT_LENGTH];
1757:
1758: { /* temporary scope for some buffers */
1759: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
1760: byte userid[256];
1761: MDstruct MD;
1762: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
1763: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
1764:
1765: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1766:
1767: if (verbose)
1768: fprintf(stderr,"\nPlaintext file: %s, signature file: %s\n",
1769: infile,outfile);
1770:
1771: if (MDfile(&MD, infile) < 0)
1772: return(-1); /* problem with input file. error return */
1773:
1774: strcpy(userid,mcguffin); /* Who we are looking for */
1775:
1776: if (getsecretkey(NULL, timestamp, userid, n, e, d, p, q, u) < 0)
1777: return(-1); /* problem with secret key file. error return. */
1778:
1779: certificate_length = make_signature_certificate(certificate, &MD, userid, n, d, p, q, u);
1780:
1781: } /* end of scope for some buffers */
1782:
1783: /* open file f for read, in binary (not text) mode...*/
1784: if ((f = fopen(infile,"rb")) == NULL)
1785: { fprintf(stderr,"\n\aCan't open plaintext file '%s'\n",infile);
1786: return(-1);
1787: }
1788:
1789: /* open file g for write, in binary (not text) mode...*/
1790: if ((g = fopen(outfile,"wb")) == NULL)
1791: { fprintf(stderr,"\n\aCan't create signature file '%s'\n",outfile);
1792: fclose(f);
1793: return(-1);
1794: }
1795:
1796: /* write out certificate record to outfile ... */
1797: fwrite(certificate,1,certificate_length,g);
1798:
1799: if (!separate_signature)
1800: {
1801: if (!nested)
1802: { ctb = CTB_LITERAL;
1803: fwrite( &ctb, 1, 1, g ); /* write LITERAL CTB */
1804: /* No CTB packet length specified means indefinite length. */
1805: }
1806: copyfile(f,g,-1UL); /* copy rest of file from file f to g */
1807: }
1808:
1809: fclose(g);
1810: fclose(f);
1811: return(0); /* normal return */
1812:
1813: } /* signfile */
1814:
1815:
1816: /*======================================================================*/
1817:
1818: int check_signaturefile(char *infile, char *outfile)
1819: {
1820: byte ctb,ctb2; /* Cipher Type Bytes */
1821: char keyfile[64]; /* for getpublickey */
1822: long fp; /* unused, just to satisfy getpublickey */
1823: int pktlen; /* unused, just to satisfy getpublickey */
1824: FILE *f;
1825: FILE *g;
1826: long start_text; /* marks file position */
1827: int i,count,blocksize;
1828: word16 SKElength, cert_length;
1829: word32 LITlength;
1830: int certificate_length; /* signature certificate length */
1831: byte certbuf[MAX_SIGCERT_LENGTH];
1832: byteptr certificate; /* for parsing certificate buffer */
1833: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1834: byte inbuf[MAX_BYTE_PRECISION];
1835: byte outbuf[MAX_BYTE_PRECISION];
1836: byte keyID[KEYFRAGSIZE];
1837: word32 tstamp;
1838: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
1839: byte userid[256];
1840: MDstruct MD;
1841: boolean separate_signature;
1842:
1843: fill0( keyID, KEYFRAGSIZE );
1844:
1845: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1846:
1847: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
1848:
1849: if (verbose)
1850: fprintf(stderr,"\nSignature file: %s, output file: %s\n",
1851: infile,outfile);
1852:
1853: /* open file f for read, in binary (not text) mode...*/
1854: if ((f = fopen(infile,"rb")) == NULL)
1855: { fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
1856: return(-1);
1857: }
1858:
1859: /******************** Read header CTB and length field ******************/
1860:
1861: fread(&ctb,1,1,f); /* read certificate CTB byte */
1862: certificate = certbuf;
1863: *certificate++ = ctb; /* copy ctb into certificate */
1864:
1865: if (!is_ctb(ctb))
1866: { fprintf(stderr,"\n\a'%s' is not a cipher file.\n",infile);
1867: goto err1;
1868: }
1869:
1870: cert_length = getpastlength(ctb, f); /* read certificate length */
1871: certificate += ctb_llength(ctb); /* either 1, 2, 4, or 8 */
1872: if (cert_length > MAX_SIGCERT_LENGTH-3)
1873: { fprintf(stderr,"\n\aSignature file '%s' has huge packet length field.\n",infile);
1874: goto err1;
1875: }
1876:
1877: /* read whole certificate: */
1878: if (fread((byteptr) certificate, 1, cert_length, f) < cert_length)
1879: { fprintf(stderr,"\n\aSignature file '%s' has bad packet length field.\n",infile);
1880: goto err1;
1881: }
1882:
1883: if (!is_ctb_type(ctb,CTB_SKE_TYPE))
1884: { fprintf(stderr,"\n\a'%s' is not a signature file.\n",infile);
1885: goto err1;
1886: }
1887:
1888: for (i=0; i<KEYFRAGSIZE; i++)
1889: keyID[i] = *certificate++; /* copy rest of key fragment */
1890:
1891: mpi2reg((unitptr)inbuf,certificate); /* get signed message digest */
1892: certificate += countbytes((unitptr)inbuf)+2;
1893:
1894: if ((certificate-certbuf) != cert_length+3)
1895: { fprintf(stderr,"\n\aBad length in signature certificate. Off by %d.\n",
1896: (signed int) ((certificate-certbuf) - (cert_length+3)));
1897: goto err1;
1898: }
1899:
1900: start_text = ftell(f); /* mark position of text for later */
1901:
1902: if (fread(outbuf,1,1,f) < 1) /* see if any plaintext is there */
1903: { /* Signature certificate has no plaintext following it.
1904: Must be in another file. Go look. */
1905: separate_signature = TRUE;
1906: fclose(f);
1907: fprintf(stderr,"\nFile '%s' has signature, but with no text.",infile);
1908: if (file_exists(outfile))
1909: { fprintf(stderr,"\nText is assumed to be in file '%s'.\n",outfile);
1910: }
1911: else
1912: { fprintf(stderr,"\nPlease enter filename of text that signature applies to: ");
1913: getstring(outfile,59,TRUE); /* echo keyboard */
1914: if (strlen(outfile) == 0)
1915: return(-1);
1916: }
1917: /* open file f for read, in binary (not text) mode...*/
1918: if ((f = fopen(outfile,"rb")) == NULL)
1919: { fprintf(stderr,"\n\aCan't open file '%s'\n",outfile);
1920: return(-1);
1921: }
1922: start_text = ftell(f); /* mark position of text for later */
1923: } /* had to open new input file */
1924: else
1925: { separate_signature = FALSE;
1926: /* We just read 1 byte, so outbuf[0] should contain a ctb,
1927: maybe a CTB_LITERAL byte. */
1928: ctb2 = outbuf[0];
1929: if (is_ctb(ctb2) && is_ctb_type(ctb2,CTB_LITERAL_TYPE))
1930: { /* skip over the CTB_LITERAL header to compute signature */
1931: LITlength = getpastlength(ctb2, f); /* read packet length */
1932: start_text = ftell(f); /* mark position of text for later */
1933: /* Now we are 1 byte past the CTB_LITERAL header. */
1934: }
1935: }
1936:
1937:
1938: /* Use keyID prefix to look up key... */
1939:
1940: /* Get and validate public key from a key file: */
1941: if (getpublickey(FALSE, verbose, keyfile, &fp, &pktlen,
1942: keyID, timestamp, userid, n, e) < 0)
1943: { /* Can't get public key. Complain and process file copy anyway. */
1944: fprintf(stderr,"\n\aWARNING: Can't find the right public key-- can't check signature integrity.\n");
1945: } /* Can't find public key */
1946: else /* got good public key, now use it to check signature...*/
1947: {
1948: if (testeq(e,0)) /* Means secret key has been compromised */
1949: { PascalToC(userid);
1950: fprintf(stderr,"\n\aWarning: Secret key compromised for userid \"%s\".",userid);
1951: fprintf(stderr,"\nThus this public key cannot be used.\n");
1952: goto err1;
1953: }
1954:
1955: /* Recover message digest via public key */
1956: mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n);
1957:
1958: /* Unblock message digest, and convert to external byte order: */
1959: count = postunblock(outbuf, (unitptr)outbuf, n, TRUE, TRUE);
1960: if (count < 0)
1961: { fprintf(stderr,"\n\aBad RSA decrypt: checksum or pad error during unblocking.\n");
1962: goto err1;
1963: }
1964:
1965: fputc('.',stderr); /* Signal RSA completion. */
1966:
1967: /* outbuf should contain message digest packet */
1968: /*==================================================================*/
1969: /* Look at nested stuff within RSA block... */
1970:
1971: if (!is_ctb_type(outbuf[0],CTB_MD_TYPE))
1972: { fprintf(stderr,"\aNested info is not a message digest packet.\n");
1973: goto err1;
1974: }
1975:
1976: if (outbuf[2] != MD4_ALGORITHM_BYTE)
1977: { fprintf(stderr,"\a\nUnrecognized message digest algorithm.\n");
1978: goto err1;
1979: }
1980:
1981: /* Reposition file to where that plaintext begins... */
1982: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
1983:
1984: MDfile0(&MD,f); /* compute a message digest from rest of file */
1985:
1986: hilo_swap(outbuf+19,4); /* convert timestamp from external LSB-first form */
1987: PascalToC(userid); /* for display */
1988:
1989: /* now compare computed MD with claimed MD */
1990: if (!equal_buffers((byte *)(MD.buffer), outbuf+3, 16))
1991: { fprintf(stderr,"\a\nWARNING: Bad signature, doesn't match file contents!\a\n");
1992: fprintf(stderr,"\nBad signature from user \"%s\".\n",userid);
1993: fprintf(stderr,"Signature made %s",ctime((long *)(outbuf+19))); /* '\n' */
1994: goto xnormal; /* normal exit */
1995: }
1996:
1997: fprintf(stderr,"\nGood signature from user \"%s\".\n",userid);
1998: fprintf(stderr,"Signature made %s",ctime((long *)(outbuf+19))); /* '\n' */
1999:
2000: } /* Found correct public key */
2001:
2002: /* Reposition file to where that plaintext begins... */
2003: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
2004:
2005: if (separate_signature)
2006: fprintf(stderr,"\nSignature and text are separate. No output file produced. ");
2007: else /* signature precedes plaintext in file... */
2008: { /* produce a plaintext output file from signature file */
2009: if (file_exists(outfile))
2010: { fprintf(stderr,"\n\aOutput file '%s' already exists. Overwrite (y/N)? ",outfile);
2011: if (!getyesno('n')) /* user said don't do it. */
2012: goto err1; /* abort operation */
2013: }
2014: /* open file g for write, in binary (not text) mode...*/
2015: if ((g = fopen(outfile,"wb")) == NULL)
2016: { fprintf(stderr,"\n\aCan't create plaintext file '%s'\n",outfile);
2017: goto err1;
2018: }
2019: copyfile(f,g,-1UL); /* copy rest of file from file f to g */
2020: fclose(g);
2021: }
2022:
2023: xnormal:
2024: burn(inbuf); /* burn sensitive data on stack */
2025: burn(outbuf); /* burn sensitive data on stack */
2026: fclose(f);
2027: if (separate_signature)
2028: return(0); /* normal return, no nested info */
2029: if (is_ctb(ctb2) && is_ctb_type(ctb2,CTB_LITERAL_TYPE))
2030: /* we already stripped away the CTB_LITERAL */
2031: return(0); /* normal return, no nested info */
2032: /* Otherwise, it's best to assume a nested CTB */
2033: return(1); /* nested information return */
2034:
2035: err1:
2036: burn(inbuf); /* burn sensitive data on stack */
2037: burn(outbuf); /* burn sensitive data on stack */
2038: fclose(f);
2039: return(-1); /* error return */
2040:
2041: } /* check_signaturefile */
2042:
2043:
2044:
2045: /*======================================================================*/
2046: int squish_and_bass_file(byte *basskey, int lenbasskey, FILE *f, FILE *g)
2047: {
2048: FILE *t;
2049: byte header[4];
2050: byte ctb;
2051:
2052: /*
2053: ** Create a temporary file 't' and compress our input file 'f' into
2054: ** 't'. If we get a good compression ratio then use file 't' for
2055: ** input and write a CTB_COMPRESSED prefix.
2056: ** But, if the file looks like a PKZIP file then skip our compression.
2057: */
2058:
2059: fread( header, 1, 4, f );
2060: rewind( f );
2061:
2062: if (pkzipSignature( header ))
2063: t = f;
2064: else
2065: if ((t = tmpfile()) != NULL)
2066: {
2067: extern int lzhEncode( FILE *, FILE * );
2068:
2069: if (verbose) fprintf(stderr, "Compressing plaintext..." );
2070:
2071: ctb = CTB_COMPRESSED; /* use compression prefix CTB */
2072: fwrite( &ctb, 1, 1, t ); /* write CTB_COMPRESSED */
2073: /* No CTB packet length specified means indefinite length. */
2074: ctb = LZH_ALGORITHM_BYTE; /* use lzh compression */
2075: fwrite( &ctb, 1, 1, t ); /* write LZH algorithm byte */
2076:
2077: /* lzhEncode returns the ratio of file size t to size f. */
2078:
2079: if (lzhEncode( f, t) < 9)
2080: {
2081: /* Compression made the input file smaller by at least
2082: 10 per cent, so use the 't' file. */
2083:
2084: if (verbose) fprintf(stderr, "compressed. " );
2085:
2086: rewind( t );
2087: }
2088: else
2089: {
2090: /* Compression made no significant difference in size so
2091: pass the input file along as it is. Close and remove
2092: the temporary file. */
2093:
2094: if (verbose) fprintf(stderr, "incompressible. " );
2095:
2096: wipeout( t );
2097: fclose( t );
2098: rewind( f );
2099: t = f;
2100: }
2101: }
2102: else
2103: t = f;
2104:
2105: /* Now write out file thru BassOmatic ... */
2106:
2107: ctb = CTB_CKE; /* CKE is Conventional Key Encryption */
2108: fwrite( &ctb, 1, 1, g ); /* write CTB_CKE */
2109: /* No CTB packet length specified means indefinite length. */
2110:
2111: bass_file( basskey, lenbasskey, FALSE, t, g ); /* encrypt file */
2112:
2113: if (t != f)
2114: { wipeout( t );
2115: fclose( t ); /* close and remove the temporary file */
2116: }
2117:
2118: return(0); /* normal return */
2119:
2120: } /* squish_and_bass_file */
2121:
2122:
2123: #define NOECHO1 1 /* Disable password from being displayed on screen */
2124: #define NOECHO2 2 /* Disable password from being displayed on screen */
2125:
2126: int bass_encryptfile(boolean nested, char *infile, char *outfile)
2127: {
2128: FILE *f; /* input file */
2129: FILE *g; /* output file */
2130: byte basskey[256];
2131: int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
2132:
2133: if (verbose)
2134: fprintf(stderr,"\nPlaintext file: %s, ciphertext file: %s\n",
2135: infile,outfile);
2136:
2137: /* open file f for read, in binary (not text) mode...*/
2138: if ((f = fopen( infile, "rb" )) == NULL)
2139: {
2140: fprintf(stderr,"\n\aCan't open plaintext file '%s'\n", infile );
2141: return(-1);
2142: }
2143:
2144: /* open file g for write, in binary (not text) mode...*/
2145: if ((g = fopen( outfile, "wb" )) == NULL)
2146: {
2147: fprintf(stderr,"\n\aCan't create ciphertext file '%s'\n", outfile );
2148: fclose(f);
2149: return(-1);
2150: }
2151:
2152: /* Get BassOmatic password with leading BassOmatic control byte: */
2153: /* Default is Military grade BassOmatic key control byte */
2154: if (getpassword(basskey,NOECHO2,0x1f) <= 0)
2155: return(-1);
2156:
2157: basskeylen = strlen(basskey);
2158:
2159: /* Now compress the plaintext and encrypt it with BassOmatic... */
2160: squish_and_bass_file( basskey, basskeylen, f, g );
2161:
2162: burn(basskey); /* burn sensitive data on stack */
2163:
2164: fclose(g);
2165: fclose(f);
2166:
2167: return(0);
2168:
2169: } /* bass_encryptfile */
2170:
2171:
2172: /*======================================================================*/
2173:
2174:
2175: int encryptfile(boolean nested, char *mcguffin, char *infile, char *outfile)
2176: {
2177: byte ctb;
2178: byte ctbCKE = CTB_CKE;
2179: byte randompad[MAX_BYTE_PRECISION]; /* buffer of random pad bytes */
2180: int i,blocksize,ckp_length,PKElength,bytecount;
2181: FILE *f;
2182: FILE *g;
2183: FILE *t;
2184: byte header[4];
2185: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2186: byte inbuf[MAX_BYTE_PRECISION];
2187: byte outbuf[MAX_BYTE_PRECISION];
2188: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2189: byte userid[256];
2190: byte basskey[64]; /* must be big enough for make_random_basskey */
2191: int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
2192: char keyfile[64]; /* for getpublickey */
2193: long fp; /* unused, just to satisfy getpublickey */
2194: int pktlen; /* unused, just to satisfy getpublickey */
2195:
2196:
2197: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
2198:
2199: if (verbose)
2200: fprintf(stderr,"\nPlaintext file: %s, ciphertext file: %s\n",
2201: infile,outfile);
2202:
2203: strcpy(userid,mcguffin); /* Who we are looking for (C string) */
2204:
2205: /* Get and validate public key from a key file: */
2206: if (getpublickey(FALSE, TRUE, keyfile, &fp, &pktlen, NULL, timestamp, userid, n, e) < 0)
2207: { return(-1);
2208: }
2209:
2210: if (testeq(e,0)) /* Means secret key has been compromised */
2211: { PascalToC(userid);
2212: fprintf(stderr,"\n\aWarning: Secret key compromised for userid \"%s\".",userid);
2213: fprintf(stderr,"\nThus this public key cannot be used.\n");
2214: return(-1);
2215: }
2216:
2217:
2218: /* set_precision has been properly called by getpublickey */
2219:
2220: /* Note that RSA key must be at least big enough to encipher a
2221: complete conventional key packet in a single RSA block.
2222: The BassOmatic key packet is 28 bytes long, which requires
2223: an RSA key 32 bytes (256 bits) long.
2224: If we implemented DES, the DES key packet is 37 bytes long
2225: (with IV, prewhitener and postwhitener), requiring an RSA
2226: key 41 bytes (328 bits) long.
2227: */
2228:
2229: blocksize = countbytes(n)-1; /* size of a plaintext block */
2230: if (blocksize < 31)
2231: { fprintf(stderr,"\n\aError: RSA key length must be at least 256 bits.\n");
2232: return(-1);
2233: }
2234:
2235: /* open file f for read, in binary (not text) mode...*/
2236: if ((f = fopen( infile, "rb" )) == NULL)
2237: {
2238: fprintf(stderr,"\n\aCan't open plaintext file '%s'\n", infile );
2239: return(-1);
2240: }
2241:
2242: /* open file g for write, in binary (not text) mode...*/
2243: if ((g = fopen( outfile, "wb" )) == NULL)
2244: {
2245: fprintf(stderr,"\n\aCan't create ciphertext file '%s'\n", outfile );
2246: fclose(f);
2247: return(-1);
2248: }
2249:
2250: /* Now we have to time some user keystrokes to get some random
2251: bytes for generating a random BassOmatic key.
2252: We would have to solicit fewer keystrokes for random BassOmatic
2253: key generation if we had already accumulated some keystrokes
2254: incidental to some other purpose, such as asking for a password
2255: to decode an RSA secret key so that a signature could be applied
2256: to the message before encrypting it.
2257: */
2258:
2259: basskeylen = 32; /* Default is big BassOmatic key */
2260: if (blocksize < 64) /* <= 512 bits */
2261: basskeylen = 24;
2262: if (blocksize < 36) /* <= 288 bits */
2263: basskeylen = 16;
2264: ckp_length = make_random_basskey(basskey,basskeylen);
2265: /* Returns a basskeylen+1 byte random BassOmatic key */
2266:
2267: outbuf[0] = CTB_CONKEY; /* conventional key packet */
2268:
2269: ckp_length += 1; /* add length of algorithm field */
2270: /* Conventional key packet length does not include itself or CTB prefix: */
2271: outbuf[1] = ckp_length;
2272:
2273: outbuf[2] = BASS_ALGORITHM_BYTE; /* select BassOmatic algorithm */
2274:
2275: for (i=0; i<ckp_length-1; i++)
2276: outbuf[3+i] = basskey[i];
2277:
2278: /*
2279: ** Messages encrypted with a public key should use random padding,
2280: ** while messages "signed" with a secret key should use constant
2281: ** padding.
2282: */
2283:
2284: for (i = 0; i < (blocksize - (ckp_length + 2)); i++)
2285: randompad[i] = randombyte();
2286:
2287: /*
2288: ** Note that RSA key must be at least big enough to encipher a
2289: ** complete conventional key packet in a single RSA block.
2290: */
2291:
2292: /* ckp_length+2 is conventional key packet length. */
2293:
2294: preblock( (unitptr)inbuf, outbuf, ckp_length+2, n, TRUE, randompad );
2295: mp_modexp( (unitptr)outbuf, (unitptr)inbuf, e, n ); /* RSA encrypt */
2296:
2297: /* write out header record to outfile ... */
2298:
2299: ctb = CTB_PKE; /* PKE is Public Key Encryption */
2300: PKElength = KEYFRAGSIZE + countbytes( (unitptr)outbuf ) + 2;
2301: fwrite( &ctb, 1, 1, g ); /* write RSA msg CTB */
2302:
2303: /* Change PKElength to external byte order: */
2304:
2305: convert( PKElength );
2306: fwrite( &PKElength, 1, sizeof( PKElength ), g ); /* write length */
2307:
2308: writekeyID( n, g ); /* write msg prefix fragment of modulus n */
2309:
2310: /* convert RSA ciphertext block via reg2mpi and write to file */
2311:
2312: write_mpi( (unitptr)outbuf, g, FALSE );
2313:
2314: burn(inbuf); /* burn sensitive data on stack */
2315: burn(outbuf); /* burn sensitive data on stack */
2316:
2317: /** Finished with RSA block containing BassOmatic key. */
2318:
2319: /* Now compress the plaintext and encrypt it with BassOmatic... */
2320: squish_and_bass_file( basskey, ckp_length-1, f, g );
2321:
2322: burn(basskey); /* burn sensitive data on stack */
2323:
2324: fclose(g);
2325: fclose(f);
2326:
2327: return(0);
2328: } /* encryptfile */
2329:
2330:
2331: /*======================================================================*/
2332: int make_literal(char *infile, char *outfile)
2333: { /* An awful lot of hassle to go thru just to prepend 1 lousy byte.
2334: Prepends a CTB_LITERAL prefix byte to a file.
2335: */
2336: byte ctb; /* Cipher Type Byte */
2337: FILE *f;
2338: FILE *g;
2339:
2340: if (verbose)
2341: fprintf(stderr,"\nInput plaintext file: %s, Output plaintext file: %s\n",
2342: infile,outfile);
2343:
2344: /* open file f for read, in binary (not text) mode...*/
2345: if ((f = fopen(infile,"rb")) == NULL)
2346: { fprintf(stderr,"\n\aCan't open input plaintext file '%s'\n",infile);
2347: return(-1);
2348: }
2349:
2350: /* open file g for write, in binary (not text) mode... */
2351: if ((g = fopen( outfile, "wb" )) == NULL)
2352: { fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
2353: goto err1;
2354: }
2355:
2356: ctb = CTB_LITERAL; /* prepend this byte prefix to message */
2357: fwrite( &ctb, 1, 1, g ); /* write LITERAL CTB */
2358: /* No CTB packet length specified means indefinite length. */
2359:
2360: copyfile( f, g, -1UL ); /* copy rest of literal plaintext file */
2361:
2362: fclose(g);
2363: fclose(f);
2364: return(0); /* normal return */
2365:
2366: err1:
2367: fclose(f);
2368: return(-1); /* error return */
2369:
2370: } /* make_literal */
2371:
2372:
2373: /*======================================================================*/
2374: int strip_literal(char *infile, char *outfile)
2375: { /* A lot of hassle to go thru just to strip off 1 lousy prefix byte.
2376: Strips off the CTB_LITERAL prefix byte from a file.
2377: */
2378: byte ctb; /* Cipher Type Byte */
2379: FILE *f;
2380: FILE *g;
2381: word32 LITlength = 0;
2382:
2383: if (verbose)
2384: fprintf(stderr,"\nInput plaintext file: %s, output plaintext file: %s\n",
2385: infile,outfile);
2386:
2387: /* open file f for read, in binary (not text) mode...*/
2388: if ((f = fopen(infile,"rb")) == NULL)
2389: { fprintf(stderr,"\n\aCan't open input plaintext file '%s'\n",infile);
2390: return(-1);
2391: }
2392:
2393: fread(&ctb,1,1,f); /* read Cipher Type Byte */
2394:
2395: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_LITERAL_TYPE))
2396: { fprintf(stderr,"\n\a'%s' is not a literal plaintext file.\n",infile);
2397: fclose(f);
2398: return(-1);
2399: }
2400:
2401: LITlength = getpastlength(ctb, f); /* read packet length */
2402:
2403: if (file_exists( outfile ))
2404: { fprintf(stderr, "\n\aOutput file '%s' already exists. Overwrite (y/N)? ", outfile );
2405: if (! getyesno( 'n' ))
2406: goto err1; /* user said don't do it - abort operation */
2407: }
2408:
2409: /* open file g for write, in binary (not text) mode... */
2410:
2411: if ((g = fopen( outfile, "wb" )) == NULL)
2412: { fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
2413: goto err1;
2414: }
2415:
2416: copyfile( f, g, LITlength ); /* copy rest of literal plaintext file */
2417:
2418: fclose(g);
2419: fclose(f);
2420: return(0); /* normal return */
2421:
2422: err1:
2423: fclose(f);
2424: return(-1); /* error return */
2425:
2426: } /* strip_literal */
2427:
2428:
2429: /*======================================================================*/
2430:
2431:
2432: int decryptfile(char *infile, char *outfile)
2433: {
2434: byte ctb; /* Cipher Type Byte */
2435: byte ctbCKE; /* Cipher Type Byte */
2436: FILE *f;
2437: FILE *g;
2438: int count, status;
2439: word32 PKElength, CKElength;
2440: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
2441: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
2442: byte inbuf[MAX_BYTE_PRECISION];
2443: byte outbuf[MAX_BYTE_PRECISION];
2444: byte keyID[KEYFRAGSIZE];
2445: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2446: byte userid[256];
2447:
2448: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
2449:
2450: if (verbose)
2451: fprintf(stderr,"\nCiphertext file: %s, plaintext file: %s\n",
2452: infile,outfile);
2453:
2454: /* open file f for read, in binary (not text) mode...*/
2455: if ((f = fopen(infile,"rb")) == NULL)
2456: { fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
2457: return(-1);
2458: }
2459:
2460: fread(&ctb,1,1,f); /* read Cipher Type Byte */
2461: if (!is_ctb(ctb))
2462: { fprintf(stderr,"\n\a'%s' is not a cipher file.\n",infile);
2463: fclose(f);
2464: return(-1);
2465: }
2466:
2467: /* PKE is Public Key Encryption */
2468: if (!is_ctb_type(ctb,CTB_PKE_TYPE))
2469: { fprintf(stderr,"\n\a'%s' is not enciphered with a public key.\n",infile);
2470: fclose(f);
2471: return(-1);
2472: }
2473:
2474: PKElength = getpastlength(ctb, f); /* read packet length */
2475:
2476: fread(keyID,1,KEYFRAGSIZE,f); /* read key ID */
2477: /* Use keyID prefix to look up key. */
2478:
2479: /* Get and validate secret key from a key file: */
2480: if (getsecretkey(keyID, timestamp, userid, n, e, d, p, q, u) < 0)
2481: { fclose(f);
2482: return(-1);
2483: }
2484:
2485: /* Note that RSA key must be at least big enough to encipher a
2486: complete conventional key packet in a single RSA block. */
2487:
2488: /*==================================================================*/
2489: /* read ciphertext block, converting to internal format: */
2490: read_mpi((unitptr)inbuf, f, FALSE, FALSE);
2491:
2492: fprintf(stderr,"Just a moment-- "); /* RSA will take a while. */
2493:
2494: rsa_decrypt((unitptr)outbuf, (unitptr)inbuf, d, p, q, u);
2495:
2496: if ((count = postunblock(outbuf, (unitptr)outbuf, n, TRUE, TRUE)) < 0)
2497: { fprintf(stderr,"\n\aBad RSA decrypt: checksum or pad error during unblocking.\n");
2498: fclose(f);
2499: return(-1);
2500: }
2501:
2502: fputc('.',stderr); /* Signal RSA completion. */
2503:
2504: /* outbuf should contain random BassOmatic key packet */
2505: /*==================================================================*/
2506: /* Look at nested stuff within RSA block... */
2507:
2508: ctb = outbuf[0]; /* get nested CTB, should be CTB_CONKEY */
2509:
2510: if (!is_ctb_type(ctb,CTB_CONKEY_TYPE))
2511: { fprintf(stderr,"\aNested info is not a conventional key packet.\n");
2512: goto err1;
2513: }
2514:
2515: /* Test the Conventional Key Packet for supported algorithms.
2516: (currently, just the BassOmatic is supported) */
2517:
2518: if ( outbuf[2] != BASS_ALGORITHM_BYTE )
2519: { fprintf(stderr,"\a\nUnrecognized conventional encryption algorithm.\n");
2520: goto err1;
2521: }
2522:
2523: if (file_exists( outfile ))
2524: { fprintf(stderr, "\n\aOutput file '%s' already exists. Overwrite (y/N)? ", outfile );
2525: if (! getyesno( 'n' ))
2526: goto err1; /* user said don't do it - abort operation */
2527: }
2528:
2529: /* open file g for write, in binary (not text) mode... */
2530: if ((g = fopen( outfile, "wb" )) == NULL)
2531: { fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
2532: goto err1;
2533: }
2534:
2535: fread(&ctbCKE,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */
2536: if (ctbCKE != CTB_CKE)
2537: { /* Should never get here. */
2538: fprintf(stderr,"\a\nBad or missing CTB_CKE byte.\n");
2539: goto err1; /* Abandon ship! */
2540: }
2541:
2542: CKElength = getpastlength(ctbCKE, f); /* read packet length */
2543:
2544: status = bass_file( outbuf+3, count-3, TRUE, f, g ); /* Decrypt ciphertext file */
2545:
2546: fclose(g);
2547: fclose(f);
2548: burn(inbuf); /* burn sensitive data on stack */
2549: burn(outbuf); /* burn sensitive data on stack */
2550: mp_burn(d); /* burn sensitive data on stack */
2551: mp_burn(p); /* burn sensitive data on stack */
2552: mp_burn(q); /* burn sensitive data on stack */
2553: mp_burn(u); /* burn sensitive data on stack */
2554: if (status < 0) /* if bass_file failed, then error return */
2555: return(status);
2556: return(1); /* always indicate output file has nested stuff in it. */
2557:
2558: err1:
2559: fclose(f);
2560: burn(inbuf); /* burn sensitive data on stack */
2561: burn(outbuf); /* burn sensitive data on stack */
2562: mp_burn(d); /* burn sensitive data on stack */
2563: mp_burn(p); /* burn sensitive data on stack */
2564: mp_burn(q); /* burn sensitive data on stack */
2565: mp_burn(u); /* burn sensitive data on stack */
2566: return(-1); /* error return */
2567:
2568: } /* decryptfile */
2569:
2570:
2571:
2572: int bass_decryptfile(char *infile, char *outfile)
2573: {
2574: byte ctb; /* Cipher Type Byte */
2575: FILE *f;
2576: FILE *g;
2577: word32 CKElength;
2578: byte basskey[256];
2579: int basskeylen; /* must get no bigger than sizeof(basskey)-2 */
2580: int status;
2581:
2582: if (verbose)
2583: fprintf(stderr,"\nCiphertext file: %s, plaintext file: %s\n",
2584: infile,outfile);
2585:
2586: /* open file f for read, in binary (not text) mode...*/
2587: if ((f = fopen(infile,"rb")) == NULL)
2588: { fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",infile);
2589: return(-1);
2590: }
2591:
2592: fread(&ctb,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */
2593:
2594: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_CKE_TYPE))
2595: { /* Should never get here. */
2596: fprintf(stderr,"\a\nBad or missing CTB_CKE byte.\n");
2597: goto err1; /* Abandon ship! */
2598: }
2599:
2600: CKElength = getpastlength(ctb, f); /* read packet length */
2601: /* The packet length is ignored. Assume it's huge. */
2602:
2603: if (file_exists( outfile ))
2604: { fprintf(stderr, "\n\aOutput file '%s' already exists. Overwrite (y/N)? ", outfile );
2605: if (! getyesno( 'n' ))
2606: goto err1; /* user said don't do it - abort operation */
2607: }
2608:
2609: /* open file g for write, in binary (not text) mode... */
2610: if ((g = fopen( outfile, "wb" )) == NULL)
2611: { fprintf(stderr, "\n\aCan't create plaintext file '%s'\n", outfile );
2612: goto err1;
2613: }
2614:
2615: /* Get BassOmatic password with leading BassOmatic control byte: */
2616: /* Default is Military grade BassOmatic key control byte */
2617: if (getpassword(basskey,NOECHO1,0x1f) <= 0)
2618: return(-1);
2619:
2620: basskeylen = strlen(basskey);
2621:
2622: status = bass_file( basskey, basskeylen, TRUE, f, g ); /* decrypt file */
2623:
2624: burn(basskey); /* burn sensitive data on stack */
2625:
2626: fclose(g);
2627: fclose(f);
2628:
2629: if (status < 0) /* if bass_file failed, then complain */
2630: { fprintf(stderr,"\n\aError: Bad pass phrase. ");
2631: remove(outfile); /* throw away our mistake */
2632: return(status); /* error return */
2633: }
2634: return(1); /* always indicate output file has nested stuff in it. */
2635:
2636: err1:
2637: fclose(f);
2638: return(-1); /* error return */
2639:
2640: } /* bass_decryptfile */
2641:
2642:
2643:
2644: int decompress_file(char *infile, char *outfile)
2645: {
2646: byte ctb;
2647: FILE *f;
2648: FILE *g;
2649: word32 compress_pkt_length;
2650: extern void lzhDecode( FILE *, FILE * );
2651: if (verbose) fprintf(stderr, "Decompressing plaintext..." );
2652:
2653: /* open file f for read, in binary (not text) mode...*/
2654: if ((f = fopen(infile,"rb")) == NULL)
2655: { fprintf(stderr,"\n\aCan't open compressed file '%s'\n",infile);
2656: return(-1);
2657: }
2658:
2659: fread(&ctb,1,1,f); /* read and skip over Cipher Type Byte */
2660: if (!is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
2661: { /* Shouldn't get here, or why were we called to begin with? */
2662: fprintf(stderr,"\a\nBad or missing CTB_COMPRESSED byte.\n");
2663: goto err1; /* Abandon ship! */
2664: }
2665:
2666: compress_pkt_length = getpastlength(ctb, f); /* read packet length */
2667: /* The packet length is ignored. Assume it's huge. */
2668:
2669: fread(&ctb,1,1,f); /* read and skip over compression algorithm byte */
2670: if (ctb != LZH_ALGORITHM_BYTE)
2671: { /* We only know one compression algorithm */
2672: fprintf(stderr,"\a\nUnrecognized compression algorithm.\n");
2673: goto err1; /* Abandon ship! */
2674: }
2675:
2676: /* open file g for write, in binary (not text) mode... */
2677: if ((g = fopen( outfile, "wb" )) == NULL)
2678: { fprintf(stderr, "\n\aCan't create decompressed file '%s'\n", outfile );
2679: goto err1;
2680: }
2681:
2682: lzhDecode( f, g );
2683: if (verbose) fprintf(stderr, "done. " );
2684: fclose(g);
2685: fclose(f);
2686: return(1); /* always indicate output file has nested stuff in it. */
2687: err1:
2688: fclose(f);
2689: return(-1); /* error return */
2690:
2691: } /* decompress_file */
2692:
2693:
2694:
2695: int view_keyring(char *mcguffin, char *ringfile)
2696: /* Lists all entries in keyring that have mcguffin string in userid.
2697: mcguffin is a null-terminated C string.
2698: */
2699: { FILE *f;
2700: long file_position,fp;
2701: byte ctb;
2702: int status;
2703: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2704: byte keyID[KEYFRAGSIZE];
2705: byte userid[256]; /* key certificate userid */
2706: word32 tstamp;
2707: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2708: int keycounter = 0;
2709:
2710: /* open file f for read, in binary (not text) mode...*/
2711: if ((f = fopen(ringfile,"rb")) == NULL)
2712: { fprintf(stderr,"\n\aCan't open key ring file '%s'\n",ringfile);
2713: return(-1);
2714: }
2715:
2716: /* Here's a good format for display of key or signature certificates:
2717: Type bits/keyID Date User ID
2718: pub 990/xxxxxx dd-mmm-yy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2719: sec 990/xxxxxx dd-mmm-yy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2720: sig 990/xxxxxx dd-mmm-yy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2721: com 990/xxxxxx dd-mmm-yy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2722: */
2723:
2724: fprintf(stderr,"\nKey ring: '%s'",ringfile);
2725: if (strlen(mcguffin) > 0)
2726: fprintf(stderr,", looking for user ID \"%s\".",mcguffin);
2727: fprintf(stderr,"\nType bits/keyID Date User ID\n");
2728: do
2729: {
2730: status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
2731: NULL,NULL,NULL,NULL);
2732: /* Note that readkeypacket has called set_precision */
2733: if (status== -1 ) break; /* eof reached */
2734: if (status < 0)
2735: { fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
2736: ringfile);
2737: fclose(f); /* close key file */
2738: return(-1);
2739: }
2740:
2741: if (!is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE)
2742: && !is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
2743: {
2744: fprintf(stderr,"\n\aError in file '%s'. Not a key certificate.\n",
2745: ringfile);
2746: return(-1);
2747: }
2748:
2749: keycounter++;
2750:
2751: extract_keyID(keyID, n);
2752: PascalToC(userid);
2753:
2754: if (strcontains(userid,mcguffin))
2755: {
2756: if (is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE))
2757: {
2758: if (testeq(e,0)) /* e==0 means key compromised */
2759: fprintf(stderr,"com "); /* "key compromised" certificate */
2760: else
2761: fprintf(stderr,"pub "); /* public key certificate */
2762: }
2763: else if (is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
2764: fprintf(stderr,"sec "); /* secret key certificate */
2765: else
2766: fprintf(stderr,"??? "); /* otherwise, who knows? */
2767:
2768: fprintf(stderr,"%4d/",countbits(n));
2769: showkeyID(keyID);
2770: fputc(' ',stderr);
2771: show_date((long *)timestamp);
2772: fprintf(stderr," ");
2773: fprintf(stderr,userid);
2774: fputc('\n',stderr);
2775: } /* if it has mcguffin */
2776: } while (status >= 0);
2777:
2778: fclose(f); /* close key file */
2779: fprintf(stderr,"%d key(s) examined. ",keycounter);
2780:
2781: return(0); /* normal return */
2782:
2783: } /* view_keyring */
2784:
2785:
2786:
2787: int remove_from_keyring(byte *keyID, char *mcguffin, char *ringfile)
2788: /* Remove the first entry in key ring that has mcguffin string in userid.
2789: Or it removes the first matching keyID from the ring.
2790: A non-NULL keyID takes precedence over a mcguffin specifier.
2791: mcguffin is a null-terminated C string.
2792: */
2793: {
2794: FILE *f;
2795: FILE *g;
2796: long file_position,fp,after_key;
2797: int packetlength=0;
2798: byte ctb;
2799: int status;
2800: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2801: byte userid[256]; /* key certificate userid */
2802: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2803:
2804: default_extension(ringfile,PUB_EXTENSION);
2805:
2806: if ((keyID==NULL) && (strlen(mcguffin)==0))
2807: return(-1); /* error, null mcguffin will match everything */
2808:
2809: strcpy(userid,mcguffin);
2810:
2811: fprintf(stderr,"\nRemoving from key ring: '%s'",ringfile);
2812: if (strlen(mcguffin) > 0)
2813: fprintf(stderr,", userid \"%s\".\n",mcguffin);
2814:
2815: status = getpublickey(TRUE, TRUE, ringfile, &fp, &packetlength, NULL, timestamp, userid, n, e);
2816: if (status < 0)
2817: { fprintf(stderr,"\n\aKey not found in key ring '%s'.\n",ringfile);
2818: return(0); /* normal return */
2819: }
2820: after_key = fp + packetlength;
2821:
2822: if (testeq(e,0)) /* This is a key compromise certificate. */
2823: { /* Wish there was a more elegant way to handle this... */
2824: fprintf(stderr,"\n\aWARNING: This is a \"key compromised\" certificate.");
2825: fprintf(stderr,"\nIt should not be removed from the key ring!\n");
2826: if (keyID != NULL) /* Decision requires human confirmation. */
2827: return(-1);
2828: }
2829:
2830: if (keyID==NULL) /* Human confirmation is required. */
2831: { /* Supposedly the key was fully displayed by getpublickey */
2832: fprintf(stderr,"\nAre you sure you want this key removed (y/N)? ");
2833: if (!getyesno('n'))
2834: return(-1); /* user said "no" */
2835: }
2836:
2837: /* open file f for read, in binary (not text) mode...*/
2838: if ((f = fopen(ringfile,"rb")) == NULL)
2839: { fprintf(stderr,"\n\aCan't open key ring file '%s'\n",ringfile);
2840: return(-1);
2841: }
2842:
2843: remove(SCRATCH_KEYRING_FILENAME);
2844: /* open file g for writing, in binary (not text) mode...*/
2845: if ((g = fopen(SCRATCH_KEYRING_FILENAME,"wb")) == NULL)
2846: { fclose(f);
2847: return(-1);
2848: }
2849: rewind(f);
2850: copyfile(f,g,fp); /* copy file f to g up to position fp */
2851: fseek(f,after_key,SEEK_SET); /* reposition file to after key */
2852: copyfile(f,g,-1UL); /* copy rest of file from file f to g */
2853: fclose(g); /* close scratch file */
2854: fclose(f); /* close key file */
2855: remove(ringfile); /* dangerous. sure hope rename works... */
2856: rename(SCRATCH_KEYRING_FILENAME,ringfile);
2857: fprintf(stderr,"\nKey removed from key ring. ");
2858:
2859: return(0); /* normal return */
2860:
2861: } /* remove_from_keyring */
2862:
2863:
2864:
2865: int addto_keyring(char *keyfile, char *ringfile)
2866: /* Adds (prepends) key file to key ring file */
2867: { FILE *f;
2868: FILE *g;
2869: long file_position,fp;
2870: int pktlen; /* unused, just to satisfy getpublickey */
2871: byte ctb;
2872: int status;
2873: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
2874: byte keyID[KEYFRAGSIZE];
2875: byte userid[256]; /* key certificate userid */
2876: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2877: boolean keycompromised;
2878:
2879: if (strcontains(ringfile,SEC_EXTENSION))
2880: force_extension(SCRATCH_KEYRING_FILENAME,SEC_EXTENSION);
2881: else
2882: force_extension(SCRATCH_KEYRING_FILENAME,PUB_EXTENSION);
2883:
2884: /* open file f for read, in binary (not text) mode...*/
2885: if ((f = fopen(keyfile,"rb")) == NULL)
2886: { fprintf(stderr,"\n\aCan't open key file '%s'\n",keyfile);
2887: return(-1);
2888: }
2889:
2890: /* Check to see if the keyID is already in key ring before we add it in. */
2891:
2892: file_position = ftell(f);
2893: status = readkeypacket(f,FALSE,&ctb,timestamp,userid,n,e,
2894: NULL,NULL,NULL,NULL);
2895: /* Note that readkeypacket has called set_precision */
2896: if (status < 0)
2897: { fprintf(stderr,"\n\aCould not read key from file '%s'.\n",
2898: keyfile);
2899: fclose(f); /* close key file */
2900: return(-1);
2901: }
2902:
2903: if (!is_ctb_type(ctb,CTB_CERT_PUBKEY_TYPE)
2904: && !is_ctb_type(ctb,CTB_CERT_SECKEY_TYPE))
2905: { fprintf(stderr,"\n\aError in file '%s'. Not a key certificate.\n",
2906: keyfile);
2907: return(-1);
2908: }
2909:
2910: extract_keyID(keyID, n); /* from keyfile, not ringfile */
2911:
2912: if (!file_exists(ringfile))
2913: { /* ringfile does not exist. Can it be created? */
2914: /* open file g for writing, in binary (not text) mode...*/
2915: g = fopen(ringfile,"wb");
2916: if (g==NULL)
2917: { fprintf(stderr,"\n\aKey ring file '%s' cannot be created.\n",ringfile);
2918: fclose(f);
2919: return(-1);
2920: }
2921: fclose(g);
2922: }
2923:
2924: /* See if we are adding a "secret key compromised" certificate: */
2925: keycompromised = testeq(e,0);
2926:
2927: /* If this is a key compromise certificate, maybe we should
2928: remove the real public key from the key ring if it's on the
2929: key ring before adding the key compromise certificate.
2930: Probably not, though, because the prepended key compromise
2931: certificate will take search order precedence.
2932: And it may be nice to keep the original public key certificate
2933: around for its timestamp, to check old signatures.
2934: It should not be possible to later add the same public key to
2935: the ring again if the key compromise certificate was there first.
2936:
2937: These tests for duplicates should have to be applied for all
2938: the keys being added to the ring, in case the added key file
2939: is itself a multikey ring. Fix this later.
2940: */
2941:
2942: /* Check for duplicate key in key ring: */
2943: if (getpublickey(TRUE, TRUE, ringfile, &fp, &pktlen, keyID, timestamp, userid, n, e) >= 0)
2944: { fprintf(stderr,"\n\aKey already included in key ring '%s'.\n",ringfile);
2945: if (!keycompromised) /* allows duplicate if key compromised */
2946: { fclose(f); /* close key file */
2947: return(0); /* normal return */
2948: }
2949: }
2950:
2951: if (keycompromised)
2952: fprintf(stderr,"\nAdding \"key compromise\" certificate '%s' to key ring '%s'.\n",
2953: keyfile,ringfile);
2954: else
2955: fprintf(stderr,"\nAdding key certificate '%s' to key ring '%s'.\n",keyfile,ringfile);
2956:
2957: /* The key is prepended to the ring to give it search precedence
2958: over other keys with that same userid. */
2959:
2960: fseek(f,file_position,SEEK_SET); /* reposition file to key */
2961:
2962: remove(SCRATCH_KEYRING_FILENAME);
2963: /* open file g for writing, in binary (not text) mode...*/
2964: if ((g = fopen(SCRATCH_KEYRING_FILENAME,"wb")) == NULL)
2965: { fclose(f);
2966: return(-1);
2967: }
2968: copyfile(f,g,-1UL); /* copy rest of file from file f to g */
2969: fclose(f);
2970:
2971:
2972: /* open file f for reading, in binary (not text) mode...*/
2973: if ((f = fopen(ringfile,"rb")) != NULL)
2974: { copyfile(f,g,-1UL); /* copy rest of file from file f to g */
2975: fclose(f);
2976: }
2977: fclose(g);
2978:
2979: remove(ringfile); /* dangerous. sure hope rename works... */
2980: rename(SCRATCH_KEYRING_FILENAME,ringfile);
2981:
2982: return(0); /* normal return */
2983:
2984: } /* addto_keyring */
2985:
2986:
2987: /*======================================================================*/
2988:
2989:
2990:
2991: int dokeygen(char *keyfile, char *numstr, char *numstr2)
2992: /* Do an RSA key pair generation, and write them out to a pair of files.
2993: The keyfile filename string must not have a file extension.
2994: numstr is a decimal string, the desired bitcount for the modulus n.
2995: numstr2 is a decimal string, the desired bitcount for the exponent e.
2996: */
2997: { unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION],
2998: p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
2999: char fname[64];
3000: char ringfile[64];
3001: byte iv[256]; /* for BassOmatic CFB mode, to protect RSA secret key */
3002: byte userid[256];
3003: short keybits,ebits,i;
3004: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
3005: boolean hidekey; /* TRUE iff secret key is encrypted */
3006:
3007: strcpy(fname,keyfile);
3008: if (strlen(fname)==0)
3009: { fprintf(stderr,"\nKey file name is required for RSA key pair: ");
3010: getstring(fname,sizeof(fname)-4,TRUE);
3011: }
3012:
3013: if (strlen(numstr)==0)
3014: { fprintf(stderr,"\nPick your RSA key size: "
3015: "\n 1) 288 bits- Casual grade, fast but less secure"
3016: "\n 2) 512 bits- Commercial grade, medium speed, good security"
3017: "\n 3) 992 bits- Military grade, very slow, highest security"
3018: "\nChoose 1, 2, or 3, or enter desired number of bits: ");
3019: numstr = userid; /* use userid buffer as scratchpad */
3020: getstring(numstr,5,TRUE); /* echo keyboard */
3021: }
3022:
3023: keybits = 0;
3024: while ((*numstr>='0') && (*numstr<='9'))
3025: keybits = keybits*10 + (*numstr++ - '0');
3026:
3027: /* Standard default key sizes: */
3028: if (keybits==1) keybits=286; /* Casual grade */
3029: if (keybits==2) keybits=510; /* Commercial grade */
3030: if (keybits==3) keybits=990; /* Military grade */
3031:
3032: /* minimum RSA keysize for BassOmatic bootstrap: */
3033: if (keybits<286) keybits=286;
3034:
3035: ebits = 0; /* number of bits in e */
3036: while ((*numstr2>='0') && (*numstr2<='9'))
3037: ebits = ebits*10 + (*numstr2++ - '0');
3038:
3039: fprintf(stderr,"\nGenerating an RSA key with a %d-bit modulus... ",keybits);
3040:
3041: fprintf(stderr,"\nEnter a user ID for your public key (your name): ");
3042: getstring(userid,255,TRUE); /* echo keyboard input */
3043: CToPascal(userid); /* convert to length-prefixed string */
3044:
3045: { char passphrase[256];
3046: fprintf(stderr,"\nYou need a pass phrase to protect your RSA secret key. ");
3047: hidekey = (getpassword(passphrase,2,0x0f) > 0);
3048: /* init CFB BassOmatic key */
3049: if (hidekey)
3050: { fill0(iv,256); /* define initialization vector IV as 0 */
3051: if ( initcfb(iv,passphrase,string_length(passphrase),FALSE) < 0 )
3052: return(-1);
3053: burn(passphrase); /* burn sensitive data on stack */
3054: }
3055: }
3056:
3057: fprintf(stderr,"\nNote that key generation is a VERY lengthy process.\n");
3058:
3059: if (keygen(n,e,d,p,q,u,keybits,ebits) < 0)
3060: { fprintf(stderr,"\n\aKeygen failed!\n");
3061: return(-1); /* error return */
3062: }
3063:
3064: if (verbose)
3065: {
3066: fprintf(stderr,"Key ID ");
3067: showkeyID2(n); fputc('\n',stderr);
3068:
3069: mp_display(" modulus n = ",n);
3070: mp_display("exponent e = ",e);
3071:
3072: mp_display("exponent d = ",d);
3073: mp_display(" prime p = ",p);
3074: mp_display(" prime q = ",q);
3075: mp_display(" inverse u = ",u);
3076: }
3077:
3078: get_timestamp(timestamp); /* Timestamp when key was generated */
3079:
3080: fputc('\a',stderr); /* sound the bell when done with lengthy process */
3081:
3082: force_extension(fname,SEC_EXTENSION);
3083: writekeyfile(fname,hidekey,timestamp,userid,n,e,d,p,q,u);
3084: force_extension(fname,PUB_EXTENSION);
3085: writekeyfile(fname,FALSE,timestamp,userid,n,e,NULL,NULL,NULL,NULL);
3086:
3087: if (hidekey) /* done with Bassomatic to protect RSA secret key */
3088: closebass();
3089:
3090: mp_burn(d); /* burn sensitive data on stack */
3091: mp_burn(p); /* burn sensitive data on stack */
3092: mp_burn(q); /* burn sensitive data on stack */
3093: mp_burn(u); /* burn sensitive data on stack */
3094: mp_burn(e); /* burn sensitive data on stack */
3095: mp_burn(n); /* burn sensitive data on stack */
3096: burn(iv); /* burn sensitive data on stack */
3097:
3098: force_extension(fname,PUB_EXTENSION);
3099: buildfilename(ringfile,PUBLIC_KEYRING_FILENAME);
3100: fprintf(stderr,"\nAdd public key to key ring '%s' (y/N)? ",ringfile);
3101: if (getyesno('n'))
3102: addto_keyring(fname,ringfile);
3103: force_extension(fname,SEC_EXTENSION);
3104: buildfilename(ringfile,SECRET_KEYRING_FILENAME);
3105: fprintf(stderr,"Add secret key to key ring '%s' (y/N)? ",ringfile);
3106: if (getyesno('n'))
3107: addto_keyring(fname,ringfile);
3108:
3109: /* Force initialization of cryptographically strong pseudorandom
3110: number generator seed file for later use...
3111: */
3112: strong_pseudorandom(iv,1);
3113:
3114: return(0); /* normal return */
3115: } /* dokeygen */
3116:
3117:
3118: /*======================================================================*/
3119:
3120:
3121: void main(int argc, char *argv[])
3122: { char keyfile[64], plainfile[64], cipherfile[64], ringfile[64], tempfile[64];
3123: int status,i;
3124: boolean nestflag = FALSE;
3125: boolean uu_emit = FALSE;
3126: boolean wipeflag = FALSE;
3127: byte ctb;
3128: byte header[6]; /* used to classify file type at the end. */
3129: char mcguffin[256]; /* userid search tag */
3130:
3131: #ifdef DEBUG1
3132: verbose = TRUE;
3133: #endif
3134:
3135: fprintf(stderr,"Pretty Good Privacy 1.0 - RSA public key cryptography for the masses.\n"
3136: "(c) Copyright 1990 Philip Zimmermann, Phil's Pretty Good Software. 5 Jun 91\n");
3137:
3138: if (argc <= 1)
3139: { fprintf(stderr,
3140: "\nFor details on free licensing and distribution, see the PGP User's Guide."
3141: "\nFor other cryptography products and custom development services, contact:"
3142: "\nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, phone (303)444-4541"
3143: );
3144: goto usage;
3145: }
3146:
3147: /* Make sure arguments will fit into filename strings: */
3148: for (i = 1; i <= argc; i++)
3149: {
3150: if (strlen(argv[i]) >= sizeof(cipherfile)-4)
3151: {
3152: fprintf(stderr, "\aInvalid filename: [%s] too long\n", argv[i] );
3153: goto user_error;
3154: }
3155: }
3156:
3157: if (argv[1][0] == '-')
3158: {
3159: if (strhas(argv[1],'l'))
3160: verbose = TRUE;
3161:
3162: nestflag = strhas(argv[1],'n');
3163:
3164: uu_emit = strhas(argv[1],'u');
3165:
3166: wipeflag = strhas(argv[1],'w');
3167:
3168: /*-------------------------------------------------------*/
3169: if ( (argc >= 3)
3170: && strhasany(argv[1],"sS") && strhasany(argv[1],"eE") )
3171: { /* Sign AND encrypt file */
3172: /* Arguments: plainfile, her_userid, your_userid, cipherfile */
3173: boolean separate_signature = FALSE;
3174:
3175: strcpy( plainfile, argv[2] );
3176:
3177: if (argc>=6) /* default signature file extension */
3178: { strcpy( cipherfile, argv[5] );
3179: default_extension( cipherfile, CTX_EXTENSION );
3180: }
3181: else
3182: { /* Default the signature file name */
3183: strcpy( cipherfile, plainfile );
3184: /* ...but replace file extension: */
3185: force_extension( cipherfile, CTX_EXTENSION );
3186: }
3187:
3188: if (strcmp( plainfile, cipherfile ) == 0)
3189: { fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
3190: goto user_error; /* same filenames for both files */
3191: }
3192:
3193: if (argc>=5)
3194: { strcpy( mcguffin, argv[4] ); /* Userid of signer */
3195: translate_spaces( mcguffin ); /* change all '_' to ' ' */
3196: }
3197: else
3198: { fprintf(stderr, "\nEnter userid to look up your secret key for signature: ");
3199: getstring( mcguffin, 255, TRUE ); /* echo keyboard */
3200: }
3201:
3202: if (nestflag) /* user thinks this file has nested info */
3203: { get_header_info_from_file( plainfile, &ctb, 1);
3204: if (!legal_ctb(ctb))
3205: { nestflag = FALSE;
3206: fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
3207: }
3208: }
3209:
3210: status = signfile( nestflag, separate_signature,
3211: mcguffin, plainfile, SCRATCH_CTX_FILENAME );
3212:
3213: if (status < 0) /* signfile failed */
3214: { fprintf(stderr, "\aSignature error\n" );
3215: goto user_error;
3216: }
3217:
3218: if (wipeflag)
3219: { wipefile(plainfile); /* destroy every trace of plaintext */
3220: remove(plainfile);
3221: fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
3222: }
3223:
3224: if (argc>=4)
3225: { strcpy( mcguffin, argv[3] ); /* Userid of recipient */
3226: translate_spaces( mcguffin ); /* change all '_' to ' ' */
3227: }
3228: else
3229: { fprintf(stderr, "\nEnter userid to look up recipient's public key: ");
3230: getstring( mcguffin, 255, TRUE ); /* echo keyboard */
3231: }
3232:
3233: /* Indicate that encrypted data has nested signature: */
3234:
3235: status = encryptfile( TRUE, mcguffin, SCRATCH_CTX_FILENAME, cipherfile );
3236:
3237: wipefile( SCRATCH_CTX_FILENAME );
3238: remove( SCRATCH_CTX_FILENAME );
3239:
3240: if (status < 0)
3241: { fprintf(stderr, "\aEncryption error\n" );
3242: goto user_error;
3243: }
3244:
3245: if (uu_emit)
3246: { status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
3247: remove(cipherfile); /* dangerous. sure hope rename works... */
3248: rename(SCRATCH_CTX_FILENAME, cipherfile);
3249: }
3250:
3251: if (!verbose) /* if other filename messages were supressed */
3252: fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
3253:
3254: exit(0);
3255: } /* Sign AND encrypt file */
3256:
3257:
3258: /*-------------------------------------------------------*/
3259: if ( (argc >= 3) && strhasany(argv[1],"sS") )
3260: { /* Sign file
3261: Arguments: plaintextfile, your_userid, signedtextfile
3262: Two kinds of signature: full signature certificate,
3263: or just an RSA-signed message digest.
3264: */
3265:
3266: boolean separate_signature = FALSE;
3267:
3268: separate_signature = strhas( argv[1], 'b' );
3269:
3270: strcpy( plainfile, argv[2] );
3271:
3272: if (argc>=5) /* default signature file extension */
3273: { strcpy( cipherfile, argv[4] );
3274: default_extension( cipherfile, CTX_EXTENSION );
3275: }
3276: else
3277: { /* Default the signature file name */
3278: strcpy( cipherfile, plainfile );
3279: /* ...but replace file extension: */
3280: force_extension( cipherfile, CTX_EXTENSION );
3281: }
3282:
3283: if (strcmp( plainfile, cipherfile ) == 0)
3284: { fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
3285: goto user_error; /* same filenames for both files */
3286: }
3287:
3288: if (argc>=4)
3289: { strcpy( mcguffin, argv[3] ); /* Userid of signer */
3290: translate_spaces( mcguffin ); /* change all '_' to ' ' */
3291: }
3292: else
3293: { fprintf(stderr, "\nEnter userid to look up your secret key for signature: ");
3294: getstring( mcguffin, 255, TRUE ); /* echo keyboard */
3295: }
3296:
3297: if (nestflag) /* user thinks this file has nested info */
3298: { get_header_info_from_file( plainfile, &ctb, 1);
3299: if (!legal_ctb(ctb))
3300: { nestflag = FALSE;
3301: fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
3302: }
3303: }
3304:
3305: status = signfile( nestflag, separate_signature,
3306: mcguffin, plainfile, cipherfile );
3307:
3308: if (status < 0) /* signfile failed */
3309: { fprintf(stderr, "\aSignature error\n" );
3310: goto user_error;
3311: }
3312:
3313: if (uu_emit)
3314: { status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
3315: remove(cipherfile); /* dangerous. sure hope rename works... */
3316: rename(SCRATCH_CTX_FILENAME, cipherfile);
3317: }
3318:
3319: if (!verbose) /* if other filename messages were supressed */
3320: fprintf(stderr,"\nSignature file: %s ", cipherfile);
3321:
3322: exit(0);
3323: } /* Sign file */
3324:
3325:
3326: /*-------------------------------------------------------*/
3327: if ( (argc >= 3) && strhasany(argv[1],"eE") )
3328: { /* Encrypt file
3329: Arguments: plaintextfile, her_userid, ciphertextfile
3330: */
3331:
3332: strcpy( plainfile, argv[2] );
3333:
3334: if (argc >= 5) /* default cipher file extension */
3335: { strcpy( cipherfile, argv[4] );
3336: default_extension( cipherfile, CTX_EXTENSION );
3337: }
3338: else
3339: { /* Default the cipherfile name */
3340: strcpy( cipherfile, plainfile );
3341: force_extension( cipherfile, CTX_EXTENSION );
3342: }
3343:
3344: if (strcmp( plainfile, cipherfile) == 0)
3345: { fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
3346: goto user_error; /* same filenames for both files */
3347: }
3348:
3349: if (argc >= 4)
3350: { strcpy( mcguffin, argv[3] ); /* Userid of recipient */
3351: translate_spaces( mcguffin ); /* change all '_' to ' ' */
3352: }
3353: else
3354: { fprintf(stderr, "\nEnter userid to look up recipient's public key: ");
3355: getstring( mcguffin, 255, TRUE ); /* echo keyboard */
3356: }
3357:
3358: if (nestflag) /* user thinks this file has nested info */
3359: { get_header_info_from_file( plainfile, &ctb, 1);
3360: if (!legal_ctb(ctb))
3361: { nestflag = FALSE;
3362: fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
3363: }
3364: }
3365:
3366: if (!nestflag)
3367: { /* Prepend CTB_LITERAL byte to plaintext file.
3368: --sure wish this pass could be optimized away. */
3369: strcpy( tempfile, plainfile );
3370: strcpy( plainfile, SCRATCH_PTX_FILENAME );
3371: status = make_literal( tempfile, plainfile );
3372: }
3373: status = encryptfile( nestflag, mcguffin, plainfile, cipherfile );
3374:
3375: if (!nestflag)
3376: { wipefile( SCRATCH_PTX_FILENAME );
3377: remove( SCRATCH_PTX_FILENAME );
3378: strcpy( plainfile, tempfile );
3379: }
3380:
3381: if (status < 0) /* encryptfile failed */
3382: { fprintf(stderr, "\aEncryption error\n" );
3383: goto user_error;
3384: }
3385:
3386: if (wipeflag)
3387: { wipefile(plainfile); /* destroy every trace of plaintext */
3388: remove(plainfile);
3389: fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
3390: }
3391:
3392: if (uu_emit)
3393: { status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
3394: remove(cipherfile); /* dangerous. sure hope rename works... */
3395: rename(SCRATCH_CTX_FILENAME, cipherfile);
3396: }
3397:
3398: if (!verbose) /* if other filename messages were supressed */
3399: fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
3400:
3401: exit(0);
3402: } /* Encrypt file */
3403:
3404:
3405: /*-------------------------------------------------------*/
3406: if ( (argc >= 3) && strhasany(argv[1],"cC") )
3407: { /* Encrypt file with BassOmatic only
3408: Arguments: plaintextfile, ciphertextfile
3409: */
3410:
3411: strcpy( plainfile, argv[2] );
3412:
3413: if (argc >= 4) /* default cipher file extension */
3414: { strcpy( cipherfile, argv[3] );
3415: default_extension( cipherfile, CTX_EXTENSION );
3416: }
3417: else
3418: { /* Default the cipherfile name */
3419: strcpy( cipherfile, plainfile );
3420: force_extension( cipherfile, CTX_EXTENSION );
3421: }
3422:
3423: if (strcmp( plainfile, cipherfile) == 0)
3424: { fprintf(stderr, "\aFile [%s] must be specified just once.\n", plainfile );
3425: goto user_error; /* same filenames for both files */
3426: }
3427:
3428: if (nestflag) /* user thinks this file has nested info */
3429: { get_header_info_from_file( plainfile, &ctb, 1);
3430: if (!legal_ctb(ctb))
3431: { nestflag = FALSE;
3432: fprintf(stderr,"\n\aNo nestable data in plaintext file '%s'.\n",plainfile);
3433: }
3434: }
3435:
3436: if (!nestflag)
3437: { /* Prepend CTB_LITERAL byte to plaintext file.
3438: --sure wish this pass could be optimized away. */
3439: strcpy( tempfile, plainfile );
3440: strcpy( plainfile, SCRATCH_PTX_FILENAME );
3441: status = make_literal( tempfile, plainfile );
3442: }
3443:
3444: status = bass_encryptfile( nestflag, plainfile, cipherfile );
3445:
3446: if (!nestflag)
3447: { wipefile( SCRATCH_PTX_FILENAME );
3448: remove( SCRATCH_PTX_FILENAME );
3449: strcpy( plainfile, tempfile );
3450: }
3451:
3452: if (status < 0) /* encryptfile failed */
3453: { fprintf(stderr, "\aEncryption error\n" );
3454: goto user_error;
3455: }
3456:
3457: if (wipeflag)
3458: { wipefile(plainfile); /* destroy every trace of plaintext */
3459: remove(plainfile);
3460: fprintf(stderr,"\nFile %s wiped and deleted. ",plainfile);
3461: }
3462:
3463: if (uu_emit)
3464: { status = uue_file(cipherfile, SCRATCH_CTX_FILENAME);
3465: remove(cipherfile); /* dangerous. sure hope rename works... */
3466: rename(SCRATCH_CTX_FILENAME, cipherfile);
3467: }
3468:
3469: if (!verbose) /* if other filename messages were supressed */
3470: fprintf(stderr,"\nCiphertext file: %s ", cipherfile);
3471:
3472: exit(0);
3473: } /* Encrypt file with BassOmatic only */
3474:
3475:
3476: /*-------------------------------------------------------*/
3477: if (argv[1][1] == 'k')
3478: { /* Key generation
3479: Arguments: keyfile, bitcount, bitcount
3480: */
3481: char keyfile[64], keybits[6], ebits[6];
3482:
3483: if (argc > 2)
3484: strcpy( keyfile, argv[2] );
3485: else
3486: strcpy( keyfile, "" );
3487:
3488: if (argc > 3)
3489: strncpy( keybits, argv[3], sizeof(keybits)-1 );
3490: else
3491: strcpy( keybits, "" );
3492:
3493: if (argc > 4)
3494: strncpy( ebits, argv[4], sizeof(ebits)-1 );
3495: else
3496: strcpy( ebits, "" );
3497:
3498: status = dokeygen( keyfile, keybits, ebits );
3499:
3500: if (status < 0)
3501: { fprintf(stderr, "\aKeygen error. " );
3502: goto user_error;
3503: }
3504: exit(0);
3505: } /* Key generation */
3506:
3507: /*-------------------------------------------------------*/
3508: if ((argc >= 3) && (argv[1][1] == 'a'))
3509: { /* Add key to key ring
3510: Arguments: keyfile, ringfile
3511: */
3512: if (argc < 4) /* default key ring filename */
3513: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
3514: else
3515: strncpy( ringfile, argv[3], sizeof(ringfile)-1 );
3516: strncpy( keyfile, argv[2], sizeof(keyfile)-1 );
3517:
3518: strlwr( keyfile );
3519: strlwr( ringfile );
3520: if (! file_exists( keyfile ))
3521: default_extension( keyfile, PUB_EXTENSION );
3522:
3523: if (strcontains( keyfile, SEC_EXTENSION ))
3524: force_extension( ringfile, SEC_EXTENSION );
3525: else
3526: force_extension( ringfile, PUB_EXTENSION );
3527:
3528: if (! file_exists( keyfile ))
3529: { fprintf(stderr, "\n\aKey file '%s' does not exist.\n", keyfile );
3530: goto user_error;
3531: }
3532:
3533: status = addto_keyring( keyfile, ringfile );
3534:
3535: if (status < 0)
3536: { fprintf(stderr, "\aKeyring add error. " );
3537: goto user_error;
3538: }
3539: exit(0);
3540: } /* Add key to key ring */
3541:
3542: /*-------------------------------------------------------*/
3543: if ((argc >= 2)
3544: && strhasany( argv[1], "vr" ) )
3545: { /* View or remove key ring entries, with userid match
3546: Arguments: userid, ringfile
3547: */
3548: if (argc < 4) /* default key ring filename */
3549: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME );
3550: else
3551: strcpy( ringfile, argv[3] );
3552:
3553: strcpy( mcguffin, argv[2] );
3554: if (strcmp( mcguffin, "*" ) == 0)
3555: strcpy( mcguffin, "" );
3556:
3557: translate_spaces( mcguffin ); /* change all '_' to ' ' */
3558:
3559: if ((argc < 4)
3560: && (strcontains( argv[2], PUB_EXTENSION )
3561: || strcontains( argv[2], SEC_EXTENSION )))
3562: { strcpy( ringfile, argv[2] );
3563: strcpy( mcguffin, "" );
3564: }
3565:
3566: strlwr( ringfile );
3567: if (! file_exists( ringfile ))
3568: default_extension( ringfile, PUB_EXTENSION );
3569:
3570: if (strhas( argv[1], 'v' ))
3571: if (view_keyring( mcguffin, ringfile ) < 0)
3572: { fprintf(stderr, "\aKeyring view error. " );
3573: goto user_error;
3574: }
3575: if (strhas( argv[1], 'r' ))
3576: if (remove_from_keyring( NULL, mcguffin, ringfile ) < 0)
3577: { fprintf(stderr, "\aKeyring remove error. " );
3578: goto user_error;
3579: }
3580: exit(0);
3581: } /* view or remove key ring entries, with userid match */
3582: /*-------------------------------------------------------*/
3583:
3584: fprintf(stderr, "\aUnrecognizable parameters. " );
3585: goto user_error;
3586: } /* -options specified */
3587:
3588:
3589: /*---------------------------------------------------------*/
3590: /* no options specified */
3591:
3592: if (argc >= 2)
3593: { /* Decrypt file
3594: Arguments: ciphertextfile, plaintextfile
3595: */
3596: strcpy( cipherfile, argv[1] );
3597: default_extension( cipherfile, CTX_EXTENSION );
3598:
3599: if (argc >= 3)
3600: { strcpy( plainfile, argv[2] );
3601: default_extension( plainfile, "." );
3602: }
3603: else
3604: { /* Default the plaintext file name */
3605: strcpy( plainfile, argv[1] );
3606: force_extension( plainfile, "." );
3607: }
3608:
3609: if (strcmp( plainfile, cipherfile ) == 0)
3610: { fprintf(stderr, "\aFile '%s' cannot be both input and output file.\n", plainfile );
3611: goto user_error; /* error: same filenames for both files */
3612: }
3613:
3614: if (! file_exists( cipherfile ))
3615: { fprintf(stderr, "\a\nError: Cipher or signature file '%s' does not exist.\n",
3616: cipherfile);
3617: goto user_error;
3618: }
3619:
3620: get_header_info_from_file( cipherfile, header, 4 );
3621: if (!is_ctb(header[0]) && is_uufile(cipherfile))
3622: {
3623: if (verbose) fprintf(stderr,"uudecoding %s...",cipherfile);
3624: status = uud_file(cipherfile, SCRATCH_CTX_FILENAME);
3625: if (status==0)
3626: { if (verbose) fprintf(stderr,"...done.\n");
3627: remove( cipherfile ); /* dangerous. sure hope rename works... */
3628: rename( SCRATCH_CTX_FILENAME, cipherfile );
3629: }
3630: else fprintf(stderr,"\n\aError: uudecode failed for file %s\n",cipherfile);
3631: }
3632:
3633: /*---------------------------------------------------------*/
3634: do /* while nested parsable info present */
3635: {
3636: if (get_header_info_from_file( cipherfile, &ctb, 1) < 0)
3637: { fprintf(stderr,"\n\aCan't open ciphertext file '%s'\n",cipherfile);
3638: goto user_error;
3639: }
3640:
3641: if (!is_ctb(ctb)) /* not a real CTB -- complain */
3642: goto reject;
3643:
3644: /* PKE is Public Key Encryption */
3645: if (is_ctb_type( ctb, CTB_PKE_TYPE ))
3646: {
3647: fprintf(stderr,"\nFile is encrypted. Secret key is required to read it. ");
3648:
3649: status = decryptfile( cipherfile, plainfile );
3650:
3651: if (status < 0) /* error return */
3652: goto user_error;
3653: if (status < 1) /* output file has no nested info? */
3654: break; /* no nested parsable info. exit loop. */
3655:
3656: /* Nested parsable info indicated. Process it. */
3657: wipefile( SCRATCH_CTX_FILENAME );
3658: remove( SCRATCH_CTX_FILENAME );
3659: rename( plainfile, SCRATCH_CTX_FILENAME );
3660: strcpy( cipherfile, SCRATCH_CTX_FILENAME );
3661: continue; /* skip rest of loop */
3662: } /* outer CTB is PKE type */
3663:
3664:
3665: if (is_ctb_type( ctb, CTB_SKE_TYPE ))
3666: {
3667: fprintf(stderr,"\nFile has signature. Public key is required to check signature. ");
3668:
3669: status = check_signaturefile( cipherfile, plainfile );
3670:
3671: if (status < 0) /* error return */
3672: goto user_error;
3673:
3674: if (status < 1) /* output file has no nested info? */
3675: break; /* no nested parsable info. exit loop. */
3676:
3677: /* Nested parsable info indicated. Process it. */
3678: /* Destroy signed plaintext, if it's in a scratchfile. */
3679: wipefile( SCRATCH_CTX_FILENAME );
3680: remove( SCRATCH_CTX_FILENAME );
3681: rename( plainfile, SCRATCH_CTX_FILENAME );
3682: strcpy( cipherfile, SCRATCH_CTX_FILENAME );
3683: continue; /* skip rest of loop */
3684: } /* outer CTB is SKE type */
3685:
3686:
3687: if (ctb == CTB_CKE)
3688: { /* Conventional Key Encrypted ciphertext. */
3689: fprintf(stderr,"\nFile is conventionally encrypted. Pass phrase required to read it. ");
3690: status = bass_decryptfile( cipherfile, plainfile );
3691: if (status < 0) /* error return */
3692: goto user_error;
3693: if (status < 1) /* output file has no nested info? */
3694: break; /* no nested parsable info. exit loop. */
3695: /* Nested parsable info indicated. Process it. */
3696: wipefile( SCRATCH_CTX_FILENAME );
3697: remove( SCRATCH_CTX_FILENAME );
3698: rename( plainfile, SCRATCH_CTX_FILENAME );
3699: strcpy( cipherfile, SCRATCH_CTX_FILENAME );
3700: continue; /* skip rest of loop */
3701: } /* CTB is CKE type */
3702:
3703:
3704: if (is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
3705: { /* Compressed text. */
3706: status = decompress_file( cipherfile, plainfile );
3707: if (status < 0) /* error return */
3708: goto user_error;
3709: /* Always assume nested information... */
3710: /* Destroy compressed plaintext, if it's in a scratchfile. */
3711: wipefile( SCRATCH_CTX_FILENAME );
3712: remove( SCRATCH_CTX_FILENAME );
3713: rename( plainfile, SCRATCH_CTX_FILENAME );
3714: strcpy( cipherfile, SCRATCH_CTX_FILENAME );
3715: continue; /* skip rest of loop */
3716: } /* CTB is COMPRESSED type */
3717:
3718:
3719: if (is_ctb_type( ctb, CTB_LITERAL_TYPE ))
3720: { /* Raw plaintext. Just copy it. No more nesting. */
3721: /* Strip off CTB_LITERAL prefix byte from file: */
3722: status = strip_literal( cipherfile, plainfile );
3723: break; /* no nested parsable info. exit loop. */
3724: } /* CTB is LITERAL type */
3725:
3726:
3727: if ((ctb == CTB_CERT_SECKEY)
3728: || (ctb == CTB_CERT_PUBKEY))
3729: { /* Key ring. View it. */
3730: fprintf(stderr, "\nFile contains key(s). Contents follow..." );
3731:
3732: if (view_keyring( NULL, cipherfile ) < 0)
3733: goto user_error;
3734:
3735: /* No output file--what should we do with plainfile?
3736: We know that we have already prevented original
3737: cipher filename from being same as plain filename.
3738: */
3739:
3740: if (strcmp( cipherfile, SCRATCH_CTX_FILENAME ) == 0)
3741: { /* key was nested in signed or enciphered file */
3742: remove( plainfile );
3743: rename( cipherfile, plainfile );
3744: }
3745: exit(0); /* no nested parsable info. */
3746: /* strcpy(plainfile,""); /* no further nesting */
3747: /* break; /* no nested parsable info. exit loop. */
3748: } /* key ring. view it. */
3749:
3750: reject: fprintf(stderr,"\a\nError: '%s' is not a cipher, signature, or key file.\n",
3751: cipherfile);
3752: goto user_error;
3753:
3754: } while (TRUE);
3755:
3756: /* No more nested parsable information */
3757:
3758: /* Destroy any sensitive information in scratchfile: */
3759: wipefile( SCRATCH_CTX_FILENAME );
3760: remove( SCRATCH_CTX_FILENAME );
3761:
3762: if (!verbose) /* if other filename messages were supressed */
3763: fprintf(stderr,"\nPlaintext filename: %s ", plainfile);
3764:
3765:
3766: /*---------------------------------------------------------*/
3767:
3768: /* One last thing-- let's attempt to classify some of the more
3769: frequently occurring cases of plaintext output files, as an
3770: aid to the user.
3771:
3772: For example, if output file is a public key, it should have
3773: the right extension on the filename.
3774:
3775: Also, it will likely be common to encrypt PKZIP files, so
3776: they should be renamed with the .zip extension.
3777: */
3778: get_header_info_from_file( plainfile, header, 4 );
3779:
3780: if (header[0] == CTB_CERT_PUBKEY)
3781: { /* Special case--may be public key, worth renaming */
3782: fprintf(stderr, "\nPlaintext file '%s' looks like it contains a public key.",
3783: plainfile );
3784: maybe_force_extension( plainfile, PUB_EXTENSION );
3785: } /* Possible public key output file */
3786:
3787: else
3788: if (pkzipSignature( header ))
3789: { /* Special case--may be a PKZIP file, worth renaming */
3790: fprintf(stderr, "\nPlaintext file '%s' looks like a PKZIP file.",
3791: plainfile );
3792: maybe_force_extension( plainfile, ".zip" );
3793: } /* Possible PKZIP output file */
3794:
3795: else
3796: if ((header[0] == CTB_PKE)
3797: || (header[0] == CTB_SKE)
3798: || (header[0] == CTB_CKE))
3799: { /* Special case--may be another ciphertext file, worth renaming */
3800: fprintf(stderr, "\n\aOutput file '%s' may contain more ciphertext or signature.",
3801: plainfile );
3802: maybe_force_extension( plainfile, ".ctx" );
3803: } /* Possible ciphertext output file */
3804:
3805: exit(0); /* no nested parsable info. */
3806:
3807: } /* Decrypt file, or check signature, or show key */
3808:
3809:
3810: user_error: /* comes here if user made a boo-boo. */
3811: fprintf(stderr,"\nFor more help, consult the PGP User's Guide.");
3812:
3813: usage:
3814: fprintf(stderr,"\nUsage summary:");
3815: fprintf(stderr,"\nTo encrypt a plaintext file with recipent's public key, type:");
3816: fprintf(stderr,"\n pgp -e textfile her_userid (produces textfile.ctx)");
3817: fprintf(stderr,"\nTo sign a plaintext file with your secret key, type:");
3818: fprintf(stderr,"\n pgp -s textfile your_userid (produces textfile.ctx)");
3819: fprintf(stderr,"\nTo sign a plaintext file with your secret key, and then encrypt it "
3820: "\n with recipent's public key, producing a .ctx file:");
3821: fprintf(stderr,"\n pgp -es textfile her_userid your_userid");
3822: fprintf(stderr,"\nTo encrypt with conventional encryption only: pgp -c textfile");
3823: fprintf(stderr,"\nTo decrypt or check a signature for a ciphertext (.ctx) file:");
3824: fprintf(stderr,"\n pgp ciphertextfile [plaintextfile]");
3825: fprintf(stderr,"\nTo generate your own unique public/secret key pair, type: pgp -k");
3826: fprintf(stderr,"\nTo add a public or secret key file's contents to your public "
3827: "\n or secret key ring: pgp -a keyfile [keyring]");
3828: fprintf(stderr,"\nTo remove a key from your public key ring: pgp -r userid [keyring]");
3829: fprintf(stderr,"\nTo view the contents of your public key ring: pgp -v [userid] [keyring] ");
3830: exit(1); /* error exit */
3831:
3832: } /* main */
3833:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.