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