|
|
1.1.1.2 root 1: /* crypto.c - Cryptographic routines for PGP.
2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
3:
4: (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved.
5: The author assumes no liability for damages resulting from the use
6: of this software, even if the damage results from defects in this
7: software. No warranty is expressed or implied.
8:
9: All the source code Philip Zimmermann wrote for PGP is available for
10: free under the "Copyleft" General Public License from the Free
11: Software Foundation. A copy of that license agreement is included in
12: the source release package of PGP. Code developed by others for PGP
13: is also freely available. Other code that has been incorporated into
14: PGP from other sources was either originally published in the public
15: domain or was used with permission from the various authors. See the
16: PGP User's Guide for more complete information about licensing,
17: patent restrictions on certain algorithms, trademarks, copyrights,
18: and export controls.
19:
20: Modified: 12-Nov-92 HAJK
21: Add FDL stuff for VAX/VMS local mode.
22: Reopen temporary files rather than create new version.
23:
1.1.1.3 ! root 24: Modified: 13-Dec-92 Derek Atkins <[email protected])
! 25: Added Multiple Recipients
! 26:
! 27: Modified 25-Feb-93 Colin Plumb
! 28: Improved security of randseed.bin in strong_pseudorandom.
! 29: Thoroughly revamped make_random_ideakey.
1.1.1.2 root 30: */
31:
32: #include <ctype.h>
33: #include <stdlib.h>
34: #include <stdio.h>
35: #include <string.h>
36: #include <time.h>
37:
38: #include "mpilib.h"
39: #include "mpiio.h"
40: #include "random.h"
41: #include "idea.h"
42: #include "crypto.h"
43: #include "keymgmt.h"
1.1.1.3 ! root 44: #include "keymaint.h"
1.1.1.2 root 45: #include "mdfile.h"
46: #include "fileio.h"
1.1.1.3 ! root 47: #include "charset.h"
1.1.1.2 root 48: #include "language.h"
49: #include "pgp.h"
1.1.1.3 ! root 50: #include "exitpgp.h"
! 51: #include "zipup.h"
1.1.1.2 root 52:
53: #define ENCRYPT_IT FALSE /* to pass to idea_file */
54: #define DECRYPT_IT TRUE /* to pass to idea_file */
55:
1.1.1.3 ! root 56: #define USE_LITERAL2
! 57:
! 58:
! 59: /* This variable stores the md5 hash of the current file, if it is
! 60: available. It is used in open_strong_pseudorandom. */
! 61: static unsigned char md5buf[16];
! 62:
! 63: /* This flag is set if the buffer above has been filled. */
! 64: static char already_have_md5 = 0;
! 65:
! 66:
! 67: /* Used by encryptfile */
! 68: static int encryptkeyintofile(FILE *g, char *mcguffin, byte *keybuf,
! 69: char *keyfile, int ckp_length, int keys_used);
1.1.1.2 root 70:
71: #ifdef M_XENIX
72: long time();
73: #endif
74:
75: /*--------------------------------------------------------------------------*/
76:
77:
78: void CToPascal(char *s)
79: { /* "xyz\0" --> "\3xyz" ... converts C string to Pascal string */
80: int i,j;
81: j = string_length(s);
82: for (i=j; i!=0; i--)
83: s[i] = s[i-1]; /* move everything 1 byte to the right */
84: s[0] = j; /* Pascal length byte at beginning */
85: } /* CToPascal */
86:
87:
88: void PascalToC( char *s )
89: { /* "\3xyz" --> "xyz\0" ... converts Pascal string to C string */
90: int i,j;
91: for (i=0,j=((byte *) s)[0]; i<j; i++)
92: s[i] = s[i+1]; /* move everything 1 byte to the left */
93: s[i] = '\0'; /* append C string terminator */
94: } /* PascalToC */
95:
96:
97: /*
98: Note: On MSDOS, the time() function calculates GMT as the local
99: system time plus a built-in timezone correction, which defaults to
100: adding 7 hours (PDT) in the summer, or 8 hours (PST) in the winter,
101: assuming the center of the universe is on the US west coast. Really--
102: I'm not making this up! The only way to change this is by setting
103: the MSDOS environmental variable TZ to reflect your local time zone,
104: for example "set TZ=MST7MDT". This means add 7 hours during standard
105: time season, or 6 hours during daylight time season, and use MST and
106: MDT for the two names of the time zone. If you live in a place like
107: Arizona with no daylight savings time, use "set TZ=MST7". See the
108: Microsoft C function tzset(). Just in case your local software
109: environment is too weird to predict how to set environmental
110: variables for this, PGP also uses its own TZFIX variable in
111: config.pgp to optionally correct this problem further. For example,
112: set TZFIX=-1 in config.pgp if you live in Colorado and the TZ
113: variable is undefined.
114: */
115:
116: word32 get_timestamp(byte *timestamp)
117: /* Return current timestamp as a byte array in internal byteorder,
118: and as a 32-bit word */
119: { word32 t;
120: t = time(NULL); /* returns seconds since GMT 00:00 1 Jan 1970 */
121:
122: #ifdef _MSC_VER
123: #if (_MSC_VER == 700)
124: /* Under MSDOS and MSC 7.0, time() returns elapsed time since
125: * GMT 00:00 31 Dec 1899, instead of Unix's base date of 1 Jan 1970.
126: * So we must subtract 70 years worth of seconds to fix this.
127: * 6/19/92 rgb
128: */
129: #define LEAP_DAYS (((unsigned long)70L/4)+1)
130: #define CALENDAR_KLUDGE ((unsigned long)86400L * (((unsigned long)365L * 70L) + LEAP_DAYS))
131: t -= CALENDAR_KLUDGE;
132: #endif
133: #endif
134:
135: t += timeshift; /* timeshift derived from TZFIX in config.pgp */
136:
137: if (timestamp != NULL)
138: { /* first, fill array in external byte order: */
139: put_word32(t, timestamp);
140: convert_byteorder(timestamp,4); /* convert to internal byteorder */
141: }
142:
143: return(t); /* return 32-bit timestamp integer */
144: } /* get_timestamp */
145:
146:
1.1.1.3 ! root 147: static int date_ymd(word32 *tstamp, int *year, int *month, int *day)
1.1.1.2 root 148: /* Given timestamp as seconds elapsed since 1970 Jan 1 00:00:00,
149: returns year (1970-2106), month (1-12), day (1-31).
150: Not valid for dates after 2100 Feb 28 (no leap day that year).
151: Also returns day of week (0-6) as functional return.
152: */
153: { word32 days,y;
154: int m,d,i;
155: static short mdays[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
156: days = (*tstamp)/(unsigned long)86400L; /* day 0 is 1970/1/1 */
157: days -= 730L; /* align days relative to 1st leap year, 1972 */
158: y = ((days*4)/(unsigned long)1461L); /* 1972 is year 0 */
159: /* reduce to days elapsed since 1/1 last leap year: */
160: d = (int) (days - ((y/4)*1461L));
161: *year = (int)(y+1972);
162: for (i=0; i<48; i++) /* count months 0-47 */
163: { m = i % 12;
164: d -= mdays[m] + (i==1); /* i==1 is the only leap month */
165: if (d < 0)
166: { d += mdays[m] + (i==1);
167: break;
168: }
169: }
170: *month = m+1;
171: *day = d+1;
172: i = (int)((days-2) % (unsigned long)7L); /* compute day of week 0-6 */
173: return(i); /* returns weekday 0-6; 0=Sunday, 6=Saturday */
174: } /* date_ymd */
175:
176:
177: char *cdate(word32 *tstamp)
178: /* Return date string, given pointer to 32-bit timestamp */
179: { int month,day,year;
180: static char datebuf[20];
181: if (*tstamp == 0)
182: return(" ");
183: (void) date_ymd(tstamp,&year,&month,&day);
184: sprintf(datebuf,"%4d/%02d/%02d", year, month, day);
185: return (datebuf);
186: } /* cdate */
187:
188:
189: char *ctdate(word32 *tstamp)
190: /* Return date and time string, given pointer to 32-bit timestamp */
191: { int hours,minutes;
192: static char tdatebuf[40];
193: long seconds;
194: seconds = (*tstamp) % (unsigned long)86400L; /* seconds past midnight today */
195: minutes = (int)((seconds+30L) / 60L); /* round off to minutes past midnight */
196: hours = minutes / 60; /* hours past midnight */
197: minutes = minutes % 60; /* minutes past the hour */
198: sprintf(tdatebuf,"%s %02d:%02d GMT", cdate(tstamp), hours, minutes);
199: return (tdatebuf);
200: } /* ctdate */
201:
202:
203:
204: /* Warn user he if key in keyfile at position fp of length pktlen, belonging
205: * to userid, is untrusted. Return -1 if the user doesn't want to proceed.
206: */
1.1.1.3 ! root 207: static int warn_signatures(char *keyfile, long fp, char *userid, boolean warn_only)
1.1.1.2 root 208: { FILE *f;
209: long fpusr;
210: int usrpktlen;
211: byte keyctrl;
212: int trust_status = -1;
213:
214: keyctrl = KC_LEGIT_UNKNOWN; /* Assume the worst */
215: if (getpubuserid (keyfile, fp, (byte *) userid, &fpusr, &usrpktlen, FALSE) >= 0)
216: { f = fopen(keyfile, FOPRBIN);
217: fseek (f, fpusr+usrpktlen, SEEK_SET);
218: /* Read trust byte */
219: trust_status = read_trust(f, &keyctrl);
220: fseek(f, fp, SEEK_SET);
221: if (is_compromised(f))
222: {
223: CToPascal(userid);
224: fprintf(pgpout, "\n");
225: show_key(f, fp, 0);
226: fclose (f);
227: fprintf(pgpout, PSTR("\007\nWARNING: This key has been revoked by its owner,\n\
228: possibly because the secret key was compromised.\n"));
229: if (warn_only)
230: { /* this is only for checking signatures */
231: fprintf(pgpout, PSTR("This could mean that this signature is a forgery.\n"));
232: return(1);
233: }
234: else
235: { /* don't use it for encryption */
236: fprintf(pgpout, PSTR("You cannot use this revoked key.\n"));
237: return(-1);
238: }
239: }
240: fclose (f);
241: }
242: CToPascal(userid);
243: if ((keyctrl & KC_LEGIT_MASK) != KC_LEGIT_COMPLETE)
244: { byte userid0[256];
245: PascalToC(userid);
246: strcpy ((char *) userid0, userid);
247: CToPascal(userid);
1.1.1.3 ! root 248:
1.1.1.2 root 249: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_UNKNOWN)
250: fprintf(pgpout,PSTR("\007\nWARNING: Because this public key is not certified with a trusted\n\
251: signature, it is not known with high confidence that this public key\n\
252: actually belongs to: \"%s\".\n"), LOCAL_CHARSET((char *)userid0));
1.1.1.3 ! root 253:
1.1.1.2 root 254: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_UNTRUSTED)
255: fprintf(pgpout, PSTR("\007\nWARNING: This public key is not trusted to actually belong to:\n\
256: \"%s\".\n"), LOCAL_CHARSET((char *)userid0));
1.1.1.3 ! root 257:
1.1.1.2 root 258: if ((keyctrl & KC_LEGIT_MASK) == KC_LEGIT_MARGINAL)
259: fprintf(pgpout,PSTR("\007\nWARNING: Because this public key is not certified with enough trusted\n\
260: signatures, it is not known with high confidence that this public key\n\
261: actually belongs to: \"%s\".\n"), LOCAL_CHARSET((char *)userid0));
1.1.1.3 ! root 262:
! 263: if (keyctrl & KC_WARNONLY)
! 264: { /* KC_WARNONLY bit already set, user must have approved before. */
! 265: fprintf(pgpout, PSTR("But you previously approved using this public key anyway.\n"));
! 266: }
! 267:
! 268: if (!filter_mode && !batchmode && !warn_only && !(keyctrl & KC_WARNONLY))
1.1.1.2 root 269: { fprintf(pgpout,PSTR("\nAre you sure you want to use this public key (y/N)? "));
270: if (!getyesno('n'))
271: return(-1);
272: if (trust_status == 0 && (f = fopen(keyfile, FOPRWBIN)) != NULL)
273: { fseek (f, fpusr+usrpktlen, SEEK_SET);
274: keyctrl |= KC_WARNONLY;
275: write_trust(f, keyctrl);
276: fclose(f);
277: }
278: }
279: }
280: return(0);
281: } /* warn_signatures */
282:
283:
284: boolean legal_ctb(byte ctb)
285: { /* Used to determine if nesting should be allowed. */
286: boolean legal;
287: byte ctbtype;
288: if (!is_ctb(ctb)) /* not even a bonafide CTB */
289: return(FALSE);
290: /* Sure hope CTB internal bit definitions don't change... */
291: ctbtype = (ctb & CTB_TYPE_MASK) >> 2;
292: /* Only allow these CTB types to be nested... */
293: legal = (
294: (ctbtype==CTB_PKE_TYPE)
295: || (ctbtype==CTB_SKE_TYPE)
296: || (ctbtype==CTB_CERT_SECKEY_TYPE)
297: || (ctbtype==CTB_CERT_PUBKEY_TYPE)
298: || (ctbtype==CTB_LITERAL_TYPE)
299: || (ctbtype==CTB_LITERAL2_TYPE)
300: || (ctbtype==CTB_COMPRESSED_TYPE)
301: || (ctbtype==CTB_CKE_TYPE)
302: );
303: return(legal);
304: } /* legal_ctb */
305:
306:
307: /* Return nonzero if val doesn't match checkval, after printing a
308: * warning.
309: */
310: int
311: version_error(int val, int checkval)
312: { if (val != checkval)
313: { fprintf (pgpout, PSTR(
314: "\n\007Unsupported packet format - you need a newer version of PGP for this file.\n"));
315: return(1);
316: }
317: return(0);
318: }
319:
320: /*-------------------------------------------------------------------------*/
321:
1.1.1.3 ! root 322: #define RAND_PREFIX_LENGTH 8 /* Length of IV for IDEA encryption */
1.1.1.2 root 323:
1.1.1.3 ! root 324: int seedfile_exists(void)
! 325: /*
! 326: If the file randseed.bin does not exist, this returns 0 and
! 327: schedules the appropriate number of random bytes for later
! 328: collection from the keyboard.
! 329: */
1.1.1.2 root 330: { char seedfile[MAX_PATH]; /* Random seed filename */
331:
332: buildfilename(seedfile,RANDSEED_FILENAME);
1.1.1.3 ! root 333: if (file_exists(seedfile))
! 334: return 1; /* True */
! 335: randaccum_later(8*(IDEAKEYSIZE+RAND_PREFIX_LENGTH));
! 336: return 0;
! 337: }
1.1.1.2 root 338:
1.1.1.3 ! root 339: void create_seedfile(void)
! 340: /*
! 341: Create the seedfile, from the random bits that seedfile_exists
! 342: buffered for accumulation. "randseed.bin" is used to generate
! 343: cryptographically strong pseudorandom numbers for session keys.
! 344: */
! 345: { char seedfile[MAX_PATH]; /* Random seed filename */
! 346: FILE *f;
! 347: byte randbuf[IDEAKEYSIZE+RAND_PREFIX_LENGTH];
! 348: int i;
1.1.1.2 root 349:
1.1.1.3 ! root 350: buildfilename(seedfile,RANDSEED_FILENAME);
1.1.1.2 root 351:
1.1.1.3 ! root 352: f = fopen(seedfile,FOPWBIN); /* open for writing binary */
! 353: if (f==NULL) /* failed to create seedfile */
! 354: return; /* error: no random number seed file available */
! 355: fprintf(pgpout,PSTR("Initializing random seed file..."));
! 356: /* This is not part of the string above because it was changed after the 2.2
! 357: release translations were started. It should be cleaned up eventually. */
! 358: fputc('\n', pgpout);
! 359: for (i=1; i<sizeof(randbuf); i++)
! 360: randbuf[i] ^= randombyte();
! 361: #ifdef VMS
! 362: fseek (f, 0, SEEK_SET);
! 363: #endif
! 364: fwrite(randbuf,1,sizeof(randbuf),f);
! 365: fclose(f);
! 366: burn(randbuf); /* Not terribly sensitive, but... */
! 367: }
1.1.1.2 root 368:
1.1.1.3 ! root 369: static int open_strong_pseudorandom(byte key[16], byte buf[24])
! 370: /* Read the randseed.bin file, encrypting it on the way with the given
! 371: key. It is intended that this key is the md5 of the message to be
! 372: encrypted, which is unpredictable to a would-be attacker who does
! 373: not posess the message. This is simply a way to get some "random"
! 374: bytes without a random number source. This "prewash" attempts to
! 375: reduce the value of a captured randseed.bin file.
! 376: Returns the length of the resultant data, or -1 in case of error. */
! 377: { char seedfile[MAX_PATH]; /* Random seed filename */
! 378: FILE *f;
! 379: static word16 iv0[4] = {0, 0, 0, 0};
! 380:
! 381: buildfilename(seedfile,RANDSEED_FILENAME);
1.1.1.2 root 382:
1.1.1.3 ! root 383: if (!file_exists(seedfile)) /* No seed file - not available. */
! 384: return(-1);
! 385: f = fopen(seedfile,FOPRBIN); /* open for reading binary */
! 386: if (f==NULL) /* did open fail? */
! 387: return(-1); /* error: no random number seed file available */
! 388: /* read IDEA random generator key */
! 389: if (fread(buf,1,sizeof(buf),f) < sizeof(buf)) /* empty file? */
! 390: { /* Empty or nearly empty file means don't use it. */
! 391: fclose(f);
! 392: return(-1); /* error: no random number seed file available */
! 393: }
! 394: initcfb_idea(iv0, key, FALSE);
! 395: ideacfb(buf, 24);
! 396: burn(iv0);
! 397: return 24;
! 398: }
1.1.1.2 root 399:
1.1.1.3 ! root 400: static int close_strong_pseudorandom(byte ideakey[IDEAKEYSIZE+RAND_PREFIX_LENGTH])
! 401: /* Using the same key and initial vector that is used to encrypt the
! 402: user's message, encrypt some pseudorandom bytes to produce the
! 403: new randseed.bin. The hope is that this "postwash" renders it is
! 404: at least as hard to derive old session keys from randseed.bin as it
! 405: is to crack the the message directly.
! 406: Note that this function leaves idearand() running; you must
! 407: call close_idearand() separately. */
! 408:
! 409: { static word16 iv0[4] = {0, 0, 0, 0};
! 410: byte buf[IDEAKEYSIZE+RAND_PREFIX_LENGTH];
! 411: char seedfile[MAX_PATH]; /* Random seed filename */
! 412: FILE *f;
! 413: int i;
! 414:
! 415: buildfilename(seedfile,RANDSEED_FILENAME);
1.1.1.2 root 416: f = fopen(seedfile,FOPWBIN); /* open for writing binary */
417: if (f==NULL) /* did open fail? */
418: return(-1); /* error: no random number seed file available */
1.1.1.3 ! root 419: initcfb_idea(iv0, ideakey, FALSE); /* Start encryption */
! 420: memcpy(buf, ideakey+IDEAKEYSIZE, RAND_PREFIX_LENGTH);
! 421: memcpy(buf+RAND_PREFIX_LENGTH, buf+RAND_PREFIX_LENGTH-2, 2);
! 422: ideacfb(buf, RAND_PREFIX_LENGTH+2); /* Feed IV through */
! 423:
! 424: for (i = 0; i < sizeof(buf); i++) /* Get message to encrypt */
! 425: buf[i] = idearand();
! 426: ideacfb(buf, sizeof(buf)); /* Encrypt it */
1.1.1.2 root 427: #ifdef VMS
428: fseek (f, 0, SEEK_SET);
429: #endif
430: /* Now at start of file again */
1.1.1.3 ! root 431: i = fwrite(buf,1,sizeof(buf),f); /* Write it out */
1.1.1.2 root 432: fclose(f);
1.1.1.3 ! root 433: burn(iv0); /* Burn all data */
! 434: burn(buf);
! 435: close_idea();
! 436:
! 437: if (i != sizeof(buf))
! 438: return -1; /* error */
! 439: return i;
! 440: }
1.1.1.2 root 441:
1.1.1.3 ! root 442: static int make_random_ideakey(byte key[IDEAKEYSIZE+RAND_PREFIX_LENGTH])
! 443: /* Make a random IDEA key. Returns its length (the constant 16).
! 444: It also generates a random IV, which is placed in the key array
! 445: after the key proper, but is not counted in the length.
! 446: Reads IDEA random key and random number seed from file, cranks the
! 447: seed through the idearand strong pseudorandom number generator,
! 448: and writes them back out. This is used for generation of
! 449: cryptographically strong pseudorandom numbers. This is mainly to
! 450: save the user the trouble of having to type in lengthy keyboard
! 451: sequences for generation of truly random numbers every time we want
! 452: to make a random session key. This pseudorandom generator will only
! 453: work if the file containing the random seed exists and is not empty.
! 454: If this is not the case, it will be automatically created.
! 455: */
! 456: {
! 457: word32 tstamp;
! 458: int count;
1.1.1.2 root 459:
1.1.1.3 ! root 460: if (open_strong_pseudorandom(md5buf, key) < 0)
! 461: {
! 462: fprintf(pgpout,PSTR("Preparing random session key..."));
1.1.1.2 root 463:
1.1.1.3 ! root 464: randaccum((IDEAKEYSIZE+RAND_PREFIX_LENGTH)*8);
! 465: /* get some random key bits */
1.1.1.2 root 466:
1.1.1.3 ! root 467: for (count = 0; count < IDEAKEYSIZE+RAND_PREFIX_LENGTH; count++)
! 468: key[count] = randombyte();
! 469: }
1.1.1.2 root 470:
1.1.1.3 ! root 471: get_timestamp((byte *)&tstamp);
! 472: init_idearand(key, key+IDEAKEYSIZE, tstamp);
1.1.1.2 root 473:
1.1.1.3 ! root 474: /* Generate a good random IDEA key and initial vector */
! 475: /* If we have no random bytes, the randombyte() part will be useless */
! 476: count = IDEAKEYSIZE+RAND_PREFIX_LENGTH;
! 477: while (count--)
! 478: key[count] = idearand() ^ try_randombyte();
1.1.1.2 root 479:
1.1.1.3 ! root 480: /* Write out a new randseed.bin */
! 481: close_strong_pseudorandom(key);
! 482:
! 483: return IDEAKEYSIZE;
! 484: }
1.1.1.2 root 485:
486:
487: word32 getpastlength(byte ctb, FILE *f)
488: /* Returns the length of a packet according to the CTB and
489: the length field. */
490: { word32 length;
491: unsigned int llength; /* length of length */
492: byte buf[8];
493:
494: fill0(buf,sizeof(buf));
495: length = 0L;
496: /* Use ctb length-of-length field... */
497: llength = ctb_llength(ctb); /* either 1, 2, 4, or 8 */
498: if (llength==8) /* 8 means no length field, assume huge length */
499: return(-1L); /* return huge length */
500:
501: /* now read in the actual length field... */
502: if (fread((byteptr) buf,1,llength,f) < llength)
503: return (-2L); /* error -- read failure or premature eof */
504: /* convert length from external byteorder... */
505: if (llength==1)
506: length = (word32) buf[0];
507: if (llength==2)
508: length = (word32) fetch_word16(buf);
509: if (llength==4)
510: length = fetch_word32(buf);
511: return(length);
512: } /* getpastlength */
513:
514:
515: /* Write a CTB with the appropriate length field. If big is true,
516: * always use a four-byte length field.
517: */
518: void write_ctb_len (FILE *f, byte ctb_type, word32 length, boolean big)
519: {
520: int llength, llenb;
521: byte ctb;
522: byte buf[4];
523:
524: if (big || (length > 0xFFFFL))
525: { llength = 4;
526: llenb = 2;
527: }
528: else if ((word16)length > 0xFF)
529: { llength = 2;
530: llenb = 1;
531: }
532: else
533: { llength = 1;
534: llenb = 0;
535: }
536: ctb = CTB_BYTE(ctb_type, llenb);
537: fwrite( &ctb, 1, 1, f );
538: /* convert length to external byteorder... */
539: if (llength==1)
540: buf[0] = length;
541: if (llength==2)
542: put_word16((word16) length, buf);
543: if (llength==4)
544: put_word32(length, buf);
545: fwrite( buf, 1, llength, f );
546: } /* write_ctb_len */
547:
548:
1.1.1.3 ! root 549: static
1.1.1.2 root 550: int idea_file(byte *ideakey, boolean decryp, FILE *f, FILE *g, word32 lenfile)
551: /* Use IDEA in cipher feedback (CFB) mode to encrypt or decrypt a file.
552: The encrypted material starts out with a 64-bit random prefix, which
553: serves as an encrypted random CFB initialization vector, and
554: following that is 16 bits of "key check" material, which is a
555: duplicate of the last 2 bytes of the random prefix. Encrypted key
556: check bytes detect if correct IDEA key was used to decrypt ciphertext.
557: */
558: { int count, status = 0;
559: word16 iv[4];
560: extern byte textbuf[DISKBUFSIZE];
561: #define RAND_PREFIX_LENGTH 8
562:
563: /* init CFB key */
564: fill0(iv,sizeof(iv)); /* define initialization vector IV as 0 */
565: initcfb_idea(iv,ideakey,decryp);
566:
567: if (!decryp) /* encrypt-- insert key check bytes */
568: { /* There is a random prefix followed by 2 key check bytes */
569:
1.1.1.3 ! root 570: memcpy(textbuf, ideakey+IDEAKEYSIZE, RAND_PREFIX_LENGTH);
1.1.1.2 root 571: /* key check bytes are simply duplicates of final 2 random bytes */
1.1.1.3 ! root 572: textbuf[RAND_PREFIX_LENGTH] = textbuf[RAND_PREFIX_LENGTH-2];
! 573: textbuf[RAND_PREFIX_LENGTH+1] = textbuf[RAND_PREFIX_LENGTH-1];
1.1.1.2 root 574:
575: ideacfb(textbuf,RAND_PREFIX_LENGTH+2);
576: fwrite(textbuf,1,RAND_PREFIX_LENGTH+2,g);
577: }
578: else /* decrypt-- check for key check bytes */
579: { /* See if the redundancy is present after the random prefix */
580: count = fread(textbuf,1,RAND_PREFIX_LENGTH+2,f);
581: lenfile -= count;
582: if (count==(RAND_PREFIX_LENGTH+2))
583: { ideacfb(textbuf,RAND_PREFIX_LENGTH+2);
584: if ((textbuf[RAND_PREFIX_LENGTH] != textbuf[RAND_PREFIX_LENGTH-2])
585: || (textbuf[RAND_PREFIX_LENGTH+1] != textbuf[RAND_PREFIX_LENGTH-1]))
1.1.1.3 ! root 586: { status = -2; /* bad key error */
1.1.1.2 root 587: }
588: }
589: else /* file too short for key check bytes */
1.1.1.3 ! root 590: status = -3; /* error of the weird kind */
1.1.1.2 root 591: }
592:
593:
1.1.1.3 ! root 594: /* read and write the whole file in CFB mode... */
! 595: count = (lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE;
! 596: while (count && status == 0)
! 597: { if ((count = fread(textbuf,1,count,f)) <= 0)
! 598: { status = -3;
! 599: break;
1.1.1.2 root 600: }
1.1.1.3 ! root 601: lenfile -= count;
! 602: ideacfb(textbuf,count);
! 603: if (fwrite(textbuf,1,count,g) != count)
! 604: status = -3;
! 605: count = (lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE;
! 606: }
1.1.1.2 root 607:
608: close_idea(); /* Clean up data structures */
609: burn(iv); /* burn sensitive data on stack */
610: burn(textbuf); /* burn sensitive data on stack */
611: return(status); /* should always take normal return */
612: } /* idea_file */
613:
614:
615: /* Checksum maintained as a running sum by read_mpi and write_mpi.
616: * The checksum is maintained based on the plaintext values being
617: * read and written. To use it, store a 0 to it before doing a set
618: * of read_mpi's or write_mpi's. Then read it aftwerwards.
619: */
620: word16 mpi_checksum;
621:
622: int read_mpi(unitptr r, FILE *f, boolean adjust_precision, boolean scrambled)
623: /* Read a mutiprecision integer from a file.
624: adjust_precision is TRUE iff we should call set_precision to the
625: size of the number read in.
626: scrambled is TRUE iff field is encrypted (protects secret key fields).
627: Returns the bitcount of the number read in, or returns a negative
628: number if an error is detected.
629: */
630: { byte buf[MAX_BYTE_PRECISION+2];
631: unsigned int count;
632: word16 bytecount,bitcount;
633:
634: mp_init(r,0);
635:
636: if ((count = fread(buf,1,2,f)) < 2)
637: return (-1); /* error -- read failure or premature eof */
638:
639: bitcount = fetch_word16(buf);
640: if (bits2units(bitcount) > global_precision)
641: return(-1); /* error -- possible corrupted bitcount */
642:
643: bytecount = bits2bytes(bitcount);
644:
645: count = fread(buf+2,1,bytecount,f);
646: if (count < bytecount)
647: return(-1); /* error -- premature eof */
648:
649: if (scrambled) /* decrypt the field */
650: ideacfb(buf+2,bytecount);
651:
652: /* Update running checksum, in case anyone cares... */
653: mpi_checksum += checksum (buf, bytecount+2);
654:
655: /* We assume that the bitcount prefix we read is an exact
656: bitcount, not rounded up to the next byte boundary.
657: Otherwise we would have to call mpi2reg, then call
658: countbits, then call set_precision, then recall mpi2reg
659: again.
660: */
661: if (adjust_precision && bytecount)
662: { /* set the precision to that specified by the number read. */
663: if (bitcount > MAX_BIT_PRECISION-SLOP_BITS)
664: return(-1);
665: set_precision(bits2units(bitcount+SLOP_BITS));
666: /* Now that precision is optimally set, call mpi2reg */
667: }
668:
669: if (mpi2reg(r,buf) == -1) /* convert to internal format */
670: return(-1);
671: burn(buf); /* burn sensitive data on stack */
672: return (bitcount);
673: } /* read_mpi */
674:
675:
676:
677: void write_mpi(unitptr n, FILE *f, boolean scrambled)
678: /* Write a multiprecision integer to a file.
679: scrambled is TRUE iff we should scramble field on the way out,
680: which is used to protect secret key fields.
681: */
682: { byte buf[MAX_BYTE_PRECISION+2];
683: short bytecount;
684: bytecount = reg2mpi(buf,n);
685: mpi_checksum += checksum (buf, bytecount+2);
686: if (scrambled) /* encrypt the field, skipping over the bitcount */
687: ideacfb(buf+2,bytecount);
688: fwrite(buf,1,bytecount+2,f);
689: burn(buf); /* burn sensitive data on stack */
690: } /* write_mpi */
691:
692:
693: /*======================================================================*/
694:
695:
696: int get_header_info_from_file(char *infile, byte *header, int count)
697: /* Reads the first count bytes from infile into header. */
698: { FILE *f;
699: fill0(header,count);
700: /* open file f for read, in binary (not text) mode...*/
701: if ((f = fopen(infile,FOPRBIN)) == NULL)
702: return(-1);
703: /* read Cipher Type Byte, and maybe more */
704: count = fread(header,1,count,f);
705: fclose(f);
706: return(count); /* normal return */
707: } /* get_header_info_from_file */
708:
709:
710: /* System clock must be broken if it isn't past this date: */
711: #define REASONABLE_DATE ((unsigned long) 0x27804180L) /* 91 Jan 01 00:00:00 */
712:
713:
1.1.1.3 ! root 714: static
1.1.1.2 root 715: int make_signature_certificate(byte *certificate, MD5_CTX *MD, byte class,
716: unitptr n, unitptr d, unitptr p, unitptr q, unitptr u)
717: /* Constructs a signed message digest in a signature certificate.
718: Returns total certificate length in bytes, or returns negative
719: error status.
720: */
721: {
722: byte inbuf[MAX_BYTE_PRECISION], outbuf[MAX_BYTE_PRECISION];
723: byte mdpacket[17];
724: byte *mdbufptr;
725: int i,j,certificate_length,blocksize,bytecount;
726: word16 ske_length;
727: word32 tstamp; byte *timestamp = (byte *) &tstamp;
728: byte keyID[KEYFRAGSIZE];
729: byte val;
730: int mdlen = 5; /* length of class plus timestamp, for adding to MD */
731:
732: /* Note that RSA key must be at least big enough to encipher a
733: complete message digest packet in a single RSA block. */
734:
735: blocksize = countbytes(n)-1; /* size of a plaintext block */
736: if (blocksize < 31)
737: { fprintf(pgpout,"\n\007Error: RSA key length must be at least 256 bits.\n");
738: return(-1);
739: }
740:
741: get_timestamp(timestamp); /* Timestamp when signature was made */
742: if (tstamp < REASONABLE_DATE) /* complain about bad time/date setting */
743: { fprintf(pgpout,PSTR("\n\007Error: System clock/calendar is set wrong.\n"));
744: return(-1);
745: }
746: convert_byteorder(timestamp,4); /* convert to external form */
747:
748: /* Finish off message digest calculation with this information */
749: MD_addbuffer (MD, &class, 1, FALSE);
750: MD_addbuffer (MD, timestamp, 4, TRUE);
751:
1.1.1.3 ! root 752: #ifdef PKCS_COMPAT
! 753: /* Pre-block digest, and convert to INTERNAL byte order: */
! 754: preblock((unitptr)inbuf, MD->digest, sizeof(MD->digest), n, NULL);
! 755: #else /* ! PKCS_COMPAT */
! 756: /* Assume MSB external byte ordering */
1.1.1.2 root 757: mdpacket[0] = MD5_ALGORITHM_BYTE;
758: mdbufptr = MD->digest; /* point at actual message digest */
759: for (i=1; i<sizeof(mdpacket); i++)
760: { mdpacket[i] = *mdbufptr++;
761: }
762: /* Pre-block mdpacket, and convert to INTERNAL byte order: */
763: preblock((unitptr)inbuf, mdpacket, sizeof(mdpacket), n, NULL);
1.1.1.3 ! root 764: #endif PKCS_COMPAT
1.1.1.2 root 765:
1.1.1.3 ! root 766: if (!quietmode)
1.1.1.2 root 767: { fprintf(pgpout,PSTR("Just a moment...")); /* RSA will take a while. */
768: fflush(pgpout);
769: }
770:
771: /* do RSA signature calculation: */
772: rsa_decrypt((unitptr)outbuf,(unitptr)inbuf,d,p,q,u);
773:
774: /* bytecount does not include the 2 prefix bytes */
775: bytecount = reg2mpi(outbuf,(unitptr)outbuf); /* convert to external format */
776: /* outbuf now contains a message digest in external byteorder
777: form. Now make a complete signature certificate from this.
778: */
779:
780: certificate_length = 0;
781:
782: /* SKE is Secret Key Encryption (signed). Append CTB for signed msg. */
783: certificate[certificate_length++] = CTB_SKE;
784:
785: /* SKE packet length does not include itself or CTB prefix: */
786: ske_length = 1 + 1 /* version and mdlen byte */
787: + mdlen /* class, timestamp and validation period */
788: + KEYFRAGSIZE + 1 + 1 /* Key ID and 2 algorithm bytes */
789: + 2 + bytecount+2; /* 2 MD bytes and RSA MPI w/bitcount */
790: put_word16((word16) ske_length, certificate+certificate_length);
791: certificate_length+=2; /* advance past word */
792:
793: certificate[certificate_length++] = VERSION_BYTE;
794:
795: /* Begin fields that are included in MD calculation... */
796:
797: certificate[certificate_length++] = mdlen; /* mdlen is length of MD-extras */
798:
799: certificate[certificate_length++] = class & 0xff;
800: mdlen--; /* assume class byte always present */
801:
802: /* timestamp already in external format */
803: if (mdlen>0)
804: { for (j=0; j<SIZEOF_TIMESTAMP; j++)
805: { certificate[certificate_length++] = timestamp[j];
806: mdlen--;
807: }
808: }
809:
810: /* if any bytes remain in mdlen, assume it's the validation period */
811: if (mdlen>0)
812: { val = 0; /* Validation period */
813: put_word16(val, certificate+certificate_length);
814: certificate_length+=2; /* advance past word */
815: mdlen-=2;
816: }
817: /* hopefully, mdlen is now zero. */
818:
819: /* ...end of fields that are included in MD calculation */
820:
821: /* Now append keyID... */
822: extract_keyID(keyID, n); /* gets keyID */
823: for (i=0; i<KEYFRAGSIZE; i++)
824: certificate[certificate_length++] = keyID[i];
825:
826: certificate[certificate_length++] = RSA_ALGORITHM_BYTE;
827: certificate[certificate_length++] = MD5_ALGORITHM_BYTE;
828:
829: /* Now append first two bytes of message digest */
830: mdbufptr = MD->digest;
831: certificate[certificate_length++] = *mdbufptr++;
832: certificate[certificate_length++] = *mdbufptr++;
833:
834: /* Now append the RSA-signed message digest packet: */
835: for (i=0; i<bytecount+2; i++)
836: certificate[certificate_length++] = outbuf[i];
837:
1.1.1.3 ! root 838: if (!quietmode)
1.1.1.2 root 839: fputc('.',pgpout); /* Signal RSA signature completion. */
840:
841: burn(inbuf); /* burn sensitive data on stack */
842: burn(outbuf); /* burn sensitive data on stack */
843:
844: return(certificate_length); /* return length of certificate in bytes */
845:
846: } /* make_signature_certificate */
847:
848:
849: #ifdef VMS
850: void write_litlocal(FILE *g, char *fdl, short fdl_len)
851: {
852: /*
853: * Local mode VMS, we write out the word VMS to say who owns the data then we follow
854: * that with the file's FDL generated earlier by fdl_generate(). This FDL is preceded
855: * by a sixteen bit size. The file follows.
856: */
857: fputc('\0', g); /* Kludge for null literal file name (supplied by FDL) */
858: fputs("VMS ", g);
859: fwrite(&fdl_len, 2, 1, g); /* Byte order *not* important, only VMS reads this!*/
860: fwrite(fdl, 1, fdl_len, g);
861: }
862: #endif /* VMS */
863:
864: /*======================================================================*/
865:
866:
867: int signfile(boolean nested, boolean separate_signature,
868: char *mcguffin, char *infile, char *outfile,
869: char lit_mode, char *literalfile)
870: /* Write an RSA-signed message digest of input file to specified
871: output file, and append input file to output file.
872: separate_signature is TRUE iff we should not append the
873: plaintext to the output signature certificate.
874: If lit_mode is MODE_TEXT, we know the infile is in canonical form.
875: We create a CTB_LITERAL packet for the plaintext data.
876: */
877: {
878: FILE *f;
879: FILE *g;
880: int certificate_length; /* signature certificate length */
881: byte certificate[MAX_SIGCERT_LENGTH];
882: char lfile[MAX_PATH];
883: byte signature_class;
884: #ifdef VMS
885: char *fdl;
886: short fdl_len;
887: #endif /* VMS */
888:
889:
890: { /* temporary scope for some buffers */
891: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
892: byte userid[256];
893: char keyfile[MAX_PATH];
1.1.1.3 ! root 894: int status;
1.1.1.2 root 895: MD5_CTX MD;
896: byte keyID[KEYFRAGSIZE];
897: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
898: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
899:
900: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
901:
902: if (verbose)
903: fprintf(pgpout,"signfile: infile = '%s', outfile = '%s', mode = '%c', literalfile = '%s'\n",
904: infile,outfile,lit_mode,literalfile);
905:
906: if (MDfile(&MD, infile) < 0)
907: return(-1); /* problem with input file. error return */
908:
1.1.1.3 ! root 909: /* Preserve MD5 hash as a source of random numbers */
! 910: memcpy(md5buf, &MD.digest, 16);
! 911: already_have_md5 = 1;
! 912:
1.1.1.2 root 913: userid[0] = '\0';
914: if (mcguffin)
915: strcpy((char *) userid,mcguffin); /* Who we are looking for */
916:
1.1.1.3 ! root 917: if (getsecretkey(0, NULL, NULL, timestamp, NULL, NULL,
1.1.1.2 root 918: userid, n, e, d, p, q, u) < 0)
919: return(-1); /* problem with secret key file. error return. */
920:
921: extract_keyID(keyID, n);
922: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
1.1.1.3 ! root 923: if ((status = getpublickey(GPK_SHOW|GPK_NORVK, keyfile, NULL, NULL, keyID,
! 924: timestamp, userid, n, e)) < 0)
1.1.1.2 root 925: return(-1); /* problem with public key file. error return. */
926:
927: if (lit_mode==MODE_TEXT) signature_class = SM_SIGNATURE_BYTE;
928: else signature_class = SB_SIGNATURE_BYTE;
929:
930: certificate_length = make_signature_certificate(certificate, &MD,
931: signature_class, n, d, p, q, u);
932: if (certificate_length < 0)
933: return(-1); /* error return from make_signature_certificate() */
934: } /* end of scope for some buffers */
935:
936: /* open file f for read, in binary (not text) mode...*/
937: #ifdef VMS
938: if (lit_mode == MODE_LOCAL) {
939: if (!(fdl_generate(infile, &fdl, &fdl_len ) & 01)) {
940: fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile);
941: return(-1);
942: }
943: }
944: #endif /* VMS */
945: if ((f = fopen(infile,FOPRBIN)) == NULL)
946: { fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"),infile);
947: return(-1);
948: }
949:
950: /* open file g for write, in binary (not text) mode...*/
951: if ((g = fopen(outfile,FOPWBIN)) == NULL)
952: { fprintf(pgpout,PSTR("\n\007Can't create signature file '%s'\n"),outfile);
953: fclose(f);
954: return(-1);
955: }
956:
957: /* write out certificate record to outfile ... */
958: fwrite(certificate,1,certificate_length,g);
959:
960: if (literalfile == NULL)
961: { /* Put in a zero byte to indicate no filename */
962: lfile[0] = '\0';
963: }
964: else
965: { strcpy( lfile, literalfile );
966: file_to_canon( lfile );
967: CToPascal( lfile );
968: }
969:
970: if (!separate_signature)
971: { if (!nested)
972: { word32 flen = fsize(f);
973: word32 dummystamp = 0;
974: if (lit_mode == MODE_LOCAL)
975: #ifdef VMS
976: write_ctb_len (g, CTB_LITERAL2_TYPE,
977: flen + fdl_len + sizeof(fdl_len) + 6, TRUE);
978: #else
979: /* debug check: should never get here */
980: fprintf(pgpout, "signfile: invalid mode\n");
981: #endif
982: else
983: #ifdef USE_LITERAL2
984: write_ctb_len (g, CTB_LITERAL2_TYPE, flen + (unsigned char) lfile[0] + 6, FALSE);
985: #else
986: write_ctb_len (g, CTB_LITERAL_TYPE, flen, FALSE);
987: #endif /* USE_LITERAL2 */
988: fwrite ( &lit_mode, 1, 1, g ); /* write lit_mode */
989: if (lit_mode == MODE_LOCAL) {
990: #ifdef VMS
991: write_litlocal( g, fdl, fdl_len);
992: free(fdl);
993: #endif /* VMS */
994: } else {
995: /* write literalfile name */
996: fwrite (lfile, 1, (unsigned char) lfile[0]+1, g);
997: /* Dummy file creation timestamp */
998: fwrite ( &dummystamp, 1, sizeof(dummystamp), g);
999: }
1000: }
1001: copyfile(f,g,-1L); /* copy rest of file from file f to g */
1002: }
1003:
1004: fclose(f);
1005: if (write_error(g))
1006: { fclose(g);
1007: return(-1);
1008: }
1009: fclose(g);
1010: return(0); /* normal return */
1011:
1012: } /* signfile */
1013:
1014:
1015: /*======================================================================*/
1016:
1017:
1.1.1.3 ! root 1018: int compromise(byte *keyID, char *keyfile)
1.1.1.2 root 1019: {
1020: FILE *f, *g;
1021: byte ctb; /* Cipher Type Byte */
1022: int certificate_length; /* signature certificate length */
1023: byte certificate[MAX_SIGCERT_LENGTH];
1024: word32 tstamp; byte *timestamp = (byte *) &tstamp;
1025: byte userid[256];
1026: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1027: MD5_CTX MD;
1028: unit d[MAX_UNIT_PRECISION];
1029: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
1030: long fp, insertpos;
1031: int pktlen;
1032: int prec;
1033: char *scratchf;
1034:
1035: setoutdir(keyfile);
1036: scratchf = tempfile(0);
1037:
1.1.1.3 ! root 1038: if (getsecretkey(0, NULL, keyID, timestamp, NULL, NULL,
1.1.1.2 root 1039: userid, n, e, d, p, q, u) < 0)
1040: return(-1); /* problem with secret key file. error return. */
1041:
1.1.1.3 ! root 1042: if (getpublickey(0, keyfile, &fp, &pktlen, keyID,
! 1043: timestamp, userid, n, e) < 0)
1.1.1.2 root 1044: return(-1);
1045:
1046: /* open file f for read, in binary (not text) mode...*/
1047: if ((f = fopen(keyfile,FOPRBIN)) == NULL)
1048: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile);
1049: return(-1);
1050: }
1051:
1052: fseek (f, fp+pktlen, SEEK_SET);
1053: nextkeypacket(f, &ctb);
1054: if (ctb == CTB_KEYCTRL)
1055: { insertpos = ftell(f);
1056: nextkeypacket(f, &ctb);
1057: }
1058: else
1059: insertpos = fp + pktlen;
1060:
1061: if (is_ctb_type(ctb, CTB_SKE_TYPE))
1062: {
1063: fprintf(pgpout, PSTR("This key has already been revoked.\n"));
1064: fclose(f);
1065: return(-1);
1066: }
1067:
1068: prec = global_precision;
1069: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1070:
1071: fseek(f, fp, SEEK_SET);
1072: /* Calculate signature */
1073: if (MDfile0_len(&MD, f, pktlen) < 0)
1074: { fclose(f);
1075: return(-1); /* problem with input file. error return */
1076: }
1077: set_precision(prec);
1078:
1079: certificate_length = make_signature_certificate(certificate, &MD,
1080: KC_SIGNATURE_BYTE, n, d, p, q, u);
1081: if (certificate_length < 0)
1082: { fclose(f);
1083: return(-1); /* error return from make_signature_certificate() */
1084: }
1085:
1086:
1087: /* open file g for write, in binary (not text) mode...*/
1088: if ((g = fopen(scratchf,FOPWBIN)) == NULL)
1089: { fprintf(pgpout,PSTR("\n\007Can't create output file to update key ring.\n"));
1090: fclose(f);
1091: return(-1);
1092: }
1093:
1094: /* Copy pre-key and key to file g */
1095: rewind(f);
1096: copyfile (f, g, insertpos);
1097:
1098: /* write out certificate record to outfile ... */
1099: fwrite(certificate,1,certificate_length,g);
1100:
1101: /* Copy the remainder from file f to file g */
1102: copyfile (f, g, -1L);
1103:
1104: if (write_error(g))
1105: { fclose(g);
1106: return(-1);
1107: }
1108: fclose(g);
1109:
1110: savetempbak(scratchf,keyfile);
1111:
1112: fprintf(pgpout, PSTR("\nKey compromise certificate created.\n"));
1113: return(0); /* normal return */
1114: } /* compromise */
1115:
1116: /*======================================================================*/
1117:
1118:
1119: int signkey(char *keyguffin, char *sigguffin, char *keyfile)
1120: /* Write an RSA-signed message digest of key for user keyguffin in
1121: keyfile, using signature from user sigguffin. Append
1122: the signature right after the key.
1123: */
1124: {
1125: FILE *f;
1126: FILE *g;
1127: byte ctb; /* Cipher Type Byte */
1128: int certificate_length; /* signature certificate length */
1129: byte certificate[MAX_SIGCERT_LENGTH];
1130: byte keyID[KEYFRAGSIZE], keyID2[KEYFRAGSIZE];
1131: word32 tstamp; byte *timestamp = (byte *) &tstamp;
1132: byte userid[256];
1133: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1134: char pubring[MAX_PATH];
1135: long fp, fpusr;
1136: int pktlen, usrpktlen, usrctrllen;
1137: char *tempring;
1138: int status;
1139:
1140: /* Get signature key ID */
1141: strcpy((char *)userid,sigguffin); /* Who we are looking for */
1.1.1.3 ! root 1142: if (getsecretkey(0, NULL, NULL, timestamp, NULL, NULL,
1.1.1.2 root 1143: userid, n, e, NULL, NULL, NULL, NULL) < 0)
1144: {
1145: return(-1); /* problem with secret key file. error return. */
1146: }
1147: extract_keyID(keyID, n); /* Remember signer key ID */
1148: buildfilename(pubring,PUBLIC_KEYRING_FILENAME); /* use default pathname */
1.1.1.3 ! root 1149: if ((status = getpublickey(GPK_NORVK, pubring, &fp, &pktlen, keyID,
! 1150: timestamp, userid, n, e)) < 0)
1.1.1.2 root 1151: return(-1); /* problem with public key file. error return. */
1152:
1153: strcpy((char *)userid, keyguffin);
1154: fprintf(pgpout, PSTR("\nLooking for key for user '%s':\n"),
1155: LOCAL_CHARSET((char *)userid));
1156:
1.1.1.3 ! root 1157: if (getpublickey(GPK_SHOW|GPK_NORVK, keyfile, &fp, &pktlen, NULL,
! 1158: timestamp, userid, n, e) < 0)
1.1.1.2 root 1159: return(-1);
1160: PascalToC((char *) userid);
1161: if (getpubuserid (keyfile, fp, (byte *)keyguffin, &fpusr, &usrpktlen, FALSE) < 0)
1162: return(-1);
1163:
1164: /* open file f for read, in binary (not text) mode...*/
1165: if ((f = fopen(keyfile,FOPRBIN)) == NULL)
1166: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile);
1167: return(-1);
1168: }
1169:
1170: /* See if there is another signature with this keyID already */
1171: fseek (f, fpusr+usrpktlen, SEEK_SET);
1172: nextkeypacket(f, &ctb); /* Add key control packet to len */
1173: usrctrllen = 0;
1174: if (ctb != CTB_KEYCTRL)
1175: fseek(f,fpusr+usrpktlen,SEEK_SET);
1176: else
1177: usrctrllen = (int) (ftell(f) - (fpusr+usrpktlen));
1178: for ( ; ; )
1179: { status = readkeypacket(f,FALSE,&ctb,NULL,NULL,NULL,NULL,
1180: NULL,NULL,NULL,NULL,keyID2,NULL);
1181: if (status < 0 || is_key_ctb (ctb) || ctb==CTB_USERID)
1182: break;
1183: if (equal_buffers(keyID, keyID2, KEYFRAGSIZE))
1184: { fprintf(pgpout,PSTR("\n\007Key is already signed by user '%s'.\n"),
1185: LOCAL_CHARSET(sigguffin));
1186: fclose(f);
1187: return(-1);
1188: }
1189: }
1190: rewind(f);
1191:
1.1.1.3 ! root 1192: if (!batchmode)
! 1193: { fprintf(pgpout,
1.1.1.2 root 1194: PSTR("\n\nREAD CAREFULLY: Based on your own direct first-hand knowledge, are\n\
1195: you absolutely certain that you are prepared to solemnly certify that\n\
1196: the above public key actually belongs to the user specified by the\n\
1197: above user ID (y/N)? "));
1.1.1.3 ! root 1198: if (!getyesno('n'))
! 1199: { fclose(f);
! 1200: return(-1);
! 1201: }
1.1.1.2 root 1202: }
1203:
1204: { /* temporary scope for some buffers */
1205: MD5_CTX MD;
1206: unit d[MAX_UNIT_PRECISION];
1207: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
1208:
1209: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1210:
1211: if ((g = fopen(keyfile,FOPRBIN)) == NULL)
1212: { fprintf(pgpout,PSTR("\n\007Can't open key ring file '%s'\n"),keyfile);
1213: return(-1);
1214: }
1215: fseek(g, fp, SEEK_SET);
1216: /* Calculate signature */
1217: if (MDfile0_len(&MD, g, pktlen) < 0)
1218: { fclose(g);
1219: fclose(f);
1220: return(-1); /* problem with input file. error return */
1221: }
1222: fclose(g);
1223:
1224: /* Add data from user id */
1225: CToPascal((char *)userid);
1226: MD5Update(&MD, userid+1, (int)(unsigned char)userid[0]);
1227:
1228: strcpy((char *)userid,sigguffin); /* Who we are looking for */
1229:
1.1.1.3 ! root 1230: /* Make sure that we DONT use the internal password to
! 1231: * get the secret key! This way you need to type your
! 1232: * pass phrase every time you come to this point!
! 1233: * Derek Atkins <[email protected]> 93-02-25
! 1234: */
! 1235: if (*password)
! 1236: memset(password, 0, sizeof(password));
! 1237:
! 1238: if (getsecretkey(0, NULL, NULL, timestamp, NULL, NULL,
1.1.1.2 root 1239: userid, n, e, d, p, q, u) < 0)
1240: { fclose(f);
1241: return(-1); /* problem with secret key file. error return. */
1242: }
1243:
1244: certificate_length = make_signature_certificate(certificate, &MD,
1245: K0_SIGNATURE_BYTE, n, d, p, q, u);
1246: if (certificate_length < 0)
1247: return(-1); /* error return from make_signature_certificate() */
1248:
1249: } /* end of scope for some buffers */
1250:
1251: /* open file g for write, in binary (not text) mode...*/
1252: tempring = tempfile(TMP_TMPDIR);
1253: if ((g = fopen(tempring,FOPWBIN)) == NULL)
1254: { fprintf(pgpout,PSTR("\n\007Can't create output file to update key ring.\n"));
1255: fclose(f);
1256: return(-1);
1257: }
1258:
1259: /* Copy pre-key and key to file g */
1260: copyfile (f, g, fpusr+usrpktlen+usrctrllen);
1261:
1262: /* write out certificate record to outfile ... */
1263: fwrite(certificate,1,certificate_length,g);
1264:
1265: /* Add "trusty" control packet */
1.1.1.3 ! root 1266: write_trust (g, KC_SIGTRUST_ULTIMATE|KC_CONTIG|KC_SIG_CHECKED);
1.1.1.2 root 1267:
1268: /* Copy the remainder from file f to file g */
1269: copyfile (f, g, -1L);
1270:
1271: fclose(f);
1272: if (write_error(g))
1273: { fclose(g);
1274: return(-1);
1275: }
1276: fclose(g);
1277:
1278: savetempbak(tempring,keyfile);
1279:
1280: fprintf(pgpout, PSTR("\nKey signature certificate added.\n"));
1281: return(0); /* normal return */
1282:
1283: } /* signkey */
1284:
1285:
1286: /*======================================================================*/
1287:
1288: int check_signaturefile(char *infile, char *outfile, boolean strip_signature,
1289: char *preserved_name)
1290: { /* Check signature in infile for validity. Strip off the signature
1291: and write the remaining packet to outfile. If strip_signature,
1292: also write the signature to outfile.sig.
1293: the original filename is stored in preserved_name
1294: */
1.1.1.3 ! root 1295: byte ctb,ctb2=0; /* Cipher Type Bytes */
1.1.1.2 root 1296: char keyfile[MAX_PATH]; /* for getpublickey */
1297: char sigfile[MAX_PATH]; /* .sig file if strip_signature */
1298: char plainfile[MAX_PATH]; /* buffer for getstring() */
1299: #ifndef CANONICAL_TEXT
1300: char *tempFileName; /* Name for temporary uncanonicalized file */
1301: FILE *tempFile;
1302: #endif /* !CANONICAL_TEXT */
1.1.1.3 ! root 1303: long fp;
1.1.1.2 root 1304: FILE *f;
1305: FILE *g;
1306: long start_text; /* marks file position */
1307: int i,count;
1308: word16 cert_length;
1309: byte certbuf[MAX_SIGCERT_LENGTH];
1310: byteptr certificate; /* for parsing certificate buffer */
1311: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1312: byte inbuf[MAX_BYTE_PRECISION];
1313: byte outbuf[MAX_BYTE_PRECISION];
1314: byte keyID[KEYFRAGSIZE];
1315: word32 tstamp;
1316: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
1317: word32 dummystamp;
1318: byte userid[256];
1319: MD5_CTX MD;
1320: boolean separate_signature;
1321: boolean fixedLiteral = FALSE; /* Whether it's a fixed literal2 packet */
1.1.1.3 ! root 1322: extern char **myArgv;
1.1.1.2 root 1323: extern int myArgc;
1324: char lit_mode = MODE_BINARY;
1325: unsigned char litfile[MAX_PATH];
1326: word32 text_len = -1;
1327: int status;
1328: byte *mdextras;
1329: byte mdlensave;
1330: byte version;
1331: byte mdlen; /* length of material to be added to MD calculation */
1332: byte class;
1333: byte algorithm;
1334: byte mdlow2[2];
1335: char org_sys[5]; /* Name of originating system */
1336: #ifdef VMS
1337: char *fdl;
1338: short fdl_len;
1339: #endif
1.1.1.3 ! root 1340: int outbufoffset;
1.1.1.2 root 1341:
1342: fill0( keyID, KEYFRAGSIZE );
1343:
1344: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1345:
1346: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME); /* use default pathname */
1347:
1348: if (verbose)
1349: fprintf(pgpout,"check_signaturefile: infile = '%s', outfile = '%s'\n",
1350: infile,outfile);
1351:
1352: if (preserved_name)
1353: *preserved_name = '\0';
1354:
1355: /* open file f for read, in binary (not text) mode...*/
1356: if ((f = fopen(infile,FOPRBIN)) == NULL)
1357: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile);
1358: return(-1);
1359: }
1360:
1361: /******************** Read header CTB and length field ******************/
1362:
1363: fread(&ctb,1,1,f); /* read certificate CTB byte */
1364: certificate = certbuf;
1365: *certificate++ = ctb; /* copy ctb into certificate */
1366:
1367: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_SKE_TYPE))
1368: goto badcert; /* complain and return bad status */
1369:
1370: cert_length = getpastlength(ctb, f); /* read certificate length */
1371: certificate += ctb_llength(ctb); /* either 1, 2, 4, or 8 */
1372: if (cert_length > MAX_SIGCERT_LENGTH-3) /* Huge packet length */
1373: goto badcert; /* complain and return bad status */
1374:
1375: /* read whole certificate: */
1376: if (fread((byteptr) certificate, 1, cert_length, f) < cert_length)
1377: /* bad packet length field */
1378: goto badcert; /* complain and return bad status */
1379:
1380: version = *certificate++;
1381: if (version_error(version, VERSION_BYTE))
1382: goto err1;
1383:
1384: mdlensave = mdlen = *certificate++; /* length of material to be added to MD */
1385: mdextras = certificate; /* pointer to extra material for MD calculation */
1386:
1387: class = *certificate++;
1388: if (class != SM_SIGNATURE_BYTE && class != SB_SIGNATURE_BYTE)
1389: { (void) version_error(class, SM_SIGNATURE_BYTE);
1390: goto err1;
1391: }
1392: mdlen--;
1393:
1394: if (mdlen>0) /* if more MD material is included... */
1395: { for (i=0; i<SIZEOF_TIMESTAMP; ++i)
1396: { timestamp[i] = *certificate++;
1397: mdlen--;
1398: }
1399: }
1400:
1401: if (mdlen>0) /* if more MD material is included... */
1402: { certificate+=2; /* skip past unused validity period field */
1403: mdlen-=2;
1404: }
1405:
1406: for (i=0; i<KEYFRAGSIZE; i++)
1407: keyID[i] = *certificate++; /* copy rest of key fragment */
1408:
1409: algorithm = *certificate++;
1410: if (version_error(algorithm, RSA_ALGORITHM_BYTE))
1411: goto err1;
1412:
1413: algorithm = *certificate++;
1414: if (version_error(algorithm, MD5_ALGORITHM_BYTE))
1415: goto err1;
1416:
1417: mdlow2[0] = *certificate++;
1418: mdlow2[1] = *certificate++;
1419:
1420: /* getpublickey() sets precision for mpi2reg, if key not found: use
1421: maximum precision to avoid error return from mpi2reg() */
1.1.1.3 ! root 1422: if (getpublickey(0, keyfile, &fp, NULL, keyID,
! 1423: (byte *)&dummystamp, userid, n, e) < 0)
1.1.1.2 root 1424: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1425:
1426: if (mpi2reg((unitptr)inbuf,certificate) == -1) /* get signed message digest */
1427: goto err1;
1428: certificate += countbytes((unitptr)inbuf)+2;
1429:
1430: if ((certificate-certbuf) != cert_length+3)
1431: /* Bad length in signature certificate. Off by
1432: ((certificate-certbuf) - (cert_length+3)) */
1433: goto badcert; /* complain and return bad status */
1434:
1435: start_text = ftell(f); /* mark position of text for later */
1436:
1437: if (fread(outbuf,1,1,f) < 1) /* see if any plaintext is there */
1438: { /* Signature certificate has no plaintext following it.
1439: Must be in another file. Go look. */
1440: separate_signature = TRUE;
1441: if (preserved_name) /* let caller know there is no output file */
1442: strcpy(preserved_name, "/dev/null");
1443: fclose(f);
1444: fprintf(pgpout,PSTR("\nFile '%s' has signature, but with no text."),infile);
1445: if (myArgc > 3 && file_exists(myArgv[3]))
1446: { outfile = myArgv[3];
1447: fprintf(pgpout,PSTR("\nText is assumed to be in file '%s'.\n"),outfile);
1448: }
1449: else
1450: { strcpy(plainfile, outfile);
1451: outfile = plainfile;
1452: drop_extension(outfile);
1453:
1454: if (file_exists(outfile))
1455: fprintf(pgpout,PSTR("\nText is assumed to be in file '%s'.\n"),outfile);
1456: else
1.1.1.3 ! root 1457: {
! 1458: if (batchmode)
! 1459: return -1;
! 1460: fprintf(pgpout,PSTR("\nPlease enter filename of text that signature applies to: "));
1.1.1.2 root 1461: getstring(outfile,59,TRUE); /* echo keyboard */
1462: if ((int)strlen(outfile) == 0)
1463: return(-1);
1464: }
1465: }
1466: /* open file f for read, in binary (not text) mode...*/
1467: if ((f = fopen(outfile,FOPRBIN)) == NULL)
1468: { fprintf(pgpout,PSTR("\n\007Can't open file '%s'\n"),outfile);
1469: return(-1);
1470: }
1471: start_text = ftell(f); /* mark position of text for later */
1472: text_len = fsize(f); /* remember length of text */
1473: } /* had to open new input file */
1474: else
1475: { separate_signature = FALSE;
1476: /* We just read 1 byte, so outbuf[0] should contain a ctb,
1477: maybe a CTB_LITERAL byte. */
1478: ctb2 = outbuf[0];
1479: fixedLiteral = is_ctb_type(ctb2,CTB_LITERAL2_TYPE);
1480: if (is_ctb(ctb2) && (is_ctb_type(ctb2,CTB_LITERAL_TYPE)||fixedLiteral))
1481: { /* Read literal data */
1482: text_len = getpastlength(ctb2, f); /* read packet length */
1483: lit_mode = '\0';
1484: fread (&lit_mode,1,1,f); /* get literal packet mode byte */
1485: if (lit_mode != MODE_TEXT && lit_mode != MODE_BINARY &&
1486: lit_mode != MODE_LOCAL)
1487: { fprintf(pgpout,"\n\007Error: Illegal mode byte %02x in literal packet.\n",
1488: lit_mode); /* English-only diagnostic for debugging */
1489: (void) version_error(lit_mode, MODE_BINARY);
1490: goto err1;
1491: }
1492: if (verbose)
1493: fprintf(pgpout, PSTR("File type: '%c'\n"), lit_mode);
1494: /* Read literal file name, use it if possible */
1495: litfile[0] = 0;
1496: fread (litfile,1,1,f);
1497: if( fixedLiteral )
1498: /* Get corrected text_len value by subtracting the length of
1499: the filename and the timestamp and mode byte and litfile length byte */
1500: text_len -= litfile[0] + sizeof(dummystamp) + 2;
1501: if (litfile[0] > 0)
1.1.1.3 ! root 1502: { if ((int)litfile[0] >= MAX_PATH)
! 1503: { fseek(f, litfile[0], SEEK_CUR);
! 1504: litfile[0] = 0;
! 1505: }
! 1506: else
! 1507: fread (litfile+1,1,litfile[0],f);
! 1508: }
1.1.1.2 root 1509: /* Use litfile if it's writeable and he didn't say an outfile */
1.1.1.3 ! root 1510: if (litfile[0])
1.1.1.2 root 1511: { PascalToC( (char *)litfile );
1512: if (verbose)
1513: fprintf(pgpout, PSTR("Original plaintext file name was: '%s'\n"), litfile);
1514: if (preserved_name)
1515: strcpy(preserved_name, (char *) litfile);
1516: }
1517: if (lit_mode == MODE_LOCAL) {
1518: fread(org_sys, 1, 4, f); org_sys[4] = '\0';
1519: #ifdef VMS
1520: #define LOCAL_TEST !strncmp("VMS ",org_sys,4)
1521: #else
1522: #define LOCAL_TEST FALSE
1523: #endif
1524: if (LOCAL_TEST) {
1525: #ifdef VMS
1526: fread(&fdl_len, 2, 1, f);
1527: fdl = (char *) malloc(fdl_len);
1528: fread(fdl, 1, fdl_len, f);
1529: if ((g = fdl_create( fdl, fdl_len, outfile, (char *) litfile)) == NULL) {
1530: fprintf(pgpout,"\n\007Unable to create file %s\n", outfile);
1531: return(-1);
1532: }
1533: free(fdl);
1534: if (preserved_name)
1535: strcpy(preserved_name, (char *) litfile);
1536: text_len -= (fdl_len + sizeof(fdl_len));
1537: #endif /* VMS */
1538: } else {
1539: fprintf(pgpout,"\n\007Unrecognised local binary type %s\n",org_sys);
1540: return(-1);
1541: }
1542: } else {
1543: /* Discard file creation timestamp for now */
1544: fread (&dummystamp, 1, sizeof(dummystamp), f);
1545: }
1546: start_text = ftell(f); /* mark position of text for later */
1547: } /* packet is CTB_LITERAL_TYPE */
1548: }
1549:
1550: /* Use keyID prefix to look up key... */
1551:
1552: /* Get and validate public key from a key file: */
1.1.1.3 ! root 1553: if (getpublickey(0, keyfile, &fp, NULL, keyID,
! 1554: (byte *)&dummystamp, userid, n, e) < 0)
1.1.1.2 root 1555: { /* Can't get public key. Complain and process file copy anyway. */
1556: fprintf(pgpout,PSTR("\n\007WARNING: Can't find the right public key-- can't check signature integrity.\n"));
1557: goto outsig;
1558: } /* Can't find public key */
1559:
1560: /* Recover message digest via public key */
1561: mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n);
1562:
1.1.1.3 ! root 1563: if (!quietmode)
1.1.1.2 root 1564: fputc('.',pgpout); /* Signal RSA completion. */
1565:
1566: /* Unblock message digest, and convert to external byte order: */
1567: count = postunblock(outbuf, (unitptr)outbuf, n);
1.1.1.3 ! root 1568:
! 1569: if (count == -1)
1.1.1.2 root 1570: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\
1571: This may be caused either by corrupted data or by using the wrong RSA key.\n"));
1572: goto outsig; /* Output data anyway */
1573: }
1574:
1575: /* outbuf should contain message digest packet */
1576: /*==================================================================*/
1577: /* Look at nested stuff within RSA block... */
1578:
1.1.1.3 ! root 1579: if (count == -2 ||
! 1580: (count != sizeof(MD.digest) && count != sizeof(MD.digest)+1) ||
! 1581: (count == sizeof(MD.digest)+1 && outbuf[0] != MD5_ALGORITHM_BYTE))
1.1.1.2 root 1582: { fprintf(pgpout,PSTR("\007\nUnrecognized message digest algorithm.\n"));
1583: fprintf(pgpout,PSTR("This may require a newer version of PGP.\n"));
1584: fprintf(pgpout,PSTR("Can't check signature integrity.\n"));
1585: goto outsig; /* Output data anyway */
1586: }
1587:
1.1.1.3 ! root 1588: /* Distinguish PKCS-compatible from pre-3.3 which has an extra byte */
! 1589: outbufoffset = (count==sizeof(MD.digest)) ? 0 : 1;
! 1590:
! 1591: if (outbuf[outbufoffset] != mdlow2[0] ||
! 1592: outbuf[outbufoffset+1] != mdlow2[1])
1.1.1.2 root 1593: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\
1594: This may be caused either by corrupted data or by using the wrong RSA key.\n"));
1595: goto outsig; /* Output data anyway */
1596: }
1597:
1598: /* Reposition file to where that plaintext begins... */
1599: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
1600:
1601: MDfile0_len(&MD,f,text_len);/* compute a message digest from rest of file */
1602:
1603: MD_addbuffer (&MD, mdextras, mdlensave, TRUE); /* Finish message digest */
1604:
1605: convert_byteorder(timestamp,4); /* convert timestamp from external form */
1606: PascalToC((char *)userid); /* for display */
1607:
1608: /* now compare computed MD with claimed MD */
1.1.1.3 ! root 1609: /* Assume MSB external byte ordering */
! 1610: if (!equal_buffers((byte *)(MD.digest), outbuf+outbufoffset, 16))
1.1.1.2 root 1611: {
1612: #ifndef CANONICAL_TEXT
1613: /* IF the signature is bad, AND this machine does not use MSDOS-style
1614: canonical text as its native text format, AND this is a detached
1615: signature certificate, AND this file appears to contain non-
1616: canonical ASCII text, THEN we convert the file to canonical text
1617: form and check the signature again. This is because a detached
1618: signature certificate probably means the file is not currently in
1619: a canonical text packet, but it was in canonical text form when
1620: the signature was created, so by re-canonicalizing it we can
1621: check the signature. */
1622: if (class == SM_SIGNATURE_BYTE && separate_signature && is_text_file(outfile))
1623: { /* Reposition file to where the plaintext begins and canonicalize it */
1624: rewind( f );
1625: tempFileName = tempfile( TMP_WIPE | TMP_TMPDIR );
1626: if (verbose)
1627: fprintf(stderr, "signature checking failed, trying in canonical mode\n");
1.1.1.3 ! root 1628: if( ( tempFile = fopen( tempFileName, FOPWPBIN ) ) != NULL )
1.1.1.2 root 1629: { /* We've opened a temporary work file, copy the text to it
1630: with canonicalization */
1631: copyfile_to_canon( f, tempFile, -1L );
1632:
1633: /* Move back to the start of the file and recalculate the MD */
1634: rewind( tempFile );
1635: MDfile0_len( &MD, tempFile, -1L );
1636: MD_addbuffer( &MD, mdextras, mdlensave, TRUE );
1637:
1638: /* Clean up behind us */
1639: fclose( tempFile );
1640: rmtemp( tempFileName );
1641:
1642: /* Check if the signature is OK this time round */
1.1.1.3 ! root 1643: /* Assume MSB external byte ordering */
! 1644: if(equal_buffers((byte *)(MD.digest),outbuf+outbufoffset,16))
1.1.1.2 root 1645: goto goodsig;
1646: }
1647: }
1648: #endif /* !CANONICAL_TEXT */
1649:
1650: fprintf(pgpout,PSTR("\007\nWARNING: Bad signature, doesn't match file contents!\007\n"));
1651: fprintf(pgpout,PSTR("\nBad signature from user \"%s\".\n"),
1652: LOCAL_CHARSET((char *)userid));
1653: fprintf(pgpout,PSTR("Signature made %s\n"),ctdate((word32 *)timestamp));
1.1.1.3 ! root 1654: if (moreflag && !batchmode)
1.1.1.2 root 1655: { /* more will scroll the message off the screen */
1656: fprintf(pgpout, PSTR("\nPress ENTER to continue..."));
1657: fflush(pgpout);
1658: getyesno('n');
1659: }
1.1.1.3 ! root 1660: goto warnsig; /* Output data anyway */
1.1.1.2 root 1661: }
1662:
1663: goodsig:
1.1.1.3 ! root 1664: signature_checked = TRUE; /* set flag for batch processing */
1.1.1.2 root 1665: fprintf(pgpout,PSTR("\nGood signature from user \"%s\".\n"),
1666: LOCAL_CHARSET((char *)userid));
1667: fprintf(pgpout,PSTR("Signature made %s\n"),ctdate((word32 *)timestamp));
1668:
1.1.1.3 ! root 1669: warnsig:
! 1670: /* warn only, don't ask if user wants to use the key */
! 1671: warn_signatures(keyfile, fp, (char *)userid, TRUE);
! 1672:
1.1.1.2 root 1673: outsig:
1674: /* Reposition file to where that plaintext begins... */
1675: fseek(f,start_text,SEEK_SET); /* reposition file from last ftell */
1676:
1677: if (separate_signature)
1.1.1.3 ! root 1678: {
! 1679: if (!quietmode)
! 1680: fprintf(pgpout,PSTR("\nSignature and text are separate. No output file produced. "));
! 1681: }
1.1.1.2 root 1682: else /* signature precedes plaintext in file... */
1683: { /* produce a plaintext output file from signature file */
1684: /* open file g for write, in binary or text mode...*/
1685: if (lit_mode==MODE_LOCAL) {
1686: #ifdef VMS
1687: if (status = fdl_copyfile2bin( f, g, text_len)) { /* Copy ok? */
1688: if (status > 0)
1689: fprintf(stderr,"\n...copying to literal file\n");
1690: else
1691: perror("\nError copying from work file");
1692: fdl_close(g);
1693: goto err1;
1694: }
1695: fdl_close(g);
1696: #endif /*VMS */
1.1.1.3 ! root 1697: }
! 1698: else
! 1699: {
1.1.1.2 root 1700: if (lit_mode == MODE_BINARY)
1701: g = fopen(outfile, FOPWBIN);
1702: else
1703: g = fopen(outfile, FOPWTXT);
1704: if (g == NULL)
1705: { fprintf(pgpout,PSTR("\n\007Can't create plaintext file '%s'\n"),outfile);
1706: goto err1;
1707: }
1708: CONVERSION = (lit_mode == MODE_TEXT) ? EXT_CONV : NO_CONV;
1709: if (lit_mode == MODE_BINARY)
1710: status = copyfile(f, g, text_len);
1711: else
1712: status = copyfile_from_canon(f, g, text_len);
1713: CONVERSION = NO_CONV;
1714: if (write_error(g) || status < 0)
1715: { fclose(g);
1716: goto err1;
1717: }
1718: fclose(g);
1719: }
1720:
1721: if (strip_signature)
1722: { /* Copy signature to a .sig file */
1723: strcpy (sigfile, outfile);
1724: force_extension(sigfile,SIG_EXTENSION);
1.1.1.3 ! root 1725: if (!force_flag && file_exists(sigfile))
1.1.1.2 root 1726: { fprintf(pgpout,PSTR("\n\007Signature file '%s' already exists. Overwrite (y/N)? "),
1727: sigfile);
1728: if (!getyesno('n'))
1729: goto err1;
1730: }
1731: if ((g = fopen(sigfile,FOPWBIN)) == NULL)
1732: { fprintf(pgpout,PSTR("\n\007Can't create signature file '%s'\n"),sigfile);
1733: goto err1;
1734: }
1735: fseek (f,0L,SEEK_SET);
1736: copyfile (f,g,(unsigned long)(cert_length+ctb_llength(ctb)+1));
1737: if (write_error(g))
1738: { fclose(g);
1739: goto err1;
1740: }
1741: fclose(g);
1.1.1.3 ! root 1742: if (!quietmode)
! 1743: fprintf(pgpout,PSTR("\nWriting signature certificate to '%s'\n"),sigfile);
1.1.1.2 root 1744: }
1745: }
1746:
1747: burn(inbuf); /* burn sensitive data on stack */
1748: burn(outbuf); /* burn sensitive data on stack */
1749: fclose(f);
1750: if (separate_signature)
1751: return(0); /* normal return, no nested info */
1752: if (is_ctb(ctb2) && (is_ctb_type(ctb2,CTB_LITERAL_TYPE) || fixedLiteral))
1753: /* we already stripped away the CTB_LITERAL */
1754: return(0); /* normal return, no nested info */
1755: /* Otherwise, it's best to assume a nested CTB */
1756: return(1); /* nested information return */
1757:
1758: badcert: /* Bad packet. Complain. */
1759: fprintf(pgpout,PSTR("\n\007Error: Badly-formed or corrupted signature certificate.\n"));
1760: fprintf(pgpout,PSTR("File \"%s\" does not have a properly-formed signature.\n"),infile);
1761: /* Now just drop through to error exit... */
1762:
1763: err1:
1764: burn(inbuf); /* burn sensitive data on stack */
1765: burn(outbuf); /* burn sensitive data on stack */
1766: fclose(f);
1767: return(-1); /* error return */
1768:
1769: } /* check_signaturefile */
1770:
1771:
1772: int check_key_sig(FILE *fkey, long fpkey, int keypktlen, char *keyuserid,
1773: FILE *fsig, long fpsig, char *keyfile, char *siguserid, byte *xtimestamp,
1774: byte *sigclass)
1775: { /* Check signature of key in file fkey at position fpkey, using signature
1776: in file fsig and position fpsig. keyfile tells the file to use to
1777: look for the public key in to check the sig. Return 0 if OK, -1 if
1778: we can't check the signature, -2 if bad or other problem.
1779: */
1780: byte ctb; /* Cipher Type Bytes */
1.1.1.3 ! root 1781: long fp;
1.1.1.2 root 1782: word16 cert_length;
1783: int i, count;
1784: byte certbuf[MAX_SIGCERT_LENGTH];
1785: byteptr certificate; /* for parsing certificate buffer */
1786: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
1787: byte inbuf[MAX_BYTE_PRECISION];
1788: byte outbuf[MAX_BYTE_PRECISION];
1789: byte keyID[KEYFRAGSIZE];
1790: MD5_CTX MD;
1791: byte mdlensave;
1792: byte *mdextras;
1793: word32 tstamp;
1794: byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
1795: byte version;
1796: byte mdlen; /* length of material to be added to MD calculation */
1797: byte class;
1798: byte algorithm;
1799: byte mdlow2[2];
1.1.1.3 ! root 1800: int outbufoffset;
1.1.1.2 root 1801:
1802: fill0( keyID, KEYFRAGSIZE );
1803:
1804: set_precision(MAX_UNIT_PRECISION); /* safest opening assumption */
1805:
1806: /******************** Read header CTB and length field ******************/
1807:
1808: fseek(fsig, fpsig, SEEK_SET);
1809: fread(&ctb,1,1,fsig); /* read certificate CTB byte */
1810: certificate = certbuf;
1811: *certificate++ = ctb; /* copy ctb into certificate */
1812:
1813: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_SKE_TYPE))
1814: goto badcert2; /* complain and return bad status */
1815:
1816: cert_length = getpastlength(ctb, fsig); /* read certificate length */
1817: certificate += ctb_llength(ctb); /* either 1, 2, 4, or 8 */
1818: if (cert_length > MAX_SIGCERT_LENGTH-3) /* Huge packet length */
1819: goto badcert2; /* complain and return bad status */
1820:
1821: /* read whole certificate: */
1822: if (fread((byteptr) certificate, 1, cert_length, fsig) < cert_length)
1823: /* bad packet length field */
1824: goto badcert2; /* complain and return bad status */
1825:
1826: version = *certificate++;
1827: if (version_error(version, VERSION_BYTE))
1828: goto err2;
1829:
1830: mdlensave = mdlen = *certificate++; /* length of material to be added to MD */
1831: mdextras = certificate; /* pointer to extra material for MD calculation */
1832:
1833: *sigclass = class = *certificate++;
1834: if (class != K0_SIGNATURE_BYTE && class != K1_SIGNATURE_BYTE &&
1835: class != K2_SIGNATURE_BYTE && class != K3_SIGNATURE_BYTE &&
1836: class != KC_SIGNATURE_BYTE)
1837: { (void) version_error(class, K0_SIGNATURE_BYTE);
1838: goto err2;
1839: }
1840: mdlen--;
1841:
1842: if (mdlen>0) /* if more MD material is included... */
1843: { for (i=0; i<SIZEOF_TIMESTAMP; ++i)
1844: { timestamp[i] = *certificate++;
1845: mdlen--;
1846: }
1847: }
1848:
1849: if (mdlen>0) /* if more MD material is included... */
1850: { certificate+=2; /* skip past unused validity period word */
1851: mdlen-=2;
1852: }
1853:
1854: if (mdlen>0) /* if more MD material is included... */
1855: certificate+=mdlen; /* skip over the rest */
1856:
1857: for (i=0; i<KEYFRAGSIZE; i++)
1858: keyID[i] = *certificate++; /* copy rest of key fragment */
1859:
1860: algorithm = *certificate++;
1861: if (version_error(algorithm, RSA_ALGORITHM_BYTE))
1862: goto err2;
1863:
1864: algorithm = *certificate++;
1865: if (version_error(algorithm, MD5_ALGORITHM_BYTE))
1866: goto err2;
1867:
1868: /* Grab 1st 2 bytes of message digest */
1869: mdlow2[0] = *certificate++;
1870: mdlow2[1] = *certificate++;
1871:
1872: /* We used to set precision here based on certificate value,
1873: * but it was sometimes less than that based on n. Read public
1874: * key here to set precision, before we go on.
1875: */
1876: /* This sets precision, too, based on n. */
1.1.1.3 ! root 1877: if (getpublickey(GPK_GIVEUP, keyfile, &fp, NULL, keyID,
! 1878: xtimestamp, (unsigned char *)siguserid, n, e) < 0)
1.1.1.2 root 1879: goto err1;
1880:
1881: if (mpi2reg((unitptr)inbuf,certificate) == -1) /* get signed message digest */
1882: goto err1;
1883: certificate += countbytes((unitptr)inbuf)+2;
1884:
1885: if ((certificate-certbuf) != cert_length+3)
1886: /* Bad length in signature certificate. Off by
1887: ((certificate-certbuf) - (cert_length+3)) */
1888: goto badcert2; /* complain and return bad status */
1889:
1890: /* Recover message digest via public key */
1891: mp_modexp((unitptr)outbuf,(unitptr)inbuf,e,n);
1892:
1893: /* Unblock message digest, and convert to external byte order: */
1.1.1.3 ! root 1894: count = postunblock(outbuf, (unitptr)outbuf, n);
! 1895:
! 1896: if (count == -2)
! 1897: goto err1; /* Unrecognized digest algorithm */
! 1898:
! 1899: if (count != sizeof(MD.digest) && count != sizeof(MD.digest)+1)
1.1.1.2 root 1900: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */
1901:
1.1.1.3 ! root 1902: /* Distinguish PKCS-compatible from pre-3.3 which has an extra byte */
! 1903: outbufoffset = (count==sizeof(MD.digest)) ? 0 : 1;
! 1904:
1.1.1.2 root 1905: /* outbuf should contain message digest packet */
1906: /*==================================================================*/
1907: /* Look at nested stuff within RSA block... */
1908:
1.1.1.3 ! root 1909: /* Assume MSB external byte ordering */
! 1910: if (outbufoffset && outbuf[0] != MD5_ALGORITHM_BYTE)
1.1.1.2 root 1911: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */
1.1.1.3 ! root 1912: if (outbuf[outbufoffset] != mdlow2[0] ||
! 1913: outbuf[outbufoffset+1] != mdlow2[1])
1.1.1.2 root 1914: goto err2; /* Bad RSA decrypt. Corruption, or wrong key. */
1915:
1916: /* Position file to where that plaintext begins... */
1917: fseek(fkey,fpkey,SEEK_SET);
1918:
1919: /* compute a message digest from key packet */
1920: MDfile0_len(&MD,fkey,keypktlen);
1921: /* Add data from user id */
1922: if (class != KC_SIGNATURE_BYTE)
1923: MD5Update(&MD, (unsigned char *) keyuserid+1, (int)(unsigned char)keyuserid[0]);
1924: /* Add time and class data */
1925: MD_addbuffer (&MD, mdextras, mdlensave, TRUE); /* Finish message digest */
1926:
1927: /* now compare computed MD with claimed MD */
1.1.1.3 ! root 1928: /* Assume MSB external byte ordering */
! 1929: if (!equal_buffers((byte *)(MD.digest), outbuf+outbufoffset, 16))
! 1930: goto err2;
1.1.1.2 root 1931:
1932: convert_byteorder(timestamp,4); /* convert timestamp from external form */
1933: memcpy (xtimestamp, timestamp, 4); /* Return signature timestamp */
1934:
1935: burn(inbuf); /* burn sensitive data on stack */
1936: burn(outbuf); /* burn sensitive data on stack */
1937: return(0); /* normal return */
1938:
1939: err1:
1940: burn(inbuf); /* burn sensitive data on stack */
1941: burn(outbuf); /* burn sensitive data on stack */
1942: return(-1); /* error return */
1943:
1944: badcert2: /* Bad packet. Complain. */
1945: fprintf(pgpout,PSTR("\n\007Error: Badly-formed or corrupted signature certificate.\n"));
1946: /* Now just drop through to error exit... */
1947:
1948: err2:
1949: burn(inbuf); /* burn sensitive data on stack */
1950: burn(outbuf); /* burn sensitive data on stack */
1951: return(-2); /* error return */
1952:
1953: } /* check_key_sig */
1954:
1955:
1956:
1957: /*======================================================================*/
1.1.1.3 ! root 1958: static int squish_and_idea_file(byte *ideakey, FILE *f, FILE *g,
1.1.1.2 root 1959: boolean attempt_compression)
1960: {
1961: FILE *t;
1.1.1.3 ! root 1962: char *tempf = NULL;
1.1.1.2 root 1963: byte ctb;
1964: word32 fpos, fpos0;
1965: extern char plainfile[];
1966:
1967: /*
1968: ** If the caller specified that we should attempt compression, we
1969: ** create a temporary file 't' and compress our input file 'f' into
1970: ** 't'. Ideally, we would see if we get a good compression ratio
1971: ** and if we did, then use file 't' for input and write a
1972: ** CTB_COMPRESSED prefix. But in this implementation we just always
1973: ** use the compressed output, even if it didn't compress well.
1974: */
1975:
1976: rewind( f );
1977:
1978: if (!attempt_compression)
1979: t = f; /* skip compression attempt */
1980: else /* attempt compression-- get a tempfile */
1981: if ((tempf = tempfile(TMP_TMPDIR|TMP_WIPE)) == NULL ||
1.1.1.3 ! root 1982: (t = fopen(tempf, FOPWPBIN)) == NULL) /* error: no tempfile */
1.1.1.2 root 1983: t = f; /* skip compression attempt */
1984: else /* attempt compression */
1985: {
1986: extern int zipup( FILE *, FILE * );
1987:
1988:
1.1.1.3 ! root 1989: if (verbose) fprintf(pgpout,"\nCompressing [%s] ", plainfile);
1.1.1.2 root 1990:
1991: /* We don't put a length field on CTB_COMPRESSED yet */
1992: ctb = CTB_COMPRESSED; /* use compression prefix CTB */
1993: fwrite( &ctb, 1, 1, t ); /* write CTB_COMPRESSED */
1994: /* No CTB packet length specified means indefinite length. */
1995: ctb = ZIP2_ALGORITHM_BYTE; /* use ZIP compression */
1996: fwrite( &ctb, 1, 1, t ); /* write ZIP algorithm byte */
1997:
1998: /* Compression the file */
1999: zipup( f, t);
2000: if (write_error(t))
2001: { fclose(t);
1.1.1.3 ! root 2002: if (tempf)
! 2003: rmtemp(tempf);
1.1.1.2 root 2004: return(-1);
2005: }
2006: if (verbose) fprintf(pgpout, PSTR("compressed. ") );
1.1.1.3 ! root 2007: else if (!quietmode)
1.1.1.2 root 2008: fputc('.',pgpout); /* show progress */
2009: rewind( t );
2010: }
2011:
2012: /* Now write out file thru IDEA cipher... */
2013:
2014: /* Write CTB prefix, leave 4 bytes for later length */
2015: fpos0 = ftell(g);
2016: write_ctb_len (g, CTB_CKE_TYPE, 0L, TRUE);
2017: fpos = ftell(g) - fpos0;
2018:
2019: idea_file( ideakey, ENCRYPT_IT, t, g, fsize(t) );
2020:
2021: /* Now re-write CTB prefix, this time with length */
2022: fseek(g,fpos0,SEEK_SET);
2023: write_ctb_len (g, CTB_CKE_TYPE, fsize(g)-fpos, TRUE);
2024:
2025: if (t != f)
2026: { fclose( t ); /* close and remove the temporary file */
1.1.1.3 ! root 2027: if (tempf)
! 2028: rmtemp(tempf);
1.1.1.2 root 2029: }
2030:
2031: return(0); /* normal return */
2032:
2033: } /* squish_and_idea_file */
2034:
2035:
2036: int squish_file(char *infile, char *outfile)
2037: {
2038: FILE *f, *g;
2039: byte ctb;
2040: extern int zip( FILE *, FILE * );
2041:
2042: if (verbose)
2043: fprintf(pgpout,"squish_file: infile = '%s', outfile = '%s'\n",
2044: infile,outfile);
2045:
2046: /* open file f for read, in binary (not text) mode...*/
2047: if ((f = fopen( infile, FOPRBIN )) == NULL)
2048: {
2049: fprintf(pgpout,PSTR("\n\007Can't open file '%s'\n"), infile );
2050: return(-1);
2051: }
2052:
2053: /* open file g for write, in binary (not text) mode...*/
2054: if ((g = fopen( outfile, FOPWBIN )) == NULL)
2055: {
2056: fprintf(pgpout,PSTR("\n\007Can't create compressed file '%s'\n"), outfile );
2057: fclose(f);
2058: return(-1);
2059: }
2060:
2061:
2062: if (verbose) fprintf(pgpout, PSTR("Compressing file..."));
2063:
2064: /* We don't put a length field on CTB_COMPRESSED yet */
2065: ctb = CTB_COMPRESSED; /* use compression prefix CTB */
2066: fwrite( &ctb, 1, 1, g ); /* write CTB_COMPRESSED */
2067: /* No CTB packet length specified means indefinite length. */
2068: ctb = ZIP2_ALGORITHM_BYTE; /* use ZIP compression */
2069: fwrite( &ctb, 1, 1, g ); /* write ZIP algorithm byte */
2070:
2071: /* Compress/store the file */
2072: zipup( f, g );
2073: if (verbose) fprintf(pgpout, PSTR("compressed. ") );
2074:
2075: fclose (f);
2076: if (write_error(g))
2077: { fclose(g);
2078: return -1;
2079: }
2080: fclose (g);
2081: return(0);
2082: } /* squish_file */
2083:
2084: #define NOECHO1 1 /* Disable password from being displayed on screen */
2085: #define NOECHO2 2 /* Disable password from being displayed on screen */
2086:
2087: int idea_encryptfile(char *infile, char *outfile,
2088: boolean attempt_compression)
2089: {
2090: FILE *f; /* input file */
2091: FILE *g; /* output file */
2092: byte ideakey[16];
2093: byte passphrase[256];
2094:
2095: if (verbose)
2096: fprintf(pgpout,"idea_encryptfile: infile = '%s', outfile = '%s'\n",
2097: infile,outfile);
2098:
2099: /* open file f for read, in binary (not text) mode...*/
2100: if ((f = fopen( infile, FOPRBIN )) == NULL)
2101: {
2102: fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"), infile );
2103: return(-1);
2104: }
2105:
2106: /* open file g for write, in binary (not text) mode...*/
2107: if ((g = fopen( outfile, FOPWBIN )) == NULL)
2108: {
2109: fprintf(pgpout,PSTR("\n\007Can't create ciphertext file '%s'\n"), outfile );
2110: fclose(f);
2111: return(-1);
2112: }
2113:
2114: /* Get IDEA password, hashed to a key */
2115: if (*password != '\0')
2116: hashpass(password, strlen(password), ideakey);
2117: else {
1.1.1.3 ! root 2118: if (!quietmode)
! 2119: fprintf(pgpout,PSTR("\nYou need a pass phrase to encrypt the file. "));
! 2120: if (batchmode || GetHashedPassPhrase((char *)passphrase,(char *)ideakey,NOECHO2) <= 0)
1.1.1.2 root 2121: { fclose(f);
2122: fclose(g);
2123: return(-1);
2124: }
2125: }
2126:
1.1.1.3 ! root 2127: if (!quietmode)
1.1.1.2 root 2128: { fprintf(pgpout,PSTR("Just a moment...")); /* this may take a while */
2129: fflush(pgpout);
2130: }
2131:
2132: /* Now compress the plaintext and encrypt it with IDEA... */
2133: squish_and_idea_file( ideakey, f, g, attempt_compression );
2134:
2135: burn(ideakey); /* burn sensitive data on stack */
2136: burn(passphrase);
2137:
2138: fclose(f);
2139: if (write_error(g))
2140: { fclose(g);
2141: return -1;
2142: }
2143: fclose(g);
2144:
2145: return(0);
2146:
2147: } /* idea_encryptfile */
2148:
2149:
2150: /*======================================================================*/
2151:
1.1.1.3 ! root 2152: static byte (*keyID_list)[KEYFRAGSIZE] = NULL;
1.1.1.2 root 2153:
1.1.1.3 ! root 2154: int encryptfile(char **mcguffins, char *infile, char *outfile,
1.1.1.2 root 2155: boolean attempt_compression)
2156: {
1.1.1.3 ! root 2157: int i,ckp_length;
1.1.1.2 root 2158: FILE *f;
2159: FILE *g;
1.1.1.3 ! root 2160: byte keybuf[MAX_BYTE_PRECISION]; /* This keeps our IDEA to encrypt */
! 2161: byte ideakey[24]; /* must be big enough for make_random_ideakey */
1.1.1.2 root 2162: word32 chksum;
1.1.1.3 ! root 2163: char keyfile[MAX_PATH];
! 2164: int keys_used = 0;
1.1.1.2 root 2165:
1.1.1.3 ! root 2166: if (mcguffins == NULL || *mcguffins == NULL || **mcguffins == '\0') {
! 2167: /* Well, we haven't gotten a user, lets die here */
! 2168: return -1;
! 2169: }
1.1.1.2 root 2170:
2171: if (verbose)
2172: fprintf(pgpout,"encryptfile: infile = %s, outfile = %s\n",
2173: infile,outfile);
2174:
2175: /* open file f for read, in binary (not text) mode...*/
2176: if ((f = fopen( infile, FOPRBIN )) == NULL)
2177: {
2178: fprintf(pgpout,PSTR("\n\007Can't open plaintext file '%s'\n"), infile );
2179: return(-1);
2180: }
2181:
2182: /* open file g for write, in binary (not text) mode...*/
2183: if ((g = fopen( outfile, FOPWBIN )) == NULL)
2184: {
2185: fprintf(pgpout,PSTR("\n\007Can't create ciphertext file '%s'\n"), outfile );
2186: fclose(f);
2187: return(-1);
2188: }
2189:
1.1.1.3 ! root 2190: /* Now we have to generate a random session key and IV.
! 2191: As part of this computation, we use the MD5 hash of the
! 2192: current file, if it has previously been obtained due to a
! 2193: signing operation. If it has not been obtained, we hash
! 2194: the first 2K (for efficiency reasons) for input into
! 2195: the key generatrion process. This is to ensure that
! 2196: capturing a randseed.bin file will not allow reconstruction
! 2197: of subsequent session keys without knowing the message
! 2198: that was encrypted. (A session key only protects a
! 2199: single message, so it is reasonable to assume that an
! 2200: opponent trying to obtain a session key is trying to
! 2201: obtain, and thus is ignorant of, the message it encrypts.)
! 2202:
! 2203: This is not perfect, but it's an improvement on how session
! 2204: keys used to be generated, and can be changed in future
! 2205: without compatibility worries.
1.1.1.2 root 2206: */
2207:
1.1.1.3 ! root 2208: if (!already_have_md5) /* Obtain some random bits from the input file */
! 2209: { MD5_CTX MD;
! 2210:
! 2211: MD5Init(&MD);
! 2212: MDfile0_len(&MD, f, 4096); /* Ignore errors - what could be done? */
! 2213: MD5Final(&MD);
! 2214:
! 2215: fseek(f, 0, SEEK_SET); /* Get back to the beginning for encryption */
! 2216:
! 2217: memcpy(md5buf, MD.digest, 16);
! 2218:
! 2219: burn(&MD);
! 2220: already_have_md5 = 1;
! 2221: }
! 2222:
1.1.1.2 root 2223: ckp_length = make_random_ideakey(ideakey);
1.1.1.3 ! root 2224: /* Returns a 24 byte random IDEA key */
1.1.1.2 root 2225:
1.1.1.3 ! root 2226: /* Assume MSB external byte ordering */
1.1.1.2 root 2227: /* Prepend identifier byte to key */
1.1.1.3 ! root 2228: keybuf[0] = IDEA_ALGORITHM_BYTE;
1.1.1.2 root 2229: for (i=0; i<ckp_length; ++i)
1.1.1.3 ! root 2230: keybuf[i+1] = ideakey[i];
1.1.1.2 root 2231: /* Compute and append checksum to the key */
1.1.1.3 ! root 2232: chksum = checksum (keybuf+1, ckp_length);
1.1.1.2 root 2233: ckp_length++;
1.1.1.3 ! root 2234: put_word16((word16) chksum, keybuf+ckp_length);
1.1.1.2 root 2235: ckp_length += 2;
2236:
1.1.1.3 ! root 2237: /* Ok, we now have our IDEA key which we are going to use
! 2238: * to encrypt our packet. We have stuffed it into a packet
! 2239: * which we can now encrypt in the Public Key of EACH USER
! 2240: * which we want to be able to decrypt this message. Now we
! 2241: * will walk down mcguffins until we hit a NULL or NULL string,
! 2242: * and we will encrypt for each user in the list, and write
! 2243: * that out to the output file.
! 2244: *
! 2245: * -derek <[email protected]> 13 Dec 1992
! 2246: */
1.1.1.2 root 2247:
1.1.1.3 ! root 2248: for (i = 0; mcguffins[i] != NULL; ++i)
! 2249: ;
! 2250: if (encrypt_to_self)
! 2251: ++i;
! 2252: keyID_list = xmalloc(i * KEYFRAGSIZE);
! 2253: /* Iterate through users */
! 2254: for (; *mcguffins && **mcguffins ; ++mcguffins) {
! 2255: buildfilename(keyfile,PUBLIC_KEYRING_FILENAME);
! 2256: /* use default pathname */
! 2257:
! 2258: keys_used =
! 2259: encryptkeyintofile(g, *mcguffins, keybuf,
! 2260: keyfile, ckp_length, keys_used);
! 2261: } /* for */
1.1.1.2 root 2262:
1.1.1.3 ! root 2263: if (!keys_used)
! 2264: { fclose(f);
! 2265: fclose(g);
! 2266: free(keyID_list);
! 2267: return -1;
! 2268: }
1.1.1.2 root 2269:
1.1.1.3 ! root 2270: /* encrypt to myself if need be */
! 2271: if (encrypt_to_self && *my_name) {
! 2272: keys_used =
! 2273: encryptkeyintofile(g, my_name, keybuf,
! 2274: keyfile, ckp_length, keys_used);
! 2275: }
! 2276: free(keyID_list);
1.1.1.2 root 2277:
1.1.1.3 ! root 2278: close_idearand();
1.1.1.2 root 2279: /** Finished with RSA block containing IDEA key. */
2280:
2281: /* Now compress the plaintext and encrypt it with IDEA... */
2282: squish_and_idea_file( ideakey, f, g, attempt_compression );
2283:
1.1.1.3 ! root 2284: burn(keybuf); /* burn the Idea Key Packet */
1.1.1.2 root 2285: burn(ideakey); /* burn sensitive data on stack */
2286:
2287: fclose(f);
2288: if (write_error(g))
2289: { fclose(g);
2290: return -1;
2291: }
2292: fclose(g);
2293:
2294: return(0);
2295: } /* encryptfile */
2296:
2297:
1.1.1.3 ! root 2298: static int
! 2299: encryptkeyintofile(FILE *g, char *mcguffin, byte *keybuf,
! 2300: char *keyfile, int ckp_length, int keys_used) {
! 2301: int i;
! 2302: byte randompad[MAX_BYTE_PRECISION]; /* buffer of random pad bytes */
! 2303: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
! 2304: byte keyID[KEYFRAGSIZE];
! 2305: byte inbuf[MAX_BYTE_PRECISION];
! 2306: byte outbuf[MAX_BYTE_PRECISION];
! 2307: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
! 2308: byte userid[256];
! 2309: long fp;
! 2310: int blocksize;
! 2311: byte ver, alg;
! 2312: byte (*keyp)[KEYFRAGSIZE];
! 2313:
! 2314:
! 2315: /* This "loop" is so we can break out at opportune moments */
! 2316: do {
! 2317: userid[0] = '\0';
! 2318:
! 2319: strcpy((char *)userid,mcguffin);
! 2320: /* Who we are looking for (C string) */
! 2321:
! 2322: /* Get and validate public key from a key file:
! 2323: * We will be nice and ask the user ONCE (and ONLY once)
! 2324: * for a keyfile if its not in the default.
! 2325: */
! 2326:
! 2327: if (getpublickey((quietmode?0:GPK_SHOW)|GPK_NORVK, keyfile, &fp, NULL, NULL,
! 2328: timestamp, userid, n, e) < 0)
! 2329: { fprintf(pgpout, PSTR("\n\007Cannot find the public key matching userid '%s'\n\
! 2330: This user will not be able to decrypt this message.\n"),
! 2331: LOCAL_CHARSET(mcguffin));
! 2332: continue;
! 2333: }
! 2334:
! 2335: /* Make sure we haven't already used this key */
! 2336: extract_keyID(keyID, n);
! 2337: for (keyp = keyID_list; keyp < keyID_list+keys_used; ++keyp)
! 2338: { if (!memcmp(keyp, keyID, KEYFRAGSIZE))
! 2339: break;
! 2340: }
! 2341:
! 2342: if (keyp < keyID_list + keys_used)
! 2343: { /* This key was already specified. Quietly ignore it. */
! 2344: continue;
! 2345: }
! 2346:
! 2347: /* Add this keyID to the list of keys used so far */
! 2348: memcpy(keyp, keyID, KEYFRAGSIZE);
! 2349:
! 2350: PascalToC((char *)userid);
! 2351: if (warn_signatures(keyfile, fp, (char *)userid,
! 2352: FALSE) < 0) {
! 2353: fprintf(pgpout, "Ok, skipping userid %s\n", mcguffin);
! 2354: continue;
! 2355: }
! 2356:
! 2357: /* set_precision has been properly called by getpublickey */
! 2358:
! 2359: /* Note that RSA key must be at least big enough
! 2360: to encipher a complete conventional key packet
! 2361: in a single RSA block.
! 2362: */
! 2363:
! 2364: blocksize = countbytes(n)-1;
! 2365: /* size of a plaintext block */
! 2366:
! 2367: if (blocksize < 31) {
! 2368: fprintf(pgpout,"\n\007Error: RSA key length must be at least 256 bits.\n");
! 2369: fprintf(pgpout, "Skipping userid %s\n", mcguffin);
! 2370: continue;
! 2371: }
! 2372:
! 2373:
! 2374: /*
! 2375: ** Messages encrypted with a public key should use
! 2376: ** random padding, while messages "signed" with a
! 2377: ** secret key should use constant padding.
! 2378: */
! 2379:
! 2380: for (i = 0; i < (blocksize - ckp_length); i++)
! 2381: while (!(randompad[i] = idearand()))
! 2382: ; /* Allow only nonzero values */
! 2383:
! 2384: /*
! 2385: ** Note that RSA key must be at least big enough
! 2386: ** to encipher a complete conventional key packet
! 2387: ** in a single RSA block.
! 2388: */
! 2389:
! 2390: /* ckp_length is conventional key packet length. */
! 2391:
! 2392: /* Do the padding here */
! 2393: preblock( (unitptr)inbuf, keybuf, ckp_length, n, randompad );
! 2394:
! 2395: /* XXX This is dangerous... This will print out the
! 2396: * IDEA Key, which is a breach of security!
! 2397: */
! 2398: #ifdef MR_DEBUG
! 2399: fprintf(pgpout, "IdeaKey and Random Pad: ");
! 2400: for (i = 0; i < blocksize; i++) {
! 2401: fprintf(pgpout, "%02X ", inbuf[i]);
! 2402: }
! 2403: fprintf(pgpout, "\n");
! 2404: #endif
! 2405: mp_modexp( (unitptr)outbuf, (unitptr)inbuf, e, n );
! 2406: /* RSA encrypt */
! 2407:
! 2408: /* write out header record to outfile ... */
! 2409:
! 2410: /* PKE is Public Key Encryption */
! 2411: write_ctb_len (g, CTB_PKE_TYPE,
! 2412: 1+KEYFRAGSIZE+1+2+countbytes((unitptr)outbuf),
! 2413: FALSE);
! 2414:
! 2415: /* Write version byte */
! 2416: ver = VERSION_BYTE;
! 2417: fwrite (&ver, 1, 1, g);
! 2418:
! 2419: writekeyID( n, g );
! 2420: /* write msg prefix fragment of modulus n */
! 2421:
! 2422: /* Write algorithm byte */
! 2423: alg = RSA_ALGORITHM_BYTE;
! 2424: fwrite (&alg, 1, 1, g);
! 2425:
! 2426: /* convert RSA ciphertext block via reg2mpi and
! 2427: * write to file
! 2428: */
! 2429:
! 2430: write_mpi( (unitptr)outbuf, g, FALSE );
! 2431:
! 2432: burn(inbuf); /* burn sensitive data on stack */
! 2433: burn(outbuf); /* burn sensitive data on stack */
! 2434: ++keys_used;
! 2435:
! 2436: } while (0);
! 2437:
! 2438: return(keys_used);
! 2439: } /* encryptkeyintofile */
! 2440:
1.1.1.2 root 2441: /*======================================================================*/
2442: int make_literal(char *infile, char *outfile, char lit_mode, char *literalfile)
2443: { /* Prepend a CTB_LITERAL prefix to a file. Convert to canonical form if
2444: lit_mode is MODE_TEXT.
2445: */
2446: char lfile[MAX_PATH];
2447: FILE *f;
2448: FILE *g;
2449: int status = 0;
2450: #ifdef VMS
2451: char *fdl;
2452: short fdl_len;
2453: #endif /* VMS */
2454:
2455: word32 flen, fpos;
2456: word32 dummystamp = 0;
2457:
2458: if (verbose)
2459: fprintf(pgpout,"make_literal: infile = %s, outfile = %s, mode = '%c', literalfile = '%s'\n",
2460: infile,outfile,lit_mode,literalfile);
2461:
2462: /* open file f for read, in binary or text mode...*/
2463:
2464: #ifdef VMS
2465: if (lit_mode == MODE_LOCAL) {
2466: if (!(fdl_generate(infile, &fdl, &fdl_len ) & 01)) {
2467: fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile);
2468: return(-1);
2469: }
2470: }
2471: #endif /*VMS*/
2472: if (lit_mode == MODE_TEXT)
2473: f = fopen(infile, FOPRTXT);
2474: else
2475: f = fopen(infile, FOPRBIN);
2476: if (f == NULL)
2477: { fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile);
2478: return(-1);
2479: }
2480: flen = fsize(f);
2481:
2482: /* open file g for write, in binary (not text) mode... */
2483: if ((g = fopen( outfile,FOPWBIN )) == NULL)
2484: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile );
2485: goto err1;
2486: }
2487:
2488: if (literalfile == NULL)
2489: { /* Put in a zero byte to indicate no filename */
2490: lfile[0] = '\0';
2491: }
2492: else
2493: { strcpy( lfile, literalfile );
2494: file_to_canon( lfile );
2495: CToPascal( lfile );
2496: }
2497:
2498: #ifdef USE_LITERAL2
2499: #define LENGTH_FIELD (flen + (unsigned char) lfile[0] + 6)
2500: #define LIT_TYPE CTB_LITERAL2_TYPE
2501: #else
2502: #define LENGTH_FIELD flen
2503: #define LIT_TYPE CTB_LITERAL_TYPE
2504: #endif
2505: if (lit_mode == MODE_BINARY)
2506: write_ctb_len (g, LIT_TYPE, LENGTH_FIELD, FALSE);
2507: #ifdef VMS
2508: else if (lit_mode == MODE_LOCAL)
2509: write_ctb_len (g, CTB_LITERAL2_TYPE, flen + fdl_len + sizeof(fdl_len) + 6, TRUE);
2510: #endif /* VMS */
2511: else /* Will put in size field later for text mode */
2512: write_ctb_len (g, LIT_TYPE, 0L, TRUE);
2513: #ifdef USE_LITERAL2
2514: fpos = ftell(g);
2515: #endif
2516: fwrite ( &lit_mode, 1, 1, g ); /* write lit_mode */
2517:
2518: if (lit_mode == MODE_LOCAL) {
2519: #ifdef VMS
2520: write_litlocal( g, fdl, fdl_len);
2521: free(fdl);
2522: #else
2523: ; /* Null statement if we don't have anything to do! */
2524: #endif /* VMS */
2525: } else {
2526: /* write literalfile name */
2527: fwrite (lfile, 1, (unsigned char) lfile[0]+1, g);
2528: /* Dummy file creation timestamp */
2529: fwrite ( &dummystamp, 1, sizeof(dummystamp), g);
2530: }
2531: #ifndef USE_LITERAL2
2532: fpos = ftell(g);
2533: #endif
2534:
2535: if ((lit_mode == MODE_BINARY) || (lit_mode == MODE_LOCAL)) {
2536: if (copyfile( f, g, -1L )) {
2537: fprintf(pgpout,"\n\007Unable to append to literal plaintext file");
2538: perror("\n");
2539: fclose(g);
2540: goto err1;
2541: }
2542: } else {
2543: CONVERSION = (lit_mode == MODE_TEXT) ? INT_CONV : NO_CONV;
2544: status = copyfile_to_canon( f, g, -1L );
2545: CONVERSION = NO_CONV;
2546: /* Re-write CTB with correct length info */
2547: rewind (g);
2548: write_ctb_len (g, LIT_TYPE, fsize(g)-fpos, TRUE);
2549: }
2550: if (write_error(g) || status < 0)
2551: { fclose(g);
2552: goto err1;
2553: }
2554: fclose(g);
2555: fclose(f);
2556: return(0); /* normal return */
2557:
2558: err1:
2559: fclose(f);
2560: return(-1); /* error return */
2561:
2562: } /* make_literal */
2563: #undef LENGTH_FIELD
2564: #undef LIT_TYPE
2565:
2566:
2567: /*======================================================================*/
2568: int strip_literal(char *infile, char *outfile, char *preserved_name,
2569: char *lit_mode)
2570: { /* Strip off literal prefix from infile, copying to outfile.
2571: Get lit_mode and literalfile info from
2572: the prefix. Replace outfile with literalfile unless
2573: literalfile is illegal
2574: the original filename is stored in preserved_name
2575: If lit_mode is MODE_TEXT, convert from canonical form as we
2576: copy the data.
2577: */
2578: byte ctb; /* Cipher Type Byte */
2579: FILE *f;
2580: FILE *g;
2581: word32 LITlength = 0;
2582: unsigned char litfile[MAX_PATH];
2583: word32 dummystamp;
2584: char org_sys[5]; /* Name of originating system */
2585: int status;
2586: #ifdef VMS
2587: char *fdl;
2588: short fdl_len;
2589: #endif
2590: *lit_mode = MODE_BINARY;
2591: if (verbose)
2592: fprintf(pgpout,"strip_literal: infile = %s, outfile = %s\n",
2593: infile,outfile);
2594:
2595: if (preserved_name)
2596: *preserved_name = '\0';
2597:
2598: /* open file f for read, in binary (not text) mode...*/
2599: if ((f = fopen(infile,FOPRBIN)) == NULL)
2600: { fprintf(pgpout,PSTR("\n\007Can't open input plaintext file '%s'\n"),infile);
2601: return(-1);
2602: }
2603:
2604: fread(&ctb,1,1,f); /* read Cipher Type Byte */
2605:
2606: if (!is_ctb(ctb) || !(is_ctb_type(ctb,CTB_LITERAL_TYPE) ||
2607: is_ctb_type(ctb,CTB_LITERAL2_TYPE)))
2608: { /* debug message in English only -- something got corrupted */
2609: fprintf(pgpout,"\n\007'%s' is not a literal plaintext file.\n",infile);
2610: fclose(f);
2611: return(-1);
2612: }
2613:
2614: LITlength = getpastlength(ctb, f); /* read packet length */
2615:
2616: /* Read literal data */
2617: *lit_mode = '\0';
2618: fread (lit_mode,1,1,f);
2619: if ((*lit_mode != MODE_BINARY) && (*lit_mode != MODE_TEXT)
2620: && (*lit_mode != MODE_LOCAL))
2621: { (void) version_error(*lit_mode, MODE_TEXT);
2622: fclose(f);
2623: return(-1);
2624: }
2625: if (verbose)
2626: fprintf(pgpout, PSTR("File type: '%c'\n"), *lit_mode);
2627: /* Read literal file name, use it if possible */
2628: litfile[0] = 0;
2629: fread (litfile,1,1,f);
2630: if (is_ctb_type(ctb, CTB_LITERAL2_TYPE))
2631: { /* subtract header length: namelength + lengthbyte + modebyte + stamp */
2632: LITlength -= litfile[0] + 2 + sizeof(dummystamp);
2633: }
2634: /* Use litfile if it's writeable and he didn't say an outfile */
1.1.1.3 ! root 2635: if (litfile[0] > 0)
! 2636: { if ((int)litfile[0] >= MAX_PATH)
! 2637: { fseek(f, litfile[0], SEEK_CUR);
! 2638: litfile[0] = 0;
! 2639: }
! 2640: else
! 2641: fread (litfile+1,1,litfile[0],f);
! 2642: }
! 2643: if (litfile[0])
1.1.1.2 root 2644: { PascalToC( (char *)litfile );
2645: if (verbose)
2646: fprintf(pgpout, PSTR("Original plaintext file name was: '%s'\n"), litfile);
2647: if (preserved_name)
2648: strcpy(preserved_name, (char *) litfile);
2649: }
2650: if (*lit_mode == MODE_LOCAL) {
2651: fread(org_sys, 1, 4, f); org_sys[4] = '\0';
2652: #ifdef VMS
2653: #define LOCAL_TEST !strncmp("VMS ",org_sys,4)
2654: #else
2655: #define LOCAL_TEST FALSE
2656: #endif
2657: if (LOCAL_TEST) {
2658: #ifdef VMS
2659: remove(outfile); /* Prevent litter, we recreate the file with correct chars. */
2660: fread(&fdl_len, 2, 1, f);
2661: fdl = (char *) malloc(fdl_len);
2662: fread(fdl, 1, fdl_len, f);
2663: if ((g = fdl_create( fdl, fdl_len, outfile, (char *) litfile)) == NULL) {
2664: fprintf(pgpout,"\n\007Unable to create file %s\n", outfile);
2665: return(-1);
2666: }
2667: free(fdl);
2668: if (preserved_name)
2669: strcpy(preserved_name, (char *) litfile);
2670: LITlength -= (fdl_len + sizeof(fdl_len));
2671: #endif /* VMS */
2672: } else {
2673: fprintf(pgpout,"\n\007Unrecognised local binary type %s\n",org_sys);
2674: return(-1);
2675: }
2676: } else {
2677: /* Discard file creation timestamp for now */
2678: fread (&dummystamp, 1, sizeof(dummystamp), f);
2679: }
2680:
2681: if (*lit_mode==MODE_LOCAL) {
2682: #ifdef VMS
2683: if (status = fdl_copyfile2bin( f, g, LITlength)) { /* Copy ok? */
2684: if (status > 0)
2685: fprintf(stderr,"\n...copying to literal file\n");
2686: else
2687: perror("\nError copying from work file");
2688: fdl_close(g);
2689: goto err1;
2690: }
2691: fdl_close(g);
2692: #endif /*VMS */
2693: } else {
2694: if (*lit_mode == MODE_TEXT)
2695: g = fopen(outfile, FOPWTXT);
2696: else
2697: g = fopen(outfile, FOPWBIN);
2698: if (g == NULL)
2699: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile );
2700: goto err1;
2701: }
2702: /* copy rest of literal plaintext file */
2703: CONVERSION = (*lit_mode == MODE_TEXT) ? EXT_CONV : NO_CONV;
2704: if (*lit_mode == MODE_BINARY)
2705: status = copyfile(f, g, LITlength);
2706: else
2707: status = copyfile_from_canon(f, g, LITlength);
2708: CONVERSION = NO_CONV;
2709: if (write_error(g) || status < 0)
2710: { fclose(g);
2711: goto err1;
2712: }
2713: fclose(g);
2714: }
2715:
2716: fclose(f);
2717: return(0); /* normal return */
2718:
2719: err1:
2720: fclose(f);
2721: return(-1); /* error return */
2722:
2723: } /* strip_literal */
2724:
2725:
2726: /*======================================================================*/
2727:
2728:
2729: int decryptfile(char *infile, char *outfile)
2730: {
2731: byte ctb; /* Cipher Type Byte */
2732: byte ctbCKE; /* Cipher Type Byte */
2733: FILE *f;
2734: FILE *g;
1.1.1.3 ! root 2735: int count, status, thiskey, gotkey, end_of_pkes;
1.1.1.2 root 2736: unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION];
2737: unit p[MAX_UNIT_PRECISION], q[MAX_UNIT_PRECISION], u[MAX_UNIT_PRECISION];
2738: byte inbuf[MAX_BYTE_PRECISION];
2739: byte outbuf[MAX_BYTE_PRECISION];
2740: byte keyID[KEYFRAGSIZE];
2741: word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */
2742: byte userid[256];
2743: word32 flen;
1.1.1.3 ! root 2744: word32 fpos = 0;
1.1.1.2 root 2745: byte ver, alg;
1.1.1.3 ! root 2746: short realprecision = 0;
1.1.1.2 root 2747: word16 chksum;
1.1.1.3 ! root 2748: struct nkey {
! 2749: byte keyID[KEYFRAGSIZE];
! 2750: struct nkey *next;
! 2751: } *nkey, *nkeys = NULL;
1.1.1.2 root 2752:
2753: if (verbose)
2754: fprintf(pgpout,"decryptfile: infile = %s, outfile = %s\n",
2755: infile,outfile);
2756:
2757: /* open file f for read, in binary (not text) mode...*/
2758: if ((f = fopen(infile,FOPRBIN)) == NULL)
2759: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile);
2760: return(-1);
2761: }
2762:
1.1.1.3 ! root 2763: /* Now we have to keep reading in packets until we either get
! 2764: * to a non PKE-type packet or we find our own... Once we find
! 2765: * our own, we're gonna have to get our private key, and then
! 2766: * keep going until we find the end of the PKE packets
! 2767: *
! 2768: * -derek <[email protected]> 13 Dec 1992
! 2769: */
1.1.1.2 root 2770:
1.1.1.3 ! root 2771: gotkey = end_of_pkes = 0; /* Set this flag now. */
! 2772: do {
! 2773: thiskey = 0;
! 2774:
! 2775: set_precision(MAX_UNIT_PRECISION);
! 2776: /* Need to set this EACH TIME... Sigh. This is because
! 2777: * read_mpi needs to have a global_precision which is
! 2778: * >= the size of the key. Therefore once we find the
! 2779: * real key, we save off the precision and then we'll
! 2780: * reset it later. -derek
! 2781: */
! 2782:
! 2783: fread(&ctb,1,1,f); /* read Cipher Type Byte */
! 2784: if (!is_ctb(ctb)) {
! 2785: fprintf(pgpout,PSTR("\n\007'%s' is not a cipher file.\n"),infile);
! 2786: fclose(f);
! 2787: return(-1);
! 2788: }
1.1.1.2 root 2789:
1.1.1.3 ! root 2790: /* PKE is Public Key Encryption */
! 2791: if (!is_ctb_type(ctb,CTB_PKE_TYPE)) {
! 2792: end_of_pkes = 1;
! 2793: continue;
! 2794: }
1.1.1.2 root 2795:
1.1.1.3 ! root 2796: getpastlength(ctb, f); /* read packet length */
! 2797:
! 2798: /* Read and check version */
! 2799: fread (&ver, 1, 1, f);
! 2800: if (version_error(ver, VERSION_BYTE))
! 2801: { fclose (f);
! 2802: return (-1);
! 2803: }
1.1.1.2 root 2804:
1.1.1.3 ! root 2805: fread(keyID,1,KEYFRAGSIZE,f); /* read key ID */
! 2806: /* Use keyID prefix to look up key. */
1.1.1.2 root 2807:
1.1.1.3 ! root 2808: /* Add this keyID to the list of keys read in */
! 2809: if ((nkey = (struct nkey *) malloc(sizeof(struct nkey)))
! 2810: == NULL) {
! 2811: fprintf(stderr, PSTR("\n\007Out of memory.\n"));
! 2812: exitPGP(7);
! 2813: }
! 2814: memcpy(nkey->keyID, keyID, KEYFRAGSIZE);
! 2815: nkey->next = nkeys;
! 2816: nkeys = nkey;
! 2817:
! 2818: /* Read and check algorithm */
! 2819: fread (&alg, 1, 1, f);
! 2820: if (version_error(alg, RSA_ALGORITHM_BYTE))
! 2821: { fclose (f);
! 2822: return (-1);
! 2823: }
1.1.1.2 root 2824:
1.1.1.3 ! root 2825: if (!gotkey) /* Only do this if we havent already */
! 2826: /* Get and validate secret key from a key file: */
! 2827: if (getsecretkey(GPK_GIVEUP|(quietmode?0:GPK_SHOW), NULL, keyID,
! 2828: timestamp, NULL, NULL,userid,
! 2829: n, e, d, p, q, u) == 0)
! 2830: {
! 2831: thiskey = gotkey = 1;
! 2832: realprecision = global_precision;
! 2833: } else {
! 2834: set_precision(MAX_UNIT_PRECISION);
! 2835: }
! 2836: /* DAMN this... This is REALLY frustrating, that I have to
! 2837: * do this... Basically, if I go to getsecretkey, it will
! 2838: * set the precision, and the precision might NOT be correct
! 2839: * if the key I get is not correct, so I have to set the
! 2840: * precision NUMEROUS times in this loop.. This sucks,
! 2841: * but its the only way. Sigh.
! 2842: *
! 2843: * -derek <[email protected]> 13 Dec 1992
! 2844: */
! 2845:
! 2846: /* Note that RSA key must be at least big enough
! 2847: to encipher a complete conventional key packet in
! 2848: a single RSA block. */
! 2849:
! 2850: /*========================================================*/
! 2851: /* read ciphertext block, converting to internal format: */
! 2852: read_mpi((unitptr)inbuf, f, FALSE, FALSE);
! 2853:
! 2854: if (thiskey) {
! 2855: if (!quietmode && thiskey) {
! 2856: fprintf(pgpout,PSTR("Just a moment..."));
! 2857: /* RSA will take a while. */
! 2858: fflush(pgpout);
! 2859: }
1.1.1.2 root 2860:
1.1.1.3 ! root 2861: rsa_decrypt((unitptr)outbuf, (unitptr)inbuf, d,
! 2862: p, q, u);
1.1.1.2 root 2863:
1.1.1.3 ! root 2864: if (!quietmode)
! 2865: fputc('.',pgpout);
! 2866: /* Signal RSA completion. */
! 2867: }
! 2868:
! 2869: fpos = ftell(f); /* Save this position */
! 2870:
! 2871: } while (!end_of_pkes); /* Loop until end of PKE packets */
! 2872:
! 2873: /* Should we list the recipients? */
! 2874: if (!gotkey || verbose) {
! 2875: char *user;
! 2876:
! 2877: setkrent(NULL);
! 2878: init_userhash();
! 2879: if (gotkey) /* verbose flag */
! 2880: fprintf(pgpout,"\nRecipients:\n");
! 2881: else
! 2882: fprintf(pgpout,PSTR("\nThis message can only be read by:\n"));
! 2883:
! 2884: for (nkey = nkeys; nkey; nkey = nkey->next) {
! 2885: if ((user = user_from_keyID(nkey->keyID)) == NULL)
! 2886: fprintf(pgpout, " keyID: %s\n", keyIDstring(nkey->keyID));
! 2887: else
! 2888: fprintf(pgpout, " %s\n", LOCAL_CHARSET(user));
! 2889: }
! 2890: endkrent();
! 2891: }
! 2892: for (nkey = nkeys; nkey; )
! 2893: { nkey = nkey->next;
! 2894: free(nkeys);
! 2895: nkeys = nkey;
! 2896: }
! 2897:
! 2898: /* Ok, Now lets clean up, and continue on to the rest of the file so
! 2899: * that it can be decrypted properly. Things should be ok once I
! 2900: * reset some stuff here... -derek
! 2901: */
! 2902: if (gotkey)
! 2903: {
! 2904: fseek(f, fpos, SEEK_SET); /* Get back to the Real McCoy! */
! 2905: set_precision(realprecision); /* reset the precision */
! 2906: }
! 2907: else
! 2908: { /* No secret key, exit gracefully (NOT!) */
! 2909: fprintf(pgpout, PSTR("\n\007You do not have the secret key needed to decrypt this file.\n"));
! 2910: fclose(f);
! 2911: return(-1);
! 2912: }
1.1.1.2 root 2913:
2914: if ((count = postunblock(outbuf, (unitptr)outbuf, n)) < 0)
2915: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\
2916: This may be caused either by corrupted data or by using the wrong RSA key.\n"));
2917: fclose(f);
2918: return(-1);
2919: }
2920:
2921: /* Verify that top of buffer has correct algorithm byte */
2922: --count; /* one less byte to drop algorithm byte */
1.1.1.3 ! root 2923: /* Assume MSB external byte ordering */
1.1.1.2 root 2924: if (version_error(outbuf[0], IDEA_ALGORITHM_BYTE))
2925: { fclose(f);
2926: return(-1);
2927: }
2928:
2929: /* Verify checksum */
2930: count -= 2; /* back up before checksum */
1.1.1.3 ! root 2931: /* Assume MSB external byte ordering */
1.1.1.2 root 2932: chksum = fetch_word16(outbuf+1+count);
2933: if (chksum != checksum(outbuf+1, count))
2934: { fprintf(pgpout,PSTR("\n\007Error: RSA-decrypted block is corrupted.\n\
2935: This may be caused either by corrupted data or by using the wrong RSA key.\n"));
2936: fclose(f);
2937: return(-1);
2938: }
2939:
2940: /* outbuf should contain random IDEA key packet */
2941: /*==================================================================*/
2942:
2943: /* open file g for write, in binary (not text) mode... */
2944:
2945: if ((g = fopen( outfile, FOPWBIN )) == NULL)
2946: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile );
2947: goto err1;
2948: }
2949:
2950: fread(&ctbCKE,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */
2951: if (!is_ctb(ctbCKE) || !is_ctb_type(ctbCKE,CTB_CKE_TYPE))
2952: { /* Should never get here. */
2953: fprintf(pgpout,"\007\nBad or missing CTB_CKE byte.\n");
2954: goto err1; /* Abandon ship! */
2955: }
2956:
2957: flen = getpastlength(ctbCKE, f); /* read packet length */
2958:
2959: /* Decrypt ciphertext file */
1.1.1.3 ! root 2960: /* Assume MSB external byte ordering */
1.1.1.2 root 2961: status = idea_file( outbuf+1, DECRYPT_IT, f, g, flen );
2962: if (status < 0)
2963: { fprintf(pgpout,PSTR("\n\007Error: Decrypted plaintext is corrupted.\n"));
2964: }
1.1.1.3 ! root 2965: if (!quietmode)
1.1.1.2 root 2966: fputc('.',pgpout); /* show progress */
2967:
2968: if (write_error(g))
2969: { fclose(g);
2970: goto err1;
2971: }
2972: fclose(g);
2973: fclose(f);
2974: burn(inbuf); /* burn sensitive data on stack */
2975: burn(outbuf); /* burn sensitive data on stack */
2976: mp_burn(d); /* burn sensitive data on stack */
2977: mp_burn(p); /* burn sensitive data on stack */
2978: mp_burn(q); /* burn sensitive data on stack */
2979: mp_burn(u); /* burn sensitive data on stack */
2980: if (status < 0) /* if idea_file failed, then error return */
2981: return(status);
2982: return(1); /* always indicate output file has nested stuff in it. */
2983:
2984: err1:
2985: fclose(f);
2986: burn(inbuf); /* burn sensitive data on stack */
2987: burn(outbuf); /* burn sensitive data on stack */
2988: mp_burn(d); /* burn sensitive data on stack */
2989: mp_burn(p); /* burn sensitive data on stack */
2990: mp_burn(q); /* burn sensitive data on stack */
2991: mp_burn(u); /* burn sensitive data on stack */
2992: return(-1); /* error return */
2993:
2994: } /* decryptfile */
2995:
2996:
2997:
2998: int idea_decryptfile(char *infile, char *outfile)
2999: {
3000: byte ctb; /* Cipher Type Byte */
3001: FILE *f;
3002: FILE *g;
3003: byte ideakey[16];
3004: byte passphrase[256];
1.1.1.3 ! root 3005: int status, retries = 0;
1.1.1.2 root 3006: word32 flen;
3007:
3008: if (verbose)
3009: fprintf(pgpout,"idea_decryptfile: infile = %s, outfile = %s\n",
3010: infile,outfile);
3011:
3012: /* open file f for read, in binary (not text) mode...*/
3013: if ((f = fopen(infile,FOPRBIN)) == NULL)
3014: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),infile);
3015: return(-1);
3016: }
3017:
3018: /* open file g for write, in binary (not text) mode... */
3019: if ((g = fopen( outfile, FOPWBIN )) == NULL)
3020: { fprintf(pgpout, PSTR("\n\007Can't create plaintext file '%s'\n"), outfile );
3021: goto err1;
3022: }
3023:
1.1.1.3 ! root 3024: if (*password == '\0')
! 3025: ++retries; /* no PGPPASS or -z */
! 3026: do /* while pass phrase is bad */
! 3027: {
! 3028: fread(&ctb,1,1,f); /* read Cipher Type Byte, should be CTB_CKE */
! 3029:
! 3030: if (!is_ctb(ctb) || !is_ctb_type(ctb,CTB_CKE_TYPE))
! 3031: { /* Should never get here. */
! 3032: fprintf(pgpout,"\007\nBad or missing CTB_CKE byte.\n");
1.1.1.2 root 3033: fclose(g);
1.1.1.3 ! root 3034: goto err1; /* Abandon ship! */
1.1.1.2 root 3035: }
1.1.1.3 ! root 3036: flen = getpastlength(ctb, f); /* read packet length */
1.1.1.2 root 3037:
1.1.1.3 ! root 3038: /* Get IDEA password, hashed */
! 3039: if (retries == 0)
! 3040: /* first try environment password */
! 3041: hashpass(password, strlen(password), ideakey);
! 3042: else {
! 3043: fprintf(pgpout,PSTR("\nYou need a pass phrase to decrypt this file. "));
! 3044: if (batchmode || GetHashedPassPhrase((char *)passphrase,(char *)ideakey,NOECHO1) <= 0)
! 3045: { fclose(f);
! 3046: fclose(g);
! 3047: return(-1);
! 3048: }
! 3049: }
1.1.1.2 root 3050:
1.1.1.3 ! root 3051: if (!quietmode)
! 3052: { fprintf(pgpout,PSTR("Just a moment...")); /* this may take a while */
! 3053: fflush(pgpout);
! 3054: }
! 3055:
! 3056: status = idea_file( ideakey, DECRYPT_IT, f, g, flen );
! 3057: if (status == 0)
! 3058: break;
! 3059: if (retries) /* first try is PGPPASS */
! 3060: fprintf(pgpout,PSTR("\n\007Error: Bad pass phrase.\n"));
! 3061: rewind(f);
! 3062: rewind(g);
! 3063: } while (status == -2 && ++retries < 3);
1.1.1.2 root 3064:
3065: burn(ideakey); /* burn sensitive data on stack */
3066: burn(passphrase);
3067:
1.1.1.3 ! root 3068: if (status == 0 && !quietmode)
1.1.1.2 root 3069: fputc('.',pgpout); /* show progress */
3070:
3071: if (write_error(g))
3072: { fclose(g);
3073: goto err1;
3074: }
3075: fclose(g);
3076: fclose(f);
3077:
3078: if (status < 0) /* if idea_file failed, then complain */
1.1.1.3 ! root 3079: { remove(outfile); /* throw away our mistake */
1.1.1.2 root 3080: return(status); /* error return */
3081: }
1.1.1.3 ! root 3082: if (!quietmode)
1.1.1.2 root 3083: fprintf(pgpout,PSTR("Pass phrase appears good. "));
3084: return(1); /* always indicate output file has nested stuff in it. */
3085:
3086: err1:
3087: fclose(f);
3088: return(-1); /* error return */
3089:
3090: } /* idea_decryptfile */
3091:
3092:
3093:
3094: int decompress_file(char *infile, char *outfile)
3095: {
3096: byte ctb;
3097: FILE *f;
3098: FILE *g;
3099: extern void lzhDecode( FILE *, FILE * );
3100: extern void unzip( FILE *, FILE * );
3101: if (verbose) fprintf(pgpout, PSTR("Decompressing plaintext...") );
3102:
3103: /* open file f for read, in binary (not text) mode...*/
3104: if ((f = fopen(infile,FOPRBIN)) == NULL)
3105: { fprintf(pgpout,PSTR("\n\007Can't open compressed file '%s'\n"),infile);
3106: return(-1);
3107: }
3108:
3109: fread(&ctb,1,1,f); /* read and skip over Cipher Type Byte */
3110: if (!is_ctb_type( ctb, CTB_COMPRESSED_TYPE ))
3111: { /* Shouldn't get here, or why were we called to begin with? */
3112: fprintf(pgpout,"\007\nBad or missing CTB_COMPRESSED byte.\n");
3113: goto err1; /* Abandon ship! */
3114: }
3115:
3116: getpastlength(ctb, f); /* read packet length */
3117: /* The packet length is ignored. Assume it's huge. */
3118:
3119: fread(&ctb,1,1,f); /* read and skip over compression algorithm byte */
3120: if (ctb != ZIP2_ALGORITHM_BYTE)
3121: { /* We only know how to uncompress deflate-compressed data. We
3122: may hit imploded or Lharc'ed data but treat it as an error just
3123: the same */
3124: fprintf(pgpout,PSTR("\007\nUnrecognized compression algorithm.\n\
3125: This may require a newer version of PGP.\n"));
3126: goto err1; /* Abandon ship! */
3127: }
3128:
3129: /* open file g for write, in binary (not text) mode... */
3130: if ((g = fopen( outfile, FOPWBIN )) == NULL)
3131: { fprintf(pgpout, PSTR("\n\007Can't create decompressed file '%s'\n"), outfile );
3132: goto err1;
3133: }
3134:
3135: unzip( f, g );
3136: if (verbose)
3137: fprintf(pgpout, PSTR("done. ") );
1.1.1.3 ! root 3138: else if (!quietmode)
1.1.1.2 root 3139: fputc('.',pgpout); /* show progress */
3140:
3141: if (write_error(g))
3142: { fclose(g);
3143: goto err1;
3144: }
3145: fclose(g);
3146: fclose(f);
3147: return(1); /* always indicate output file has nested stuff in it. */
3148: err1:
3149: fclose(f);
3150: return(-1); /* error return */
3151:
3152: } /* decompress_file */
3153:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.