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