diff -urpN john-1.7.8-jumbo-5a/src/Makefile john-1.7.8-jumbo-5b/src/Makefile
--- john-1.7.8-jumbo-5a/src/Makefile	2011-08-11 21:26:11.656250000 +0000
+++ john-1.7.8-jumbo-5b/src/Makefile	2011-08-17 18:33:12.250000000 +0000
@@ -34,7 +34,7 @@ OMPFLAGS =
 CFLAGS = -c -Wall -O2 -fomit-frame-pointer -I/usr/local/include $(OMPFLAGS)
 # -DHAVE_SKEY
 ASFLAGS = -c $(OMPFLAGS)
-LDFLAGS = -s -L/usr/local/lib -L/usr/local/ssl/lib -lcrypto -lssl -lm $(OMPFLAGS)
+LDFLAGS = -s -L/usr/local/lib -L/usr/local/ssl/lib -lcrypto -lssl -lm -lz $(OMPFLAGS)
 # -lskey
 LDFLAGS_SOLARIS = -lrt -lnsl -lsocket
 LDFLAGS_MKV = -s -lm
diff -urpN john-1.7.8-jumbo-5a/src/pkzip.h john-1.7.8-jumbo-5b/src/pkzip.h
--- john-1.7.8-jumbo-5a/src/pkzip.h	1970-01-01 00:00:00.000000000 +0000
+++ john-1.7.8-jumbo-5b/src/pkzip.h	2011-08-18 20:52:35.781250000 +0000
@@ -0,0 +1,82 @@
+#ifndef PKZIP_H
+#define PKZIP_H
+
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef          char c8;
+typedef ARCH_WORD_32 u32;
+
+/* crc32 0xdebb20e3 table and supplementary functions.  */
+
+static const u32 pkz_crc_32_tab[] =
+{
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL,
+	0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL,
+	0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL,
+	0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL,
+	0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+	0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL,
+	0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL,
+	0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL,
+	0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL,
+	0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+	0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL,
+	0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL,
+	0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL,
+	0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL,
+	0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+	0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL,
+	0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL,
+	0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL,
+	0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL,
+	0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+	0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL,
+	0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL,
+	0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL,
+	0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL,
+	0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+	0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL,
+	0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL,
+	0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL,
+	0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL,
+	0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+	0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL,
+	0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL
+};
+
+#define pkzip_crc32(crc,byte) (pkz_crc_32_tab[(u8)((crc)^(byte))] ^ ((crc) >> 8))
+
+#define UBUF_SIZE (32*1024)
+#define MAX_PKZ_FILES 8
+typedef struct zip_salt_t {
+	unsigned cnt;			// number of hashes
+	u8 h[MAX_PKZ_FILES][12];	// hash data (up to 8)
+	u8 c[MAX_PKZ_FILES][2];	// the 1 or 2 byte checksums (that match the 1 to 8 hashes)
+	u8 *asciidat;
+	u8 *ascii_decr;
+	unsigned asciilen;
+	u8 *ascii_ucmp;
+	unsigned ascii_ucmp_len;
+
+	u8 *encrDat;			// Encrypted data from the zip file. May be partial, or may be 'full'.  If an ASCII file, then partial will work.
+//	u8 *decrDat;			// 
+//	u8 *uncomprDat;			// 
+
+	u32 crc32;				// if a 'full' file of encr data, then this is the CRC
+	unsigned compLen;		// length of compressed data (whether part or full)
+	unsigned deCompLen;		// length of decompressed data (if full).
+	unsigned flags;			// 
+	unsigned offset;
+	char *filename;
+	char *ifilename;
+	u8 *full_encr_dat;
+	u8 *full_decr_dat;
+	unsigned chk_bytes;		// number of bytes valid in checksum (1 or 2)
+} PKZ_SALT;
+
+typedef union MY_WORD {
+	u32 u;
+	u8  c[4];
+} MY_WORD;
+
+#endif
diff -urpN john-1.7.8-jumbo-5a/src/pkzip_fmt_plug.c john-1.7.8-jumbo-5b/src/pkzip_fmt_plug.c
--- john-1.7.8-jumbo-5a/src/pkzip_fmt_plug.c	1970-01-01 00:00:00.000000000 +0000
+++ john-1.7.8-jumbo-5b/src/pkzip_fmt_plug.c	2011-08-18 22:01:12.171875000 +0000
@@ -0,0 +1,730 @@
+/* PKZIP patch for john to handle 'old' pkzip passwords (old 'native' format)
+ *
+ * Written by Jim Fougeron <jfoug at cox.net> in 2011.  No copyright
+ * is claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2011 Jim Fougeron and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ */
+
+#include <string.h>
+
+#include "common.h"
+#include "arch.h"
+#include "misc.h"
+#include "formats.h"
+#include "pkzip.h"
+
+#include "zlib.h"
+
+#define FORMAT_LABEL			"pkzip"
+#define FORMAT_NAME				"pkzip"
+#define ALGORITHM_NAME			"N/A"
+
+#define BENCHMARK_COMMENT		""
+#define BENCHMARK_LENGTH		-1
+
+#define PLAINTEXT_LENGTH		40
+
+#define BINARY_SIZE				(MAX_PKZ_FILES*2)
+#define SALT_SIZE				(sizeof(PKZ_SALT*))
+
+#define MIN_KEYS_PER_CRYPT		1
+#define MAX_KEYS_PER_CRYPT		64
+
+//#define ZIP_DEBUG
+
+// format:  
+//   $pkzip$
+//   Number of test records*
+//   bytes_of_checksum_valid*	Either 1 or 2 byte validation.  PKZIP > 2 will only use 1.
+//                              Older stuff (and many unixes), validate against both bytes.
+//                              These both byte validations cuts down a lot on items needing
+//                              to be validated.
+//
+//   Flags (which fields are present, after the checksum hashes).
+//     1 chksum_tst_only  (only does a checksum test, not the decompress test)
+//     2 ASCII.     Field ascii length, and ascii 'hash' will be filled in.
+//     4 CRC_LEN    Fields CRC32, comp_len and decomp_len filled in.
+//     8 FileName   Fields Offset and FileName are filled in
+//     16 FileData  The .zip compressed/encrypted data will be provided.
+//
+//    12_byte_hash_plus_2_byte_chksum_inhex*    This is the 12 byte hash of the file,
+//                                              and the 2 bytes of crc.
+//    [12_byte_hash2*[hash3*[hash4*[hash5*]]]]  (up to 5 files from a zip file can be here.
+//                                              More files means a 'correct' checksum is
+//                                              likely to be the right one.
+//    ASCII hash len*   if flags&2
+//    ASCII hash data*  if flags&2
+//    CRC32*            if flags&4
+//    Compr_len*        if flags&4
+//    deCompr_len*      if flags&4
+//    Offset*           Only if flags&8  this is the offset from start of file to the 
+//                                       compressed/encrypted deflated 'blob' of data.
+//    FileName*         if flags&8       the name of the .zip file.  NOTE, that file WILL be
+//                                       required.  Filename cant contain a '*' charcter.
+//    InternalFName*    if flags*8       This is the name of the file.  Used if we implement
+//                                       a spawn to unzip -P to test passwords.
+//    FileData*         if flags&16      This IS the .zip data (the compressed/encrypted blob.
+//                                       If the file is small (or a small one 'exists' in the
+//                                       .zip, then the data can be put here inline.
+
+static struct fmt_tests tests[] = {
+	{"$pkzip$1*2*1*c97839b8fe9e0373ba3c7b29ac6f**********", "love"},
+	{"$pkzip$1*1*1*4f83334e87f67a42fce2a53ef967**********", "john"},
+	{"$pkzip$1*1*1*fcf7385e0c4466cd621743a7f967**********", "john"},
+	{"$pkzip$4*2*1*dce4fb16f19b70cf9c368a5c139b*e27bc3e3adb1cc0f227758f38b8d*20f4ad0590ec2b44ff8510266aec*f63277b2a5ea02bcaed067ee71a6**********", "john"},
+	{"$pkzip$1*2*1*20f4ad0590ec2b44ff8510266aec**********", "john"},
+	{"$pkzip$1*2*16*20f4ad0590ec2b44ff8510266aec*38*20f4ad0590ec2b44ff85102650314ec911cc2227bdb0e5ced23ea8517ce4bdc5ec77136e450641fcfe317fd36e069de280f6623e34085186*f967d462*54*49****20F4AD0590EC2B44FF85102650314EC911CC2227BDB0E5CED23EA8517CE4BDC5EC77136E450641FCFE317FD36E069DE280F6623E34085186F3A4FEE45EB6D4C6AABF9B7A5A142D456CF542C1EB35BCAAE120330D*", "john"},
+	{"$pkzip$1*2*2*20f4ad0590ec2b44ff8510266aec*38*20f4ad0590ec2b44ff85102650314ec911cc2227bdb0e5ced23ea8517ce4bdc5ec77136e450641fcfe317fd36e069de280f6623e34085186********", "john"},
+	{"$pkzip$5*1*14*556f978a58fa4d1bbd18c6ad7cf3*15d082fd66f783745e02a9a4e138*515d1afdf3036ceddd74f6c2e6a0*117e84fce498fc1aa4ba251efed7*55f7bd45d53f0345aac7a408ac\
+0f***fed7246b*4c6*e00****117e84fce498fc1aa4ba251e5eae6d70747ce420626b1306568499b7600bc9758b0cb03b3eec5343b745b24a41f26b95794af638ff195878692a7bb012d6457bc36b6b48a4f01e99b5c7febaeee\
+a045abd0286f8fe676bbf28c6232555b71f242794cb3bf9df89eab681e8436c7fdc561c951d2ffbf6e3ac5302cbad5706c5f59f8f1806e76b465f1f4280e829db18c0ddc3b181b6fa992076b6f1641539b5f45142004db41d5ed\
+158338f663822612bd8ad18676dc7d40148bb006e4d4033f9dfe80526862286afb908d2f46b895cdc11e15fd2712932ba491a82aeadc231612c6cbc304858d80a46378f72dcda91ea70adfeda96c0fbdd17a954dd4f88fb6c44b\
+d362e0302fe209ac1b9a06a1b7f35dc6208b58d5315058322c85117184e279f4aaec3870a8f05dc2aff0e8bc8613adbc30a95f77f9594132027f44217164c193ab2568a7c175bc41bb6ba96e847746e40d179cc41da890049d35\
+7488645ff4ec952254f47c5d48edb59e1f46a406ae7c2002c88706168dcd24dd4829e9ea454e67ebe2633d162f0d50c41a3a78e6582ce132cf580dc507be23b4e58c9ef2f45d61b909ba68dc1b765e97699207d76e4f488b45be\
+a674feaa56f05bfbb9e103aef0790df9d57097803842aa9c975d4ddaaf68c770a54f815e64b518972feba8381f7d4ab36a3fef1098d75bad8d8bb87f2316e8f20e18e26955120b5c563b6017dd3d7e9ad00e38f60a00f516455f\
+70b9ce84cb46104de15130ecdb28d836197b35b0c2ac87f60ee5eda4dd1a0873ca9932027b1cccada6a00f2d3de6f682f0b74e8baccd40ffc3fc9765a6dd3f4f06e3ad33bb4f82f200d65040fa13ed4abc0204e97fc84bc819bb\
+95e20c8d58bff5b269c26a99094fa3333f857b36bfa1de58d99fcaee4f0261272d780d7416eae9606984599c65b29e5e83cfedbf5b6a3fc6047294770fded9f64dfbe05a933840a2a27aa7c5b13b6a5de598de67f7c8d531ccbd\
+9089c2aa081d95166f88650acf3804097ef5b65d3883397cdea39b33f5e490ed4677884c15270dce76970be24d8efcbdd7880dd9ef849aabfb5359cdcdbcd68dbe985b53caed3442ef0e2fe584bab26c84f5f3e26a6d15d6ceba\
+e5610c81da50ced1bd4d24e4761a9a33a48dd818af569ed9370d1a68436a1e285c454830af0a34402d810cf95044c24cc0b6f8602afc97229662a2ecc7791d4b9adbe763f4e873d98a8c71f7d378aa07e55d922500857c633885\
+501ef3444c1a169d07f16c72896f299472d21d09258ee8a82b2b8bb224557ca8f2fc0dcb5dd2a7548cc65937d8c160dc6e26dd0cbbc011c6bf85f60d944364052e1e7369eaa2c32f7203e8efc4b4bb4744d6d8f5272335377222\
+9f51dba75b8f695f824f0d23c69e257200d61091a55213b23dc3902960f27b66995a06c7796f87d9abe4aa1a94f7907d97d20f2591d8f370940d7419d732fdb13a93989467e5773c9ae3320c8ae9cfe0ce3b482bffd35be7df11\
+e3a33789cd383c4b56fa26aab823228e163c0981e73426dd3f5d0e2c887de924e7abdfe5818f98fde9afb359fe13925161cb017c0ac5be55a7294958e8792a0172bcdeb2605402ccf1299011e86861e85204b8c46afceea53502\
+d0cf4f6b2c23618eb41064842441345b3792abd1a258da71e54b3bddc542b566137e718d59ed219c6331d2846ed6fdeafe1d6f572fd87f28c1cd45f3d7122e0ae*", "password"},
+	{NULL}
+};
+
+static char saved_key[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int saved_key_len[MAX_KEYS_PER_CRYPT];
+//static const PKZ_SALT *salt;
+static PKZ_SALT *salt;
+static int cur_chk_bytes=2;
+static u8 mult_tab[16384];
+static u8 chk[MAX_PKZ_FILES][2];
+static u8 ucpr_buf[UBUF_SIZE];
+
+extern struct fmt_main fmt_pkzip;
+
+static int binary_hash1_0(void *binary);
+static int binary_hash1_1(void *binary);
+static int get_hash1_0(int index);
+static int get_hash1_1(int index);
+static int binary_hash2_0(void *binary);
+static int binary_hash2_1(void *binary);
+static int binary_hash2_2(void *binary);
+static int binary_hash2_3(void *binary);
+static int get_hash2_0(int index);
+static int get_hash2_1(int index);
+static int get_hash2_2(int index);
+static int get_hash2_3(int index);
+
+
+static u8 *GetFld(u8 *p, u8 **pRet) {
+	if (!p || *p==0) {
+		*pRet = (u8*)"";
+		return p;
+	}
+	if (p && *p && *p == '*') {
+		*pRet = (u8*)"";
+		return ++p;
+	}
+	*pRet = p;
+	while (*p && *p != '*') 
+		++p;
+	if (*p)
+	  *p++ = 0;
+	return p;
+}
+
+static int is_hex_str(const u8 *cp) {
+	int len, i;
+
+	if (!cp) return 1; // empty is 'fine'
+	len = strlen((c8*)cp);
+	for (i = 0; i < len; ++i) {
+		if (atoi16[ARCH_INDEX(cp[i])] == 0x7F)
+			return 0;
+	}
+	return 1;
+}
+
+static int valid(char *ciphertext, struct fmt_main *pFmt)
+{
+	u8 *p, *cp;
+	int len, cnt;
+	u32 flags;
+	FILE *in;
+
+	if (strncmp(ciphertext, "$pkzip$", 7))
+		return 0;
+
+	cp = (u8*)str_alloc_copy(ciphertext);
+
+	p = &cp[7];
+	p = GetFld(p, &cp);
+	if (!p || *p==0 || *cp < '1' || *cp > ('0'+MAX_PKZ_FILES)) return 0;
+	sscanf((c8*)cp, "%x", &cnt);
+	p = GetFld(p, &cp);
+	if (!p || *p==0 || *cp < '1' || *cp > '2') return 0;
+	p = GetFld(p, &cp);
+	if (!p || *p==0 || !is_hex_str(cp)) return 0;
+	sscanf((c8*)cp, "%x", &flags);
+
+	while (cnt--) {
+		p = GetFld(p, &cp);
+		if ( (cnt && (!p || *p==0)) || strlen((c8*)cp) != 28 || !is_hex_str(cp)) return 0;
+	}
+
+	// Handle flags&2
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&2) && !strlen((c8*)cp)) || !is_hex_str(cp)) return 0;
+	sscanf((c8*)cp, "%x", &len);  // ASCII-mode blob length
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&2) && strlen((c8*)cp) != (len<<1)) || !is_hex_str(cp)) return 0;
+
+	// Handle flags&4
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&4) && !strlen((c8*)cp)) || !is_hex_str(cp)) return 0;
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&4) && !strlen((c8*)cp)) || !is_hex_str(cp)) return 0;
+	sscanf((c8*)cp, "%x", &len);  // compressed len
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&4) && !strlen((c8*)cp)) || !is_hex_str(cp)) return 0;
+
+	// Handle flags&8
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&8) && !strlen((c8*)cp)) || !is_hex_str(cp)) return 0;
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&8) && !strlen((c8*)cp))) return 0;
+	if (flags&8) {
+		in = fopen((c8*)cp, "r");
+		if (!in) {
+			fprintf(stderr, "Error loading a pkzip hash line. The file %s could NOT be found\n", cp);
+			return 0;
+		}
+		fclose(in);
+	}
+	p = GetFld(p, &cp);
+	if ( !p || *p==0 || ((flags&8) && !strlen((c8*)cp))) return 0;
+
+	// Handle flags&16
+	p = GetFld(p, &cp);
+	if ( !p || *p || ((flags&16) && strlen((c8*)cp) != (len<<1)) || !is_hex_str(cp)) return 0;
+
+	if ( (flags & (8|16)) && !(flags&4)) // if we have the 'full' file (or file name), and not the CRC and complen, then bail.
+		return 0;
+
+	return 1;
+}
+
+
+static void init(struct fmt_main *pFmt)
+{
+	// Precompute the multiply mangling, within 2 parts of the hash.
+	unsigned short n;
+	for (n = 0; n < 16384; n++)
+		mult_tab[n] = ((n*4+3) * (n*4+2) >> 8) & 0xff;
+}
+
+static void SetChkBytes() {
+	cur_chk_bytes = salt->chk_bytes;
+	switch(cur_chk_bytes) {
+		case 1:
+			fmt_pkzip.methods.binary_hash[0] = binary_hash1_0;
+			fmt_pkzip.methods.binary_hash[1] = binary_hash1_1;
+			fmt_pkzip.methods.get_hash[0] = get_hash1_0;
+			fmt_pkzip.methods.get_hash[1] = get_hash1_1;
+			break;
+		case 2:
+			fmt_pkzip.methods.binary_hash[0] = binary_hash2_0;
+			fmt_pkzip.methods.binary_hash[1] = binary_hash2_1;
+			fmt_pkzip.methods.binary_hash[2] = binary_hash2_2;
+			fmt_pkzip.methods.binary_hash[2] = binary_hash2_3;
+			fmt_pkzip.methods.get_hash[0] = get_hash2_0;
+			fmt_pkzip.methods.get_hash[1] = get_hash2_1;
+			fmt_pkzip.methods.get_hash[2] = get_hash2_2;
+			fmt_pkzip.methods.get_hash[2] = get_hash2_3;
+			break;
+	}
+}
+
+static void set_salt(void *_salt) {
+	salt = *((PKZ_SALT**)_salt);
+	if(cur_chk_bytes != salt->chk_bytes)
+		SetChkBytes();
+}
+
+static void load_bin_data(u8 *inp, u8 **out) {
+	int i, len = strlen((c8*)inp);
+	*out = mem_alloc_tiny(len>>1, MEM_ALIGN_NONE);
+	for (i = 0; i < len>>1; ++i)
+		(*out)[i] = (atoi16[ARCH_INDEX(inp[i<<1])]<<4) + atoi16[ARCH_INDEX(inp[(i<<1)+1])];
+}
+
+static void * get_salt(char *ciphertext)
+{
+	static unsigned char salt_p[8];
+	PKZ_SALT *salt;
+	int i, j;
+	u8 *p, *cp, *cpalloc = (unsigned char*)mem_alloc(strlen(ciphertext)+1);
+
+	salt = mem_alloc_tiny(sizeof(PKZ_SALT), MEM_ALIGN_NONE);
+	memcpy(salt_p, &salt, sizeof(salt));
+	memset(salt, 0, sizeof(PKZ_SALT));
+
+	cp = cpalloc;
+	strcpy((c8*)cp, ciphertext);
+
+	p = &cp[7];
+	p = GetFld(p, &cp);
+	sscanf((c8*)cp, "%x", &(salt->cnt));
+	p = GetFld(p, &cp);
+	sscanf((c8*)cp, "%x", &(salt->chk_bytes));
+	p = GetFld(p, &cp);
+	sscanf((c8*)cp, "%x", &(salt->flags));
+	for(i = 0; i < salt->cnt; ++i) {
+		p = GetFld(p, &cp);
+		salt->c[i][0] = (atoi16[ARCH_INDEX(cp[24])]<<4) + atoi16[ARCH_INDEX(cp[25])];
+		salt->c[i][1] = (atoi16[ARCH_INDEX(cp[26])]<<4) + atoi16[ARCH_INDEX(cp[27])];
+		for (j = 0; j < 12; ++j)
+			salt->h[i][j] = (atoi16[ARCH_INDEX(cp[j*2])]<<4) + atoi16[ARCH_INDEX(cp[j*2+1])];
+	}
+
+	// Handle flags&2
+	p = GetFld(p, &cp);
+	if (salt->flags&2)
+		sscanf((c8*)cp, "%x", &(salt->asciilen));  // ASCII-mode blob length
+	p = GetFld(p, &cp);
+	if (salt->flags&2)
+		load_bin_data(cp, &(salt->asciidat));
+
+	// Handle flags&4
+	p = GetFld(p, &cp);
+	if (salt->flags&4)
+		sscanf((c8*)cp, "%x", &(salt->crc32));  // compressed len
+	p = GetFld(p, &cp);
+	if (salt->flags&4)
+		sscanf((c8*)cp, "%x", &(salt->compLen));  // compressed len
+	p = GetFld(p, &cp);
+	if (salt->flags&4)
+		sscanf((c8*)cp, "%x", &(salt->deCompLen));  // compressed len
+
+	// Handle flags&8
+	p = GetFld(p, &cp);
+	if (salt->flags&8)
+		sscanf((c8*)cp, "%x", &(salt->offset));  // Offset to data blob in file.
+	p = GetFld(p, &cp);
+	if (salt->flags&8)
+		salt->filename = str_alloc_copy((c8*)cp);
+	p = GetFld(p, &cp);
+	if (salt->flags&8)
+		salt->ifilename = str_alloc_copy((c8*)cp);
+
+	// Handle flags&16
+	p = GetFld(p, &cp);
+	if (salt->flags&16) {
+		load_bin_data(cp, &(salt->full_encr_dat));
+		salt->full_decr_dat = mem_alloc_tiny(salt->compLen-12, MEM_ALIGN_NONE);
+	}
+
+	MEM_FREE(cpalloc);
+	return salt_p;
+}
+
+static void *get_binary(char *ciphertext)
+{
+	static unsigned char Buf[BINARY_SIZE];
+	int cnt;
+	unsigned char *op=Buf, *p, *cp, *cpalloc = (unsigned char*)mem_alloc(strlen(ciphertext)+1);
+
+	cp = cpalloc;
+	strcpy((c8*)cp, ciphertext);
+
+	p = &cp[7];
+	p = GetFld(p, &cp);
+	sscanf((c8*)cp, "%d", &cnt);
+	p = GetFld(p, &cp);
+	p = GetFld(p, &cp);
+	while (cnt--) {
+		p = GetFld(p, &cp);
+		*op++ = (atoi16[ARCH_INDEX(cp[24])]<<4) + atoi16[ARCH_INDEX(cp[25])];
+		*op++ = (atoi16[ARCH_INDEX(cp[26])]<<4) + atoi16[ARCH_INDEX(cp[27])];
+	}
+	MEM_FREE(cpalloc);
+	return Buf;
+}
+
+static int binary_hash1_0(void *binary) { return ((unsigned char*)binary)[0] & 0xf; }
+static int binary_hash1_1(void *binary) { return ((unsigned char*)binary)[0]; }
+
+static int get_hash1_0(int index) { return chk[index][0] & 0xF; }
+static int get_hash1_1(int index) { return chk[index][0]; }
+
+static int binary_hash2_0(void *binary) { return ((unsigned short*)binary)[0] & 0xf; }
+static int binary_hash2_1(void *binary) { return ((unsigned short*)binary)[0] & 0xff; }
+static int binary_hash2_2(void *binary) { return ((unsigned short*)binary)[0] & 0xfff; }
+static int binary_hash2_3(void *binary) { return ((unsigned short*)binary)[0] & 0xffff; }
+
+static int get_hash2_0(int index) { return *((unsigned short*)&(chk[index])) & 0xf; }
+static int get_hash2_1(int index) { return *((unsigned short*)&(chk[index])) & 0xff; }
+static int get_hash2_2(int index) { return *((unsigned short*)&(chk[index])) & 0xfff; }
+static int get_hash2_3(int index) { return *((unsigned short*)&(chk[index])) & 0xffff; }
+
+static void set_key(char *key, int index)
+{
+	saved_key_len[index] = strlen(key);
+	if (saved_key_len[index] > PLAINTEXT_LENGTH) {
+		saved_key_len[index] = PLAINTEXT_LENGTH;
+		memcpy(saved_key[index], key, PLAINTEXT_LENGTH);
+		saved_key[index][PLAINTEXT_LENGTH] = 0;
+	}
+	else
+		memcpy(saved_key[index], key, saved_key_len[index]+1);
+}
+
+static char *get_key(int index)
+{
+	return saved_key[index];
+}
+
+static void crypt_all(int _count)
+{
+	int idx;
+	char *pw_end, *pw;
+	for (idx = 0; idx < _count; ++idx) {
+		int count = salt->cnt;
+		int count2 = 0, len;
+		int salt_idx = -1;
+		MY_WORD key0, key1, key2;
+		u8 *p;
+
+		pw = saved_key[idx];
+		len = saved_key_len[idx];
+		pw_end = pw + len;
+
+		p = (u8 *)pw_end - len;
+
+		key0.u = 0x12345678UL;
+		key1.u = 0x23456789UL;
+		key2.u = 0x34567890UL;
+		do {
+			key0.u = pkzip_crc32 (key0.u, *p++);
+			key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
+			key2.u = pkzip_crc32 (key2.u, key1.c[3]);
+		} while (*p);
+		do
+		{
+			u8 target, pre_target;
+
+			//#if !USE_MULT_TAB
+			//u16 t;
+			//#endif
+			MY_WORD kez0, kez1, kez2;
+			const u8 *b = salt->h[++salt_idx], *be = &b[11];
+			const u8 *e = salt->c[salt_idx];
+
+			kez0.u = key0.u, kez1.u = key1.u, kez2.u = key2.u;
+			do
+			{
+				//#if USE_MULT_TAB
+
+				pre_target = *b++ ^ mult_tab [(kez2.u&0xFFFF) >> 2];		// 6550k/s GCC speed.   6995k/s (VC speed)
+				//pre_target = *b++ ^ mult_tab [(u16)(kez2.u) >> 2];		// 6360k/s              7029k/s
+				//pre_target = *b++ ^ mult_tab [(kez2.u>>2)&0x3FFF];		// 6440k/s              7052k/s
+
+				//#else
+				//     t = kez2.u | 2;
+				//     pre_target = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));
+				//#endif
+				kez0.u = pkzip_crc32 (kez0.u, pre_target);
+				kez1.u = (kez1.u + kez0.c[0]) * 134775813 + 1;
+				kez2.u = pkzip_crc32 (kez2.u, kez1.c[3]);
+			}
+			while (b < be);
+
+			//#if USE_MULT_TAB
+
+			target = *b++ ^ mult_tab [(kez2.u&0xFFFF) >> 2];
+			//target = *b++ ^ mult_tab [(u16)(kez2.u) >> 2];
+			//target = *b++ ^ mult_tab [(kez2.u>>2)&0x3FFF];
+
+
+			//#else
+			//     t = kez2.u | 2;
+			//     target = *b++ ^ (u8)(((u16) (t * (t^1)) >> 8));
+			//#endif
+
+			if (target != e[0])
+				goto out;
+
+			if (pre_target == e[1])
+				count2++;
+			else if (salt->chk_bytes == 2)
+				goto out;
+		}
+		while(--count);
+
+		// We got a HIT!!!!
+		chk[idx][0] = salt->c[0][0];
+		chk[idx][1] = salt->c[0][1];
+		continue;
+		
+		out: ;
+		chk[idx][0] = ~(salt->c[0][0]);
+		chk[idx][1] = ~(salt->c[0][1]);
+	}
+}
+
+static int cmp_one(void *binary, int idx)
+{
+	u8 *b = (u8*)binary;
+	if (b[0] == chk[idx][0]) {
+		if (salt->compLen == 1)
+			return 1;
+		else if (b[1] == chk[idx][1])
+			return 1;
+	}
+	return 0;
+}
+
+static int cmp_all(void *binary, int count)
+{
+	int i;
+	for (i = 0; i < count; ++i) {
+		if (cmp_one(binary, i))
+			return 1;
+	}
+	return 0;
+}
+
+static void decrypt (int idx, u8 *inp, u8 *out, int inplen) {
+	char *pw_end, *pw;
+	MY_WORD key0, key1, key2;
+	u8 *p, C;
+	const u8 *b = inp, *be = &b[12];
+
+	pw = saved_key[idx];
+	pw_end = pw + saved_key_len[idx];
+
+	p = (u8 *)pw_end - saved_key_len[idx];
+
+	key0.u = 0x12345678UL; 	key1.u = 0x23456789UL; 	key2.u = 0x34567890UL;
+	do {
+		key0.u = pkzip_crc32 (key0.u, *p++);
+		key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
+		key2.u = pkzip_crc32 (key2.u, key1.c[3]);
+	} while (*p);
+
+	// Load the IV into the keys.
+	do {
+		C = *b++ ^ mult_tab [(key2.u & 0xFFFF) >> 2];
+		key0.u = pkzip_crc32 (key0.u, C);
+		key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
+		key2.u = pkzip_crc32 (key2.u, key1.c[3]);
+	} while (b < be);
+
+	be = &(inp[inplen]);
+	do {
+		C = *b++ ^ mult_tab [(key2.u & 0xFFFF) >> 2];
+		*out++ = C;
+		key0.u = pkzip_crc32 (key0.u, C);
+		key1.u = (key1.u + key0.c[0]) * 134775813 + 1;
+		key2.u = pkzip_crc32 (key2.u, key1.c[3]);
+	} while (b < be);
+}
+
+static int decomp_validate(u8 *inp, int inplen, int outlen, u32 crcExpect) {
+	// Ok, here we have to do a FULL decrypt, make sure the data is the proper length, and make sure the
+	// CRC32 matches.  If all of that, then we have a 100% hit on the password.  Otherwise, a false positive.
+	z_stream strm;
+	int ret, i;
+	u32 crc = 0xFFFFFFFF;
+	int last_out, bytes_this_time;
+
+	strm.zalloc = Z_NULL;
+	strm.zfree = Z_NULL;
+	strm.opaque = Z_NULL;
+	strm.avail_in = 0;
+	strm.next_in = Z_NULL;
+
+	ret = inflateInit2(&strm, -15); // 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data.
+	if (ret != Z_OK)
+	   perror("Error, initializing the libz inflateInit2() system\n");
+
+	strm.avail_in = inplen;
+	strm.next_in = inp;
+
+	do {
+		strm.avail_out = UBUF_SIZE;
+		strm.next_out = ucpr_buf;
+		last_out = strm.total_out;
+
+		ret = inflate(&strm, Z_SYNC_FLUSH);
+		if (ret != Z_OK) {
+			inflateEnd(&strm);
+			if (ret == Z_STREAM_END) {
+				// This is the MOST LIKELY successful spot.
+				if (strm.total_out != outlen)
+					return 0;
+				bytes_this_time = strm.total_out - last_out;
+				for (i = 0; i < bytes_this_time; ++i)
+					crc = pkzip_crc32(crc,ucpr_buf[i]);
+				if (~crc == crcExpect) {
+					// yea!  we found it.
+#ifdef ZIP_DEBUG
+					fprintf(stderr, "YEA, Found it!! (full zip validation)  Crc=%x Expected=%x\n", ~crc, crcExpect);
+#endif
+					return 1;
+				}
+			}
+			return 0;
+		}
+		bytes_this_time = strm.total_out - last_out;
+		for (i = 0; i < bytes_this_time; ++i)
+			crc = pkzip_crc32(crc,ucpr_buf[i]);
+		if (strm.total_out > outlen) {
+			inflateEnd(&strm);
+			return 0;
+		}
+	} while (bytes_this_time == UBUF_SIZE);
+
+	// this will likely only happen, if the output len mod UBUF_SIZE == 0, but it 'can' happen.
+	inflateEnd(&strm);
+	if (~crc != crcExpect || strm.total_out != outlen)
+		return 0;
+	// yea!  we found it.
+	return 1;
+}
+
+static int decomp_validate_ascii(u8 *inp, u8 *out, int inplen, int outlen) {
+
+	z_stream strm;
+	int ret, i;
+
+	strm.zalloc = Z_NULL;
+	strm.zfree = Z_NULL;
+	strm.opaque = Z_NULL;
+	strm.avail_in = 0;
+	strm.next_in = Z_NULL;
+	
+	ret = inflateInit2(&strm, -15); // 'raw', since we do not have gzip header, or gzip crc. .ZIP files are 'raw' implode data.
+	if (ret != Z_OK)
+	   perror("Error, initializing the libz inflateInit2() system\n");
+
+	strm.avail_in = inplen;
+	strm.next_in = inp;
+	strm.avail_out = salt->ascii_ucmp_len;
+	strm.next_out = salt->ascii_ucmp;
+
+	ret = inflate(&strm, Z_SYNC_FLUSH);
+
+	inflateEnd(&strm);
+
+	if (ret != Z_OK || strm.total_out < 16)
+		return 0;
+
+	for (i = 0; i < strm.total_out-6; ++i) {
+		char c = salt->ascii_ucmp[i];
+		if (c > 0x7F)
+			return 0;
+		if (c > ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0x1a)
+			continue;
+		return 0;
+	}
+	return 1;
+}
+
+static int cmp_exact(char *source, int index)
+{
+	if (salt->flags&1) // checksum only
+		return 1;
+
+	// Do we have ASCII data?
+	if (salt->flags&2) {
+		if (!salt->ascii_ucmp) {
+			salt->ascii_ucmp_len = salt->asciilen*5;
+			salt->ascii_ucmp = mem_alloc_tiny(salt->ascii_ucmp_len, MEM_ALIGN_NONE);
+			salt->ascii_decr = mem_alloc_tiny(salt->asciilen-12, MEM_ALIGN_NONE);
+		}
+		decrypt(index, salt->asciidat, salt->ascii_decr, salt->asciilen);
+		if (!decomp_validate_ascii(salt->ascii_decr, salt->ascii_ucmp, salt->asciilen-12, salt->ascii_ucmp_len))
+			return 0;
+	}
+	if (salt->flags&4) {
+		if (!salt->full_encr_dat && salt->filename) {
+			FILE *in = fopen(salt->filename, "rb");
+			salt->full_encr_dat = mem_alloc_tiny(salt->compLen, MEM_ALIGN_NONE);
+			fseek(in, salt->offset, SEEK_SET);
+			fread(salt->full_encr_dat, 1, salt->compLen, in);
+			fclose(in);
+		}
+		if (!salt->full_decr_dat)
+			salt->full_decr_dat = mem_alloc_tiny(salt->compLen-12, MEM_ALIGN_NONE);
+		decrypt(index, salt->full_encr_dat, salt->full_decr_dat, salt->compLen);
+		if (!decomp_validate(salt->full_decr_dat, salt->compLen-12, salt->deCompLen, salt->crc32)) {
+#ifdef ZIP_DEBUG
+			fprintf(stderr, "False positive:  Pw found is:  %s\n", saved_key[index]);
+#endif
+			return 0;
+		}
+		// we found the biatch
+		return 1;
+	}
+
+	return 1;
+}
+
+struct fmt_main fmt_pkzip = {
+	{
+		FORMAT_LABEL,
+		FORMAT_NAME,
+		ALGORITHM_NAME,
+		BENCHMARK_COMMENT,
+		BENCHMARK_LENGTH,
+		PLAINTEXT_LENGTH,
+		BINARY_SIZE,
+		SALT_SIZE,
+		MIN_KEYS_PER_CRYPT,
+		MAX_KEYS_PER_CRYPT,
+		FMT_CASE | FMT_8_BIT,
+		tests
+	}, {
+		init,
+		fmt_default_prepare,
+		valid,
+		fmt_default_split,
+		get_binary,
+		get_salt,
+		{
+			binary_hash2_0,
+			binary_hash2_1,
+			binary_hash2_2,
+			binary_hash2_3,
+			NULL
+		},
+		fmt_default_salt_hash,
+		set_salt,
+		set_key,
+		get_key,
+		fmt_default_clear_keys,
+		crypt_all,
+		{
+			get_hash2_0,
+			get_hash2_1,
+			get_hash2_2,
+			get_hash2_3,
+			NULL
+		},
+		cmp_all,
+		cmp_one,
+		cmp_exact
+	}
+};
diff -urpN john-1.7.8-jumbo-5a/src/zip2john.c john-1.7.8-jumbo-5b/src/zip2john.c
--- john-1.7.8-jumbo-5a/src/zip2john.c	2011-07-02 21:01:00.000000000 +0000
+++ john-1.7.8-jumbo-5b/src/zip2john.c	2011-08-18 20:39:21.765625000 +0000
@@ -5,6 +5,13 @@
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted.
  *
