text: /*
   * ZIP cracker patch for JtR. Hacked together during June of 2011
   * by Dhiru Kholia <dhiru.kholia at gmail.com> for GSoC.
   *
   * This software is Copyright (c) 2011, Dhiru Kholia <dhiru.kholia at gmail.com>,
   * 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.
   *
   * http://www.winzip.com/aes_info.htm (There is a 1 in 65,536 chance that an
   * incorrect password will yield a matching verification value; therefore, a
   * matching verification value cannot be absolutely relied on to indicate a
   * correct password.). The alternative is to implement/use a full unzip engine.
   *
   * This format significantly improved, Summer of 2014, JimF.  Changed the signature
   * to the $zip2$, and added logic to properly make this format work. Now there is no
   * false positives any more.  Now it properly cracks the passwords. There is
   * an hmac-sha1 'key' that is also processed (and the decryption key), in the pbkdf2
   * call.  Now we use this hmac-sha1 key, process the compressed and encrypted buffer,
   * compare to a 10 byte checksum (which is now the binary blob), and we KNOW that we
   * have cracked or not cracked the key.  The $zip$ was broken before, so that signature
   * has simply been retired as DOA.  This format is now much like the pkzip format.
   * it may have all data contained within the hash string, OR it may have some, and
   * have a file pointer on where to get the rest of the data.
   *
   * optimizations still that can be done.
   *  1. decrypt and inflate some data for really large buffers, BEFORE doing the
   *     hmac-sha1 call.  The inflate algorithm is pretty self checking for 'valid'
   *     data, so a few hundred bytes of checking and we are 99.999% sure we have the
   *     right password, before starting an expensive hmac (for instance if the zip blob
   *     was 50mb).
   *  2. Put in the 'file magic' logic we have for pkzip. There is a place holder for it,
   *     but the logic has not been added.
   */
  
  #if FMT_EXTERNS_H
  extern struct fmt_main fmt_zip;
  #elif FMT_REGISTERS_H
  john_register_one(&fmt_zip);
  #else
  
  #include <string.h>
  #include <assert.h>
  #include <errno.h>
  #include <ctype.h>
  
  #include "arch.h"
  #include "crc32.h"
  #include "misc.h"
  #include "params.h"
  #include "common.h"
  #include "formats.h"
  #include "johnswap.h"
  #include "memory.h"
  #include "pkzip.h"
  #include "pbkdf2_hmac_sha1.h"
  #include "dyna_salt.h"
  #ifdef _OPENMP
  #include <omp.h>
  #ifndef OMP_SCALE
  #define OMP_SCALE               1	// Tuned on core i7
  #endif
  static int omp_t = 1;
  #endif
  #include "hmac_sha.h"
  #include "memdbg.h"
  
  #define KEY_LENGTH(mode)        (8 * ((mode) & 3) + 8)
  #define SALT_LENGTH(mode)       (4 * ((mode) & 3) + 4)
  
  typedef struct my_salt_t {
  	dyna_salt dsalt;
  	uint32_t comp_len;
  	struct {
  		uint16_t type     : 4;
  		uint16_t mode : 4;
  	} v;
  	unsigned char passverify[2];
  	unsigned char salt[SALT_LENGTH(3)];
  	//uint64_t data_key; // MSB of md5(data blob).  We lookup using this.
  	unsigned char datablob[1];
  } my_salt;
  
  
  #define FORMAT_LABEL        "ZIP"
  #define FORMAT_NAME         "WinZip"
  #ifdef SIMD_COEF_32
  #define ALGORITHM_NAME      "PBKDF2-SHA1 " SHA1_ALGORITHM_NAME
  #else
  #define ALGORITHM_NAME      "PBKDF2-SHA1 32/" ARCH_BITS_STR
  #endif
  #define PLAINTEXT_LENGTH	125
  #define BINARY_ALIGN        sizeof(ARCH_WORD_32)
  #define SALT_SIZE           sizeof(my_salt*)
  #define SALT_ALIGN          sizeof(my_salt*)
  #ifdef SIMD_COEF_32
  #define MIN_KEYS_PER_CRYPT  SSE_GROUP_SZ_SHA1
  #define MAX_KEYS_PER_CRYPT  SSE_GROUP_SZ_SHA1
  #else
  #define MIN_KEYS_PER_CRYPT  1
  #define MAX_KEYS_PER_CRYPT  1
  #endif
  
  static char (*saved_key)[PLAINTEXT_LENGTH + 1];
  static unsigned char (*crypt_key)[((WINZIP_BINARY_SIZE+3)/4)*4];
  static my_salt *saved_salt;
  
  
  //    filename:$zip2$*Ty*Mo*Ma*Sa*Va*Le*DF*Au*$/zip2$
  //    Ty = type (0) and ignored.
  //    Mo = mode (1 2 3 for 128/192/256 bit
  //    Ma = magic (file magic).  This is reserved for now.  See pkzip_fmt_plug.c or zip2john.c for information.
  //         For now, this must be a '0'
  //    Sa = salt(hex).   8, 12 or 16 bytes of salt (depends on mode)
  //    Va = Verification bytes(hex) (2 byte quick checker)
  //    Le = real compr len (hex) length of compressed/encrypted data (field DF)
  //    DF = compressed data DF can be L*2 hex bytes, and if so, then it is the ENTIRE file blob written 'inline'.
  //         However, if the data blob is too long, then a .zip ZIPDATA_FILE_PTR_RECORD structure will be the 'contents' of DF
  //    Au = Authentication code (hex) a 10 byte hex value that is the hmac-sha1 of data over D. This is the binary() value
  
  //  ZIPDATA_FILE_PTR_RECORD  (this can be the 'DF' of this above hash line.
  //      *ZFILE*Fn*Oh*Ob*  (Note, the leading and trailing * are the * that 'wrap' the DF object.
  //  ZFILE This is the literal string ZFILE
  //  Fn    This is the name of the .zip file.  NOTE the user will need to keep the .zip file in proper locations (same as
  //        was seen when running zip2john. If the file is removed, this hash line will no longer be valid.
  //  Oh    Offset to the zip central header record for this blob.
  //  Ob    Offset to the start of the blob data
  
  static void init(struct fmt_main *self)
  {
  #ifdef _OPENMP
  	omp_t = omp_get_max_threads();
  	self->params.min_keys_per_crypt *= omp_t;
  	omp_t *= OMP_SCALE;
  	self->params.max_keys_per_crypt *= omp_t;
  #endif
  	saved_key = mem_calloc(self->params.max_keys_per_crypt,
  	                       sizeof(*saved_key));
  	crypt_key = mem_calloc(self->params.max_keys_per_crypt,
  	                       sizeof(*crypt_key));
  }
  
  static void done(void)
  {
  	MEM_FREE(crypt_key);
  	MEM_FREE(saved_key);
  }
  
  static void *get_salt(char *ciphertext)
  {
  	int i;
  	my_salt salt, *psalt;
  	static unsigned char *ptr;
  	/* extract data from "ciphertext" */
  	c8 *copy_mem = strdup(ciphertext);
  	c8 *cp, *p;
  
  	if (!ptr) ptr = mem_alloc_tiny(sizeof(my_salt*),sizeof(my_salt*));
  	p = copy_mem + WINZIP_TAG_LENGTH+1; /* skip over "$zip2$*" */
  	memset(&salt, 0, sizeof(salt));
  	cp = strtokm(p, "*"); // type
  	salt.v.type = atoi((const char*)cp);
  	cp = strtokm(NULL, "*"); // mode
  	salt.v.mode = atoi((const char*)cp);
  	cp = strtokm(NULL, "*"); // file_magic enum (ignored)
  	cp = strtokm(NULL, "*"); // salt
  	for (i = 0; i < SALT_LENGTH(salt.v.mode); i++)
  		salt.salt[i] = (atoi16[ARCH_INDEX(cp[i<<1])]<<4) | atoi16[ARCH_INDEX(cp[(i<<1)+1])];
  	cp = strtokm(NULL, "*");	// validator
  	salt.passverify[0] = (atoi16[ARCH_INDEX(cp[0])]<<4) | atoi16[ARCH_INDEX(cp[1])];
  	salt.passverify[1] = (atoi16[ARCH_INDEX(cp[2])]<<4) | atoi16[ARCH_INDEX(cp[3])];
  	cp = strtokm(NULL, "*");	// data len
  	sscanf((const char *)cp, "%x", &salt.comp_len);
  
  	// later we will store the data blob in our own static data structure, and place the 64 bit LSB of the
  	// MD5 of the data blob into a field in the salt. For the first POC I store the entire blob and just
  	// make sure all my test data is small enough to fit.
  
  	cp = strtokm(NULL, "*");	// data blob
  
  	// Ok, now create the allocated salt record we are going to return back to John, using the dynamic
  	// sized data buffer.
  	psalt = (my_salt*)mem_calloc(1, sizeof(my_salt) + salt.comp_len);
  	psalt->v.type = salt.v.type;
  	psalt->v.mode = salt.v.mode;
  	psalt->comp_len = salt.comp_len;
  	psalt->dsalt.salt_alloc_needs_free = 1;  // we used mem_calloc, so JtR CAN free our pointer when done with them.
  	memcpy(psalt->salt, salt.salt, sizeof(salt.salt));
  	psalt->passverify[0] = salt.passverify[0];
  	psalt->passverify[1] = salt.passverify[1];
  
  	// set the JtR core linkage stuff for this dyna_salt
  	psalt->dsalt.salt_cmp_offset = SALT_CMP_OFF(my_salt, comp_len);
  	psalt->dsalt.salt_cmp_size = SALT_CMP_SIZE(my_salt, comp_len, datablob, psalt->comp_len);
  
  
  	if (strcmp((const char*)cp, "ZFILE")) {
  	for (i = 0; i < psalt->comp_len; i++)
  		psalt->datablob[i] = (atoi16[ARCH_INDEX(cp[i<<1])]<<4) | atoi16[ARCH_INDEX(cp[(i<<1)+1])];
  	} else {
  		c8 *Fn, *Oh, *Ob;
  		long len;
  		uint32_t id;
  		FILE *fp;
  
  		Fn = strtokm(NULL, "*");
  		Oh = strtokm(NULL, "*");
  		Ob = strtokm(NULL, "*");
  
  		fp = fopen((const char*)Fn, "rb");
  		if (!fp) {
  			psalt->v.type = 1; // this will tell the format to 'skip' this salt, it is garbage
  			goto Bail;
  		}
  		sscanf((const char*)Oh, "%lx", &len);
  		if (fseek(fp, len, SEEK_SET)) {
  			fclose(fp);
  			psalt->v.type = 1;
  			goto Bail;
  		}
  		id = fget32LE(fp);
  		if (id != 0x04034b50U) {
  			fclose(fp);
  			psalt->v.type = 1;
  			goto Bail;
  		}
  		sscanf((const char*)Ob, "%lx", &len);
  		if (fseek(fp, len, SEEK_SET)) {
  			fclose(fp);
  			psalt->v.type = 1;
  			goto Bail;
  		}
  		if (fread(psalt->datablob, 1, psalt->comp_len, fp) != psalt->comp_len) {
  			fclose(fp);
  			psalt->v.type = 1;
  			goto Bail;
  		}
  		fclose(fp);
  	}
  Bail:;
  	MEM_FREE(copy_mem);
  
  	memcpy(ptr, &psalt, sizeof(my_salt*));
  	return (void*)ptr;
  }
  
  static void set_salt(void *salt)
  {
  	saved_salt = *((my_salt**)salt);
  }
  
  static void set_key(char *key, int index)
  {
  	int saved_len = strlen(key);
  	if (saved_len > PLAINTEXT_LENGTH)
  		saved_len = PLAINTEXT_LENGTH;
  	memcpy(saved_key[index], key, saved_len);
  	saved_key[index][saved_len] = 0;
  }
  
  static char *get_key(int index)
  {
  	return saved_key[index];
  }
  
  static int get_hash_0(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_0; }
  static int get_hash_1(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_1; }
  static int get_hash_2(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_2; }
  static int get_hash_3(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_3; }
  static int get_hash_4(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_4; }
  static int get_hash_5(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_5; }
  static int get_hash_6(int index) { return ((ARCH_WORD_32*)&(crypt_key[index]))[0] & PH_MASK_6; }
  
  static int crypt_all(int *pcount, struct db_salt *salt)
  {
  	int count = *pcount;
  	int index;
  
  	if (saved_salt->v.type) {
  		// This salt passed valid() but failed get_salt().
  		// Should never happen.
  		memset(crypt_key, 0, count * WINZIP_BINARY_SIZE);
  		return count;
  	}
  
  #ifdef _OPENMP
  #pragma omp parallel for default(none) private(index) shared(count, saved_key, saved_salt, crypt_key)
  #endif
  	for (index = 0; index < count; index += MAX_KEYS_PER_CRYPT) {
  #ifdef SIMD_COEF_32
  		unsigned char pwd_ver[64*MAX_KEYS_PER_CRYPT];
  		int lens[MAX_KEYS_PER_CRYPT], i;
  		unsigned char *pin[MAX_KEYS_PER_CRYPT], *pout[MAX_KEYS_PER_CRYPT];
  		for (i = 0; i < MAX_KEYS_PER_CRYPT; ++i) {
  			lens[i] = strlen(saved_key[i+index]);
  			pin[i] = (unsigned char*)saved_key[i+index];
  			pout[i] = &pwd_ver[i*(2+2*KEY_LENGTH(saved_salt->v.mode))];
  		}
  		pbkdf2_sha1_sse((const unsigned char **)pin, lens, saved_salt->salt,
  		                SALT_LENGTH(saved_salt->v.mode), KEYING_ITERATIONS,
  		                pout, 2, 2*KEY_LENGTH(saved_salt->v.mode));
  		for (i = 0; i < MAX_KEYS_PER_CRYPT; ++i) {
  			if (!memcmp(pout[i], saved_salt->passverify, 2)) {
  				pbkdf2_sha1_sse((const unsigned char **)pin, lens,
  				                saved_salt->salt,
  				                SALT_LENGTH(saved_salt->v.mode),
  				                KEYING_ITERATIONS, pout,
  				                KEY_LENGTH(saved_salt->v.mode),
  				                KEY_LENGTH(saved_salt->v.mode));
  				hmac_sha1(pout[i], KEY_LENGTH(saved_salt->v.mode),
  				          (const unsigned char*)saved_salt->datablob,
  				          saved_salt->comp_len, crypt_key[index+i],
  				          WINZIP_BINARY_SIZE);
  			}
  			else
  				memset(crypt_key[index+i], 0, WINZIP_BINARY_SIZE);
  		}
  #else
  		union {
  			unsigned char pwd_ver[64];
  			ARCH_WORD_32 w;
  		} x;
  		unsigned char *pwd_ver = x.pwd_ver;
  		pbkdf2_sha1((unsigned char *)saved_key[index], strlen(saved_key[index]),
  		            saved_salt->salt, SALT_LENGTH(saved_salt->v.mode),
  		            KEYING_ITERATIONS, pwd_ver, 2,
  		            2*KEY_LENGTH(saved_salt->v.mode));
  		if (!memcmp(pwd_ver, saved_salt->passverify, 2)) {
  			pbkdf2_sha1((unsigned char *)saved_key[index],
  			            strlen(saved_key[index]), saved_salt->salt,
  			            SALT_LENGTH(saved_salt->v.mode), KEYING_ITERATIONS,
  			            pwd_ver, KEY_LENGTH(saved_salt->v.mode),
  			            KEY_LENGTH(saved_salt->v.mode));
  			hmac_sha1(pwd_ver, KEY_LENGTH(saved_salt->v.mode),
  			          (const unsigned char*)saved_salt->datablob,
  			          saved_salt->comp_len, crypt_key[index],
  			          WINZIP_BINARY_SIZE);
  		}
  		else
  			memset(crypt_key[index], 0, WINZIP_BINARY_SIZE);
  #endif
  	}
  	return count;
  }
  
  static int cmp_all(void *binary, int count)
  {
  	int i;
  
  	for (i = 0; i < count; i++)
  		if (((ARCH_WORD_32*)&(crypt_key[i]))[0] == ((ARCH_WORD_32*)binary)[0])
  			return 1;
  	return 0;
  }
  
  static int cmp_one(void *binary, int index)
  {
  	return (((ARCH_WORD_32*)&(crypt_key[index]))[0] == ((ARCH_WORD_32*)binary)[0]);
  }
  
  static int cmp_exact(char *source, int index)
  {
  	void *b = winzip_common_binary(source);
  	return !memcmp(b, crypt_key[index], sizeof(crypt_key[index]));
  }
  
  struct fmt_main fmt_zip = {
  	{
  		FORMAT_LABEL,
  		FORMAT_NAME,
  		ALGORITHM_NAME,
  		WINZIP_BENCHMARK_COMMENT,
  		WINZIP_BENCHMARK_LENGTH,
  		0,
  		PLAINTEXT_LENGTH,
  		4, // WINZIP_BINARY_SIZE,
  		BINARY_ALIGN,
  		SALT_SIZE,
  		SALT_ALIGN,
  		MIN_KEYS_PER_CRYPT,
  		MAX_KEYS_PER_CRYPT,
  		FMT_CASE | FMT_8_BIT | FMT_OMP | FMT_DYNA_SALT,
  		{ NULL },
  		winzip_common_tests
  	}, {
  		init,
  		done,
  		fmt_default_reset,
  		fmt_default_prepare,
  		winzip_common_valid,
  		fmt_default_split,
  		winzip_common_binary,
  		get_salt,
  		{ NULL },
  		fmt_default_source,
  		{
  			fmt_default_binary_hash_0,
  			fmt_default_binary_hash_1,
  			fmt_default_binary_hash_2,
  			fmt_default_binary_hash_3,
  			fmt_default_binary_hash_4,
  			fmt_default_binary_hash_5,
  			fmt_default_binary_hash_6
  		},
  		fmt_default_dyna_salt_hash,
  		NULL,
  		set_salt,
  		set_key,
  		get_key,
  		fmt_default_clear_keys,
  		crypt_all,
  		{
  			get_hash_0,
  			get_hash_1,
  			get_hash_2,
  			get_hash_3,
  			get_hash_4,
  			get_hash_5,
  			get_hash_6
  		},
  		cmp_all,
  		cmp_one,
  		cmp_exact
  	}
  };
  
  #endif /* plugin stanza */
  