--- pgp/src/pgp.c 2018/04/24 16:43:55 1.1.1.8 +++ pgp/src/pgp.c 2018/04/24 16:44:53 1.1.1.9 @@ -96,6 +96,8 @@ Version 2.4 - 6 Nov 93 Version 2.5 - 5 May 94 Version 2.6 - 22 May 94 + Version 2.6.1 - 29 Aug 94 + Version 2.6.2 - 11 Oct 94 Modified: 12-Nov-92 HAJK Add FDL stuff for VAX/VMS local mode. @@ -145,8 +147,8 @@ unsigned _stklen = 24 * 1024; #define STACK_WIPE 4096 /* Global filenames and system-wide file extensions... */ -char rel_version[] = _LANG("2.6.1"); /* release version */ -static char rel_date[] = "29 Aug 94"; /* release date */ +char rel_version[] = _LANG("2.6.2"); /* release version */ +static char rel_date[] = "11 Oct 94"; /* release date */ char PGP_EXTENSION[] = ".pgp"; char ASC_EXTENSION[] = ".asc"; char SIG_EXTENSION[] = ".sig"; @@ -189,7 +191,7 @@ static char *compressName[] = "LHarc"}; static char *compressExt[] = {".zip", ".zoo", ".gif", ".arj", - ".hpk", ".z", ".Z", ".pak", ".hyp", + ".hpk", ".gz", ".Z", ".pak", ".hyp", ".lzh"}; /* "\032\0??", "ARC", ".arc" */ @@ -364,11 +366,11 @@ static boolean strip_sig_flag = FALSE; boolean clear_signatures = TRUE; boolean strip_spaces; static boolean c_flag = FALSE; +static boolean u_flag = FALSE; /* Did I get my_name from -u? */ boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */ boolean batchmode = FALSE; /* if TRUE: don't ask questions */ boolean quietmode = FALSE; boolean force_flag = FALSE; /* overwrite existing file without asking */ -boolean pkcs_compat = 1; #ifdef VMS /* kludge for those stupid VMS variable-length text records */ char literal_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal @@ -385,12 +387,12 @@ boolean keepctx = FALSE; /* TRUE means k boolean interactive_add = FALSE; boolean compress_enabled = TRUE; /* attempt compression before encryption */ long timeshift = 0L; /* seconds from GMT timezone */ -boolean legal_kludge; -int version_byte = VERSION_BYTE_OLD; +int version_byte = VERSION_BYTE_NEW; boolean nomanual = 0; +/* If non-zero, initialize file to this many random bytes */ +int makerandom = 0; -static boolean attempt_compression; /* attempt compression before encryption */ static char *outputfile = NULL; static int errorLvl = EXIT_OK; static char mcguffin[256]; /* userid search tag */ @@ -416,6 +418,8 @@ int main(int argc, char *argv[]) boolean keyflag = FALSE; boolean encrypt_flag = FALSE; boolean conventional_flag = FALSE; + boolean attempt_compression; /* attempt compression before encryption */ + boolean output_stdout; /* Output goes to stdout */ char *clearfile = NULL; char *literal_file = NULL; char literal_file_name[MAX_PATH]; @@ -531,7 +535,18 @@ int main(int argc, char *argv[]) /* Process the config file first. Any command-line arguments will override the config file settings */ +#if defined(UNIX) || defined(MSDOS) || defined(OS2) + /* Try "pgp.ini" on MS-DOS or ".pgprc" on Unix */ +#ifdef UNIX + buildfilename(mcguffin, ".pgprc"); +#else + buildfilename(mcguffin, "pgp.ini"); +#endif + if (access(mcguffin, 0) != 0) + buildfilename(mcguffin, "config.txt"); +#else buildfilename(mcguffin, "config.txt"); +#endif if (access(mcguffin, 0) == 0) { opt++; if (processConfigFile(mcguffin) < 0) @@ -559,9 +574,6 @@ in AUTOEXEC.BAT file.\n")); if ((p = getenv(TEMP)) != NULL && *p != '\0') settmpdir(p); - /* Turn on incompatibility as of 1 September 1994 (GMT) */ - legal_kludge = (get_timestamp(NULL) >= 0x2e651980); - if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) { fprintf(stderr, LANG("\n\007Out of memory.\n")); exitPGP(7); @@ -644,6 +656,7 @@ in AUTOEXEC.BAT file.\n")); case 'u': strncpy(my_name, optarg, sizeof(my_name) - 1); CONVERT_TO_CANONICAL_CHARSET(my_name); + u_flag = TRUE; break; case 'w': wipeflag = TRUE; @@ -668,26 +681,19 @@ in AUTOEXEC.BAT file.\n")); signon_msg(); check_expiration_date(); /* hobble any experimental version */ - if (legal_kludge) - version_byte = VERSION_BYTE_KLUDGE; + /* + * Write to stdout if explicitly asked to, or in filter mode and + * no explicit file name was given. + */ + output_stdout = outputfile ? strcmp(outputfile, "-") == 0 : filter_mode; #if 1 /* At request of Peter Simons, use stderr always. Sounds reasonable. */ /* JIS: Put this code back in... removing it broke too many things */ - if (!filter_mode && (outputfile == NULL || strcmp(outputfile, "-"))) + if (!output_stdout) pgpout = stdout; #endif -#if 0 - /* Check for the existence of the manual */ - /* Commented out to make PGP less facist */ - if (manuals_missing()) { - fputs( -LANG("\nWARNING: PGP User's Guide not found. PGP should not be\n\ -distributed without the User's Guide.\n"), pgpout); - } -#endif - #if defined(UNIX) || defined(VMS) umask(077); /* Make files default to private */ @@ -767,6 +773,35 @@ phone +1 303 541-0140\n")); if (filter_mode) { inputfile = "stdin"; + } else if (makerandom > 0) { /* Create the input file */ + /* + * +makerandom=: Create an input file consisting of + * cryptographically strong random bytes, before applying the + * encryption options of PGP. This is an advanced option, so + * assume the user knows what he's doing and don't bother about + * overwriting questions. E.g. + * pgp +makerandom=24 foofile + * Create "foofile" with 24 random bytes in it. + * pgp +makerandom=24 -ea foofile recipient + * The same, but also encrypt it to "recipient", creating + * foofile.asc as well. + * This feature was created to allow PGP to create and send keys + * around for other applications to use. + */ + status = cryptRandWriteFile(inputfile, (struct IdeaCfbContext *)0, + (unsigned)makerandom); + if (status < 0) { + fprintf(stderr,"Error writing file \"%s\"\n",inputfile); + exitPGP(INVALID_FILE_ERROR); + } + fprintf(pgpout, LANG("File %s created containing %d random bytes.\n"), + inputfile, makerandom); + /* If we aren't encrypting, don't bother trying to decrypt this! */ + if (decrypt_mode) + exitPGP(EXIT_OK); + + /* This is obviously NOT a text file */ + literal_mode = MODE_BINARY; } else { if (decrypt_mode && no_extension(inputfile)) { strcpy(cipherfile, inputfile); @@ -831,13 +866,9 @@ phone +1 303 541-0140\n")); /* * See if plaintext input file was actually created by PGP earlier-- * If it was, maybe we should NOT encapsulate it in a literal packet. - * Otherwise, always encapsulate it. + * (nestflag = TRUE). Otherwise, always encapsulate it (default). + * (Why test for filter_mode???) */ - if (force_flag) /* for use with batchmode, force nesting */ - nestflag = legal_ctb(ctb); - else - nestflag = FALSE; /* First assume we will encapsulate it. */ - if (!batchmode && !filter_mode && legal_ctb(ctb)) { /* Special case--may be a PGP-created packet, so do we inhibit encapsulation in literal packet? */ @@ -847,12 +878,16 @@ LANG("\n\007Input file '%s' looks like i fprintf(pgpout, LANG("\nIs it safe to assume that it was created by PGP (y/N)? ")); nestflag = getyesno('n'); - } /* Possible ciphertext input file */ - if (moreflag) { /* special name to cause printout on decrypt */ + } else if (force_flag && makerandom == 0 && legal_ctb(ctb)) { + nestflag = TRUE; + } + + if (moreflag && makerandom == 0) { + /* special name to cause printout on decrypt */ strcpy(literal_file_name, CONSOLE_FILENAME); literal_mode = MODE_TEXT; /* will check for text file later */ } else { - strcpy(literal_file_name, inputfile); + strcpy(literal_file_name, file_tail(inputfile)); #ifdef MSDOS strlwr(literal_file_name); #endif @@ -872,22 +907,28 @@ File will be treated as binary data.\n") workfile); literal_mode = MODE_BINARY; /* now expect straight binary */ } - if (moreflag && literal_mode == MODE_BINARY) { /* For eyes only? - Can't display - binary file. */ + if (moreflag && literal_mode == MODE_BINARY) { + /* For eyes only? Can't display binary file. */ fprintf(pgpout, LANG("\n\007Error: Only text files may be sent as display-only.\n")); errorLvl = INVALID_FILE_ERROR; user_error(); } - /* See if plainfile looks like it might be incompressible, - by examining its contents for compression headers for - commonly-used compressed file formats like PKZIP, etc. - Remember this information for later, when we are deciding - whether to attempt compression before encryption. - */ - attempt_compression = compress_enabled && file_compressible(plainfile); + /* + * See if plainfile looks like it might be incompressible, + * by examining its contents for compression headers for + * commonly-used compressed file formats like PKZIP, etc. + * Remember this information for later, when we are deciding + * whether to attempt compression before encryption. + * + * Naturally, don't bother if we are making a separate signature or + * clear-signed message. Also, don't bother trying to compress a + * PGP message, as it's probably already compressed. + */ + attempt_compression = compress_enabled && !separate_signature && + !nestflag && !clearfile && makerandom == 0 && + file_compressible(plainfile); if (sign_flag) { if (!filter_mode && !quietmode) @@ -916,7 +957,8 @@ added key on your secret keyring.\n")); rmtemp(workfile); workfile = tempf; } - if ((emit_radix_64 || encrypt_flag) && !separate_signature) + if (attempt_compression || encrypt_flag || emit_radix_64 || + output_stdout) tempf = tempfile(TMP_WIPE | TMP_TMPDIR); else tempf = tempfile(TMP_WIPE); @@ -931,28 +973,25 @@ added key on your secret keyring.\n")); errorLvl = SIGNATURE_ERROR; user_error(); } - /* - * We used to compress signed files only if they were also - * armored. Now that we have clear signatures it makes more - * sense to always compress signature files. - */ - if (attempt_compression && !separate_signature && !encrypt_flag - && !clearfile) { - tempf = tempfile(TMP_WIPE | TMP_TMPDIR); - squish_file(workfile, tempf); - rmtemp(workfile); - workfile = tempf; - } } else if (!nestflag) { /* !sign_file */ /* Prepend CTB_LITERAL byte to plaintext file. --sure wish this pass could be optimized away. */ - tempf = tempfile(TMP_WIPE); + if (attempt_compression || encrypt_flag || emit_radix_64 || + output_stdout) + tempf = tempfile(TMP_WIPE | TMP_TMPDIR); + else + tempf = tempfile(TMP_WIPE); + /* for clear signatures we create a separate signature */ status = make_literal(workfile, tempf, literal_mode, literal_file); rmtemp(workfile); workfile = tempf; } + if (encrypt_flag) { - tempf = tempfile(TMP_WIPE); + if (emit_radix_64 || output_stdout) + tempf = tempfile(TMP_WIPE | TMP_TMPDIR); + else + tempf = tempfile(TMP_WIPE); if (!conventional_flag) { if (!filter_mode && !quietmode) fprintf(pgpout, @@ -964,8 +1003,8 @@ LANG("\n\nRecipients' public key(s) will LANG("\nA user ID is required to select the recipient's public key. ")); fprintf(pgpout, LANG("\nEnter the recipient's user ID: ")); getstring(mcguffin, 255, TRUE); /* echo keyboard */ - if ((mcguffins = (char **) malloc(2 * sizeof(char *))) - == NULL) { + if ((mcguffins = (char **) malloc(2 * sizeof(char *))) == NULL) + { fprintf(stderr, LANG("\n\007Out of memory.\n")); exitPGP(7); } @@ -992,13 +1031,28 @@ LANG("\nA user ID is required to select fprintf(pgpout, LANG("\007Encryption error\n")); errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR); user_error(); - } - } /* encrypt file */ - if (outputfile) /* explicit output file overrides - filter mode */ - filter_mode = (strcmp(outputfile, "-") == 0); + } + } else if (attempt_compression && !separate_signature && !clearfile) { + /* + * PGP used to be parsimonious about compressin; originally, it only + * did it for files that were being encrypted (to reduce the + * redundancy in the plaintext), but it should really do it for + * anything where it's not a bad idea. + */ + if (emit_radix_64 || output_stdout) + tempf = tempfile(TMP_WIPE | TMP_TMPDIR); + else + tempf = tempfile(TMP_WIPE); + squish_file(workfile, tempf); + rmtemp(workfile); + workfile = tempf; + } - if (filter_mode) { + /* + * Write to stdout if explicitly asked to, or in filter mode and + * no explicit file name was given. + */ + if (output_stdout) { if (emit_radix_64) { /* NULL for outputfile means write to stdout */ if (armor_file(workfile, NULL, inputfile, clearfile) != 0) { @@ -1335,6 +1389,7 @@ LANG("\nFile has signature. Public key /* swap file names instead of just copying the file */ outfile = cipherfile; cipherfile = NULL; + nested_info = FALSE; /* No error */ break; /* no further processing */ } /* Key ring. View it. */ @@ -1551,30 +1606,48 @@ static int do_keyopt(char keychar) /*-------------------------------------------------------*/ case 'g': - { /* Key generation - Arguments: bitcount, bitcount - */ - char keybits[6], ebits[6]; + { /* Key generation + Arguments: bitcount, bitcount + */ + char keybits[6], ebits[6], *username = NULL; /* * Why all this code? - * - * Some dimwits have been distributing versions of - * PGP (especially on MS-DOS) without the manuals. - * This frustrates users (who call Philip Zimmermann - * at all hours of the day and night), and in - * addition to depriving them of instructions on how - * to operate the program, also deprives them of - * IMPORTANT legal notices. This is a Bad Thing, so - * we've gone to the trouble of being fascist and - * *forcing* the manuals to be there. The +nomanual - * flag (documented only in the manual) lets you - * overrride this if desired. + * + * Some people may object to PGP insisting on finding the + * manual somewhere in the neighborhood to generate a key. + * They bristle against this seemingly authoritarian + * attitude. Some people have even modified PGP to defeat + * this feature, and redistributed their hotwired version to + * others. That creates problems for me (PRZ). + * + * Here is the problem. Before I added this feature, there + * were maimed versions of the PGP distribution package + * floating around that lacked the manual. One of them was + * uploaded to Compuserve, and was distributed to countless + * users who called me on the phone to ask me why such a + * complicated program had no manual. It spread out to BBS + * systems around the country. And a freeware distributor got + * hold of the package from Compuserve and enshrined it on + * CD-ROM, distributing thousands of copies without the + * manual. What a mess. + * + * Please don't make my life harder by modifying PGP to + * disable this feature so that others may redistribute PGP + * without the manual. If you run PGP on a palmtop with no + * memory for the manual, is it too much to ask that you type + * one little extra word on the command line to do a key + * generation, a command that is seldom used by people who + * already know how to use PGP? If you can't stand even this + * trivial inconvenience, can you suggest a better method of + * reducing PGP's distribution without the manual? + * + * PLEASE DO NOT DISABLE THIS CHECK IN THE SOURCE CODE + * WITHOUT AT LEAST CALLING PHILIP ZIMMERMANN + * (+1 303 541-0140, or prz@acm.org) TO DISCUSS IT. */ - if (!nomanual && manuals_missing()) { char const *const *dir; - fputs(LANG("\a\nError: PGP User's Guide not found.\n\ PGP looked for it in the following directories:\n"), pgpout); for (dir = manual_dirs; *dir; dir++) @@ -1590,6 +1663,8 @@ got it from that this is an incomplete p distributed further.\n\ \n\ PGP will not generate a key without finding the User's Guide.\n\ +There is a simple way to override this restriction. See the\n\ +PGP User's Guide for details on how to do it.\n\ \n"), pgpout); return KEYGEN_ERROR; } @@ -1603,8 +1678,12 @@ PGP will not generate a key without find else ebits[0] = '\0'; + /* If the -u option is given, use that username */ + if (u_flag && my_name != NULL && *my_name != '\0') + username = my_name; + /* dokeygen writes the keys out to the key rings... */ - status = dokeygen(keybits, ebits); + status = dokeygen(keybits, ebits, username); if (status < 0) { fprintf(pgpout, LANG("\007Keygen error. ")); @@ -2084,6 +2163,9 @@ void exitPGP(int returnval) for (hpw = keypasswds; hpw; hpw = hpw->next) memset(hpw->hash, 0, sizeof(hpw->hash)); cleanup_tmpf(); + /* Merge any entropy we collected into the randseed.bin file */ + if (cryptRandOpen((struct IdeaCfbContext *)0) >= 0) + cryptRandSave((struct IdeaCfbContext *)0); #if defined(DEBUG) && defined(linux) if (verbose) { struct mstats mstat;