+ * Updated in Aug 2011 by Jim Fougeron.  Added PKZIP 'old' encryption.  The signature
+ * on the pkzip will be $pkzip$ and does not look like the AES version written by Dhiru
+ * Also fixed some porting issues, such as variables needing declared at top of blocks.
+ * Added a -a= switch for 'old' format.  That allows a user to give a hint that a specific
+ * file 'is' known to be ASCII.  This allows john to have a significant performance 
+ * improvement when there are no small files.
+ *
  * References:
  *
  * 1. http://www.winzip.com/aes_info.htm
@@ -15,6 +22,8 @@
  * 7. http://www.pkware.com/documents/casestudies/APPNOTE.TXT
  * 8. http://gladman.plushost.co.uk/oldsite/cryptography_technology/fileencrypt/index.php
  *   (borrowed files have "gladman_" prepended to them)
+ * 9. http://svn.assembla.com/svn/os2utils/unzip60f/proginfo/extrafld.txt
+ * 10. http://emerge.hg.sourceforge.net/hgweb/emerge/emerge/diff/c2f208617d32/Source/unzip/proginfo/extrafld.txt
  *
  * Usage:
  *
@@ -27,18 +36,71 @@
  * For type = 0, for ZIP files encrypted using AES
  * filename:$zip$*type*hex(CRC)*encryption_strength*hex(salt)*hex(password_verfication_value):hex(authentication_code)
  *
