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