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