- * For type = 1, for ZIP files encrypted using old encryption (TODO)
- * filename:$zip$*type*...  */
+ * For pkzip type:  (JimF, with longer explaination of fields)
+ * filename:$pkzip$C*B*F*H*[H*[H*...]]*AL*AD*crc*cmplen*decomplen*offset*filename*intfilename*filedata*
+ *
+ * All numeric and 'binary data' fields are stored in hex.  
+ *
+ * C  is the count of hashes present (the H's.).
+ * B  is number of valid bytes in the checksum (1 or 2).  Unix zip is 2 bytes, all others are 1
+ * F  is a set of flags. The bits of the flag list which fields following the array of H's should have data.
+ * H  is a 'hash'. This is the first 12 bytes of the encrypted imploded data blob (the IV), and also the 2 bytes of checksum, 
+ *    either from the CRC32 of the file, or the Dos timestamp. There can be up to 8 of these (if there are 8 encrypted files
+ *    in the .zip file, and this 'assumes' that all files have the same password.
+ * AL is the 'length' of the ASCII compressed file blob.  This assumes that there is a 'known to be' total ASCII text file
+ *    encrypted in the zip.  Only a tiny part of the start of the file is decrypted and decompressed. Then if that decompressed
+ *    data is 'all' ASCII items, then that is a better validation than a checksum match.
+ * AD This is the compressed ASCII data.  It is the first 12 bytes (the IV), of the imploded data of the ASCII file, and some
+ *    more.  80-90 bytes is more than adequate.  This number may be reduced, if it speeds things up in the end.
+ * CRC32       This is the crc of the 'whole' file we have to test
+ * Compr_len   This is the length of compressed data (the test-3 full test data).
+ * deComp_len  The length of the decompressed data (full file test data).
+ * Offset      This is the offset of this data within the .zip file. If the file is too large, then it can not be placed into
+ *             the john input line.  If that is the case, the .zip file must be present (name listed next), and when john
+ *             runs, it will load the zip data.
+ * FileName    The name of the .zip file (can contain path's).
+ * IntFileName This is the name of the compressed/encrypted file within the .zip.  This is needed if we spawn out to unzip -P
+ *             to perform the test (this field may go away.
+ * FileData    We can provide the file data, if it is small enough.  NOTE the file should be a couple hundred bytes long at
+ *             least, to make it MUCH more unlikely that we could decrypt/explode/crc and have proper size and crc.  If the
+ *             file data is provided, then the Offset/FileName/IntFileName are not needed.
+ *
+ * NOTE the flags field lists which of the above fields are present in the hash.  NOTE, it is valid to have only the hashes
+ * (the 'H' data) present.  John will be able to crack based only upon that.  Within the format, many of the test vectors
+ * are Hash only.
+
+ * There are 3 'test' items in a file.  The more of these that are present, the less likely it is to have false positive
+ *   passwords.
+ * The first is the checksum hash. There can be up to 8 of these hashes.  The hashes may have 1 or 2 bytes that 'match'
+ *   in the checksum.  The 2 byte checksums provide much stronger 'pre' validation.  If there are enough of these
+ *   checksums, then this may be all the data needed.  This is the array of 'H' data.  Unix (info-zip) makes zips
+ *   which have 2 bytes valid in the checksum (and the checksum checks against the dos-timestamp). Winzip and pkzip 2.00+
+ *   both only have 1 byte of valid checksum data, and it is the LSB of the CRC field.
+ * The second (optional), is the first part of a 'text' file. If there is a file that is KNOWN to be pure ASCII
+ *   text, then we can grab the first small part of the encrypted/compressed data, decrypt it, decompress it, and 
+ *   see if all the data is ASCII (ignoring the last couple of bytes).  This is not perfect, but may be very fast,
+ *   compared to step 3 if all files are LARGE, and it eliminates almost ALL false positives that passed the 
+ *   checksum checks.   This is the AL and AD data, and is optional.
+ * The 3rd part, is an entire compressed data blob, it's length it's CRC32.  This is the real 'test'.  The file should
+ *   have a certain minimum size, say 100 bytes, decompressed.  john will either spawn unzip -P to test the .zip file
+ *   or will perform the full decryption of the data blob, the full explosion of the data blob, and if the length matches
+ *   what it is supposed to, and the CRC of the decompressed data blob matches, THEN we know we have the password found.
+ *
+ */
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
+#include "stdint.h"
 #include <limits.h>
 #include <errno.h>
 #include <string.h>
 #include <assert.h>
 #include "common.h"
 
+static int ascii_mode=0;
+static int checksum_only=0;
+static char *ascii_fname;
+
 /* helper functions for byte order conversions, header values are stored
  * in little-endian byte order */
 static uint32_t fget32(FILE * fp)
@@ -57,6 +119,14 @@ static uint16_t fget16(FILE * fp)
 	return v;
 }
 
+int convert_to_hex(char *O, unsigned char *H, int len) {
+	int i;
+	for (i = 0; i < len; ++i)
+		O += sprintf (O, "%02x", *H++);
+	return len<<1;
+}
+
+static void process_old_zip(const char *fname);
 static void process_file(const char *fname)
 {
 	unsigned char filename[1024];
@@ -93,17 +163,20 @@ static void process_file(const char *fna
 			filename[filename_length] = 0;
 
 			if (compression_method == 99) {	/* AES encryption */
-				fprintf(stderr,
-				    "%s->%s is using AES encryption, extrafield_length is %d\n",
-				    fname, filename, extrafield_length);
 				uint16_t efh_id = fget16(fp);
 				uint16_t efh_datasize = fget16(fp);
 				uint16_t efh_vendor_version = fget16(fp);
 				uint16_t efh_vendor_id = fget16(fp);
 				char efh_aes_strength = fgetc(fp);
-				uint16_t actual_compression_method =
-				    fget16(fp);
+				uint16_t actual_compression_method = fget16(fp);
+				unsigned char salt[16];
+				int n = 0;
+				uint16_t password_verification_value;
+				unsigned char *p;
 
+				fprintf(stderr,
+				    "%s->%s is using AES encryption, extrafield_length is %d\n",
+				    fname, filename, extrafield_length);
 				/* unused variables */
 				(void) efh_id;
 				(void) efh_datasize;
@@ -114,8 +187,6 @@ static void process_file(const char *fna
 
 				printf("%s:$zip$*0*%d*", fname,
 				    efh_aes_strength);
-				unsigned char salt[16];
-				int n = 0;
 				switch (efh_aes_strength) {
 				case 1:
 					n = 8;
@@ -137,10 +208,8 @@ static void process_file(const char *fna
 					    itoa16[ARCH_INDEX(salt[i] &
 						    0x0f)]);
 				}
-				uint16_t password_verification_value =
-				    fget16(fp);
-				unsigned char *p = (unsigned char *)
-				    &password_verification_value;
+				password_verification_value = fget16(fp);
+				p = (unsigned char *) &password_verification_value;
 				printf("*");
 				for (i = 0; i < 2; i++) {
 					printf("%c%c",
@@ -151,8 +220,9 @@ static void process_file(const char *fna
 				fseek(fp, 10, SEEK_CUR);
 
 			} else if (flags & 1) {	/* old encryption */
-				printf("%s is using old encryption!\n",
-				    filename);
+				fclose(fp);
+				process_old_zip(fname);
+				return;
 			} else {
 				printf("%s->%s is not encrypted!\n", fname,
 				    filename);
@@ -170,15 +240,223 @@ cleanup:
 	fclose(fp);
 }
 
+static void process_old_zip(const char *fname) {
+	/* instead of using anything from the process_file, we simply detected a encrypted old style
+	   password, close the file, and call this function.  This function handles the older pkzip
+	   password, while the process_file handles ONLY the AES from WinZip */
+
+	unsigned char filename[1024];
+	unsigned char H[12];
+	char building_hash[29*8+1];  // store up to 8 hashes. They are 12 bytes + 2 bytes (in hex), which is 28 bytes, and the '*' char (and +1 for the null byte).
+	char *pbuilding_hash=building_hash;
+	int count_of_hashes = 0;
+	FILE *fp;
+	char *FileData = "";
+	int unix_made=0, check_in_crc = 1, two_byte_check = 0;
+	unsigned Flag_bits = 1;
+	// todo.
+	unsigned AL=0;
+	char *AD = "";
+	char sAL[20] = {0};
+
+	uint32_t best_size=0xFFFFFFFF, best_off, best_crc, best_cmp_size;
+	char best_filename[1024]={0}, best_str_off[20]={0}, best_fname[1024]={0};
+
+	strcpy(best_fname, fname);
+
+	memset(building_hash, 0, sizeof(building_hash));
+
+	if (!(fp = fopen(fname, "rb"))) {
+		fprintf(stderr, "! %s : %s\n", fname, strerror(errno));
+		return;
+	}
+
+	while (!feof(fp)) {
+		uint32_t id = fget32(fp);
+
+		if (id == 0x04034b50UL) {	/* local header */
+			uint16_t version = fget16(fp);
+			uint16_t flags = fget16(fp);
+			uint16_t compression_method = fget16(fp);
+			uint16_t lastmod_time = fget16(fp);
+			uint16_t lastmod_date = fget16(fp);
+			uint32_t crc = fget32(fp);
+			uint32_t compressed_size = fget32(fp);
+			uint32_t uncompressed_size = fget32(fp);
+			uint16_t filename_length = fget16(fp);
+			uint16_t extrafield_length = fget16(fp);
+			/* unused variables */
+			(void) lastmod_date;
+
+			fread(filename, 1, filename_length, fp);
+			filename[filename_length] = 0;
+
+			// we only handle implode or store.
+			if (version == 0x14 && (flags & 1) && (compression_method == 8 || compression_method == 0)) {
+				uint16_t extra_len_used = 0;
+				if (flags & 8) {
+					while (extra_len_used < extrafield_length) {
+						uint16_t efh_id = fget16(fp);
+						uint16_t efh_datasize = fget16(fp);
+						extra_len_used += 4 + efh_datasize;
+						fseek(fp, efh_datasize, SEEK_CUR);
+						//http://svn.assembla.com/svn/os2utils/unzip60f/proginfo/extrafld.txt
+						//http://emerge.hg.sourceforge.net/hgweb/emerge/emerge/diff/c2f208617d32/Source/unzip/proginfo/extrafld.txt
+						if (efh_id == 0x07c8 ||  // Info-ZIP Macintosh (old, J. Lee)
+							efh_id == 0x334d ||  // Info-ZIP Macintosh (new, D. Haase's 'Mac3' field)
+							efh_id == 0x4d49 ||  // Info-ZIP OpenVMS (obsolete)
+							efh_id == 0x5855 ||  // Info-ZIP UNIX (original; also OS/2, NT, etc.)
+							efh_id == 0x6375 ||  // Info-ZIP UTF-8 comment field
+							efh_id == 0x7075 ||  // Info-ZIP UTF-8 name field
+							efh_id == 0x7855 ||  // Info-ZIP UNIX (16-bit UID/GID info)
+							efh_id == 0x7875)    //  Info-ZIP UNIX 3rd generation (generic UID/GID, ...)
+						{
+							unix_made = 1;
+							two_byte_check = 1;
+							check_in_crc = 0;
+						}
+					}
+				}
+				else if (extrafield_length)
+					fseek(fp, extrafield_length, SEEK_CUR);
+
+				fprintf(stderr,
+					"%s->%s PKZIP Encr:%s%s cmplen=%d, decmplen=%d, crc=%X\n",
+					fname, filename, two_byte_check?" 2b chk,":"", check_in_crc?"":" TS_chk,", compressed_size, uncompressed_size, crc);
+
+				if (!checksum_only && uncompressed_size > 48 && uncompressed_size < best_size) {
+					best_size=uncompressed_size;
+					best_off=ftell(fp);
+					best_crc=crc;
+					best_cmp_size=compressed_size;
+					strcpy(best_filename, (char*)filename);
+				}
+
+				if (!checksum_only && ascii_mode && !strcmp((char*)filename, ascii_fname)) {
+					long whence = ftell(fp);
+					unsigned char Buf[112];
+					AL = 112;
+					if (compressed_size < 102)
+						AL = compressed_size;
+					fread(Buf, 1, AL, fp);
+					fseek(fp, whence, SEEK_SET);
+					AD = mem_alloc_tiny( (AL<<1)+1, MEM_ALIGN_NONE);
+					convert_to_hex(AD, Buf, AL);
+					sprintf(sAL, "%x", AL);
+					Flag_bits |= 2;
+					Flag_bits &= (~1); // remove the 'checksum' only flag bit.
+				}
+				if (count_of_hashes < 8 && compressed_size > 14) {
+					fread(H, 1, 12, fp);
+					fseek(fp, compressed_size-12, SEEK_CUR);
+					if (pbuilding_hash != building_hash)
+						*pbuilding_hash++ = '*';
+					pbuilding_hash += convert_to_hex(pbuilding_hash, H, 12);
+					if (!check_in_crc)
+						sprintf (pbuilding_hash, "%02x%02x", lastmod_time>>8, lastmod_time&0xFF);
+					else
+						sprintf (pbuilding_hash, "%02x%02x", (crc>>24)&0xFF, (crc>>16)&0xFF);
+					pbuilding_hash += 4;
+					++count_of_hashes;
+				}
+				else
+					fseek(fp, compressed_size, SEEK_CUR);
+
+			} else {
+				printf("%s->%s is not encrypted, or stored with non-handled compression type\n", fname, filename);
+				fseek(fp, extrafield_length, SEEK_CUR);
+				fseek(fp, compressed_size, SEEK_CUR);
+			}
+		} else if (id == 0x08074b50UL) {	/* data descriptor */
+			fseek(fp, 12, SEEK_CUR);
+		} else if (id == 0x02014b50UL || id == 0x06054b50UL) {	/* central directory structures */
+			goto print_and_cleanup;
+		}
+	}
+
+print_and_cleanup:;
+
+	sprintf (best_str_off, "%x", best_off);
+	if (!checksum_only && best_cmp_size != 0xFFFFFFFF) {
+		Flag_bits |= (4|8);
+		Flag_bits &= (~1); // remove the checksum only bit.
+	}
+	if (!checksum_only && best_cmp_size < 1400) {
+		// we can store the whole ZIP BLOB in the hash line.
+		unsigned char Buf[1400];
+		static char sBuf[2801];
+		// remove bit 3 and set bit 4
+		Flag_bits &= (~8);
+		Flag_bits |= 16;
+		fseek(fp, best_off, SEEK_SET);
+		fread(Buf, 1, best_cmp_size, fp);
+		convert_to_hex(sBuf, Buf, best_cmp_size);
+		FileData = sBuf;
+		best_off = 0;
+		// now, 'remove' the offset, the zip name and the internal file name, since we are storing the 'real' data.
+		*best_filename = 0;
+		*best_fname = 0;
+		*best_str_off = 0;
+
+		if (best_cmp_size < 90) // in this case, simply skip doing ANY ascii checking, and run right to the final checking.
+		{
+			Flag_bits &= (~4);
+			AD = "";
+			*sAL = 0;
+		}
+	}
+	printf ("%s:$pkzip$%x*%x*%x*%s*", fname, count_of_hashes, two_byte_check+1, Flag_bits, building_hash);
+	if (checksum_only)
+		printf("*********\n");
+	else
+		printf("%s*%s*%x*%x*%x*%s*%s*%s*%s*\n", sAL, AD, best_crc, best_cmp_size, best_size, best_str_off, best_fname, best_filename, FileData );
+	fclose(fp);
+}
+
+int usage() {
+	printf("Usage: zip2john [options] [zip files]\n");
+	printf("\tOptions (for 'old' PKZIP encrypted files):\n");
+	printf("\t  -a=filename   This is a 'known' ASCII file\n");
+	printf("\t      Using 'ascii' mode is a serious speedup, IF all files are larger, and\n");
+	printf("\t      you KNOW that at least one of them starts out as 'pure' ASCII data\n");
+	printf("\t  -co This will create a 'checksum only' hash.  If there are many encrypted\n");
+	printf("\t      files in the .zip file, then this may be an option, and there will be\n");
+	printf("\t      enough data that false possitives will not be seen.  If the .zip is 2\n");
+	printf("\t      byte checksums, and there are 8 of them, then only 1 out of 2^128 chance\n");
+	printf("\t      that a bad password could sneak through.  If there are 8 1-byte hashes,\n");
+	printf("\t      there is only 1 in 2^64 chance of a false positive.\n");
+	return 0;
+}
 int zip2john(int argc, char **argv)
 {
-	int i;
+	int i=1;
 
-	if (argc < 2) {
-		puts("Usage: zip2john [zip files]");
-		return 0;
+	if (argc < 2)
+		return usage();
+	while (argv[i][0] == '-') {
+		// handle both the -val and --val types of command line switches (since all the rest of john does this also).
+		if (strstr(argv[i], "-a=")) {
+			if (!strncmp(argv[i], "-a=", 3))
+				ascii_fname = &argv[i][3];
+			else if (!strncmp(argv[i], "--a=", 4))
+				ascii_fname = &argv[i][4];
+			else
+				break;
+			ascii_mode = 1;
+			fprintf(stderr, "Using file %s as an 'ASCII' quick check file\n", ascii_fname);
+			++i;
+		}
+		else if (!strcmp(argv[i], "-co") || !strcmp(argv[i], "--co")) {
+			checksum_only = 1;
+			++i;
+			fprintf(stderr, "Outputing hashes that are 'checksum ONLY' hashes\n");
+		}
+		else if (!strncmp(argv[i], "-h", 2) || !strncmp(argv[i], "--h", 3))
+			return usage();
+		else
+			break; // file name starting with a '-' char.
 	}
-	for (i = 1; i < argc; i++)
+	for (; i < argc; i++)
 		process_file(argv[i]);
 
 	return 0;
diff -urpN john-1.7.8-jumbo-5a/src/john.c john-1.7.8-jumbo-5b/src/john.c
--- john-1.7.8-jumbo-5a/src/john.c	2011-08-16 15:09:16.453125000 +0000
+++ john-1.7.8-jumbo-5b/src/john.c	2011-08-18 20:41:47.000000000 +0000
@@ -577,10 +577,10 @@ int main(int argc, char **argv)
 
 	if (!strcmp(name, "rar2john"))
 		return rar2john(argc, argv);
+#endif
 
 	if (!strcmp(name, "zip2john"))
 		return zip2john(argc, argv);
-#endif
 
 #ifdef HAVE_MPI
 	mpi_setup(argc, argv);
