From 7053e4738a32acfcf98098833ed68595fbeaceb2 Mon Sep 17 00:00:00 2001
From: magnum <magnum>
Date: Fri, 16 Sep 2011 11:25:27 +0200
Subject: [PATCH] NETNTLM, NETNTLMv2, NETLMv2, MSCHAPv2 OMP scaling

---
 src/MSCHAPv2_fmt_plug.c  |   71 +++++++++++---------------
 src/NETLMv2_fmt_plug.c   |   96 ++++++++++++-----------------------
 src/NETNTLM_fmt_plug.c   |   73 +++++++++++++++------------
 src/NETNTLMv2_fmt_plug.c |  125 ++++++++++++++++++----------------------------
 src/mskrb5_fmt_plug.c    |    2 +-
 5 files changed, 152 insertions(+), 215 deletions(-)

diff --git a/src/MSCHAPv2_fmt_plug.c b/src/MSCHAPv2_fmt_plug.c
index f3e7567..460e5e0 100644
--- a/src/MSCHAPv2_fmt_plug.c
+++ b/src/MSCHAPv2_fmt_plug.c
@@ -47,8 +47,7 @@
 #define ALGORITHM_NAME       "mschapv2"
 #define BENCHMARK_COMMENT    ""
 #define BENCHMARK_LENGTH     0
-#define PLAINTEXT_LENGTH     54 /* lmcons.h - PWLEN (256) ? 127 ? */
-#define UTF8_PLAINTEXT_LEN   125
+#define PLAINTEXT_LENGTH     125 /* lmcons.h - PWLEN (256) ? 127 ? */
 #define USERNAME_LENGTH      256 /* lmcons.h - UNLEN (256) / LM20_UNLEN (20) */
 #define DOMAIN_LENGTH        15  /* lmcons.h - CNLEN / DNLEN */
 #define PARTIAL_BINARY_SIZE  8
@@ -59,13 +58,12 @@
 #define TOTAL_LENGTH         13 + USERNAME_LENGTH + CHALLENGE_LENGTH + CIPHERTEXT_LENGTH
 
 // these may be altered in init() if running OMP
-// and that formula is subject to change
-#define MIN_KEYS_PER_CRYPT	    1
-#define THREAD_RATIO            256
+#define MIN_KEYS_PER_CRYPT	1
+#define THREAD_RATIO		256
 #ifdef _OPENMP
-#define MAX_KEYS_PER_CRYPT	    0x10000
+#define MAX_KEYS_PER_CRYPT	0x10000
 #else
-#define MAX_KEYS_PER_CRYPT	    THREAD_RATIO
+#define MAX_KEYS_PER_CRYPT	THREAD_RATIO
 #endif
 
 static struct fmt_tests tests[] = {
@@ -84,10 +82,12 @@ static struct fmt_tests tests[] = {
   {NULL}
 };
 
-static uchar saved_plain[MAX_KEYS_PER_CRYPT][UTF8_PLAINTEXT_LEN + 1];
+static uchar saved_plain[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int saved_len[MAX_KEYS_PER_CRYPT];
 static uchar saved_key[MAX_KEYS_PER_CRYPT][21];
 static uchar *challenge;
 static ARCH_WORD_32 output[MAX_KEYS_PER_CRYPT][PARTIAL_BINARY_SIZE/sizeof(ARCH_WORD_32)];
+static int keys_prepared;
 
 #include "unicode.h"
 
@@ -101,15 +101,11 @@ static void init(struct fmt_main *pFmt)
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_MSCHAPv2.params.min_keys_per_crypt = n;
-	n = n * n * ((n >> 1) + 1) * THREAD_RATIO;
+	n = n * (n << 1) * THREAD_RATIO;
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_MSCHAPv2.params.max_keys_per_crypt = n;
 #endif
-	if (options.utf8) {
-		// in utf-8, up to four bytes can compose one character
-		fmt_MSCHAPv2.params.plaintext_length = UTF8_PLAINTEXT_LEN;
-	}
 }
 
 static int mschapv2_valid(char *ciphertext, struct fmt_main *pFmt)
@@ -157,25 +153,6 @@ static int mschapv2_valid(char *ciphertext, struct fmt_main *pFmt)
 
 static char *mschapv2_prepare(char *split_fields[10], struct fmt_main *pFmt)
 {
-//	else if (options.format && (strncmp(options.format, "mschapv2", 8)==0)) {
-//		char *srv_challenge = ldr_get_field(&line, db_options->field_sep_char);
-//		char *mschapv2 = ldr_get_field(&line, db_options->field_sep_char);
-//		char *cli_challenge = ldr_get_field(&line, db_options->field_sep_char);
-//		char *username = NULL;
-//
-//	/* DOMAIN\USERNAME -or - USERNAME -- ignore DOMAIN */
-//	if ((tmp = strstr(*login, "\\")) == NULL)
-//		tmp = *login;
-//	else
-//		tmp++;
-//
-//		username = (char *) mem_alloc(strlen(tmp) + 1);
-//		strcpy(username, tmp);
-//
-//		tmp = (char *) mem_alloc_tiny(8 + strlen(srv_challenge) + 1 + strlen(mschapv2) + 1 + strlen(cli_challenge) + 1 + strlen(username) + 1, MEM_ALIGN_NONE);
-//		sprintf(tmp, "$MSCHAPv2$%s$%s$%s$%s", srv_challenge, mschapv2, cli_challenge, username);
-//		*ciphertext = tmp;
-//	}
 	char *username, *cp;
 
 	if (!strncmp(split_fields[1], "$MSCHAPv2$", 10))
@@ -263,6 +240,23 @@ static void mschapv2_crypt_all(int count)
 	DES_key_schedule ks;
 	int i;
 
+	if (!keys_prepared) {
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+		for(i=0; i<count; i++) {
+			int len;
+			/* Generate 16-byte NTLM hash */
+			len = E_md4hash((uchar *) saved_plain[i], saved_len[i], saved_key[i]);
+
+			if (len <= 0)
+				saved_plain[i][-len] = 0; // match if it was truncated
+
+			/* NULL-padding the 16-byte hash to 21-bytes is made in cmp_exact if needed */
+		}
+		keys_prepared = 1;
+	}
+
 #ifdef _OPENMP
 #pragma omp parallel for default(none) private(i, ks) shared(count, output, challenge, saved_key)
 #endif
@@ -363,16 +357,9 @@ static void mschapv2_set_salt(void *salt)
 
 static void mschapv2_set_key(char *key, int index)
 {
-	int len = strlen(key);
-	memcpy(saved_plain[index], key, len + 1);
-
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash((uchar *) saved_plain[index], len, saved_key[index]);
-
-	if (len <= 0)
-		saved_plain[index][-len] = 0; // match if it was truncated
-
-	/* NULL-padding the 16-byte hash to 21-bytes is made in cmp_exact if needed */
+	saved_len[index] = strlen(key);
+	memcpy(saved_plain[index], key, saved_len[index] + 1);
+	keys_prepared = 0;
 }
 
 static char *mschapv2_get_key(int index)
diff --git a/src/NETLMv2_fmt_plug.c b/src/NETLMv2_fmt_plug.c
index de77b1c..14cec11 100644
--- a/src/NETLMv2_fmt_plug.c
+++ b/src/NETLMv2_fmt_plug.c
@@ -51,25 +51,8 @@
 #include "options.h"
 #include "unicode.h"
 
-#if 0
-#warning INFO: We are using OpenSSL HMAC_MD5
-#include <openssl/hmac.h>
-static void hmac_md5(const unsigned char *key, const unsigned char *data, int datalen, unsigned char *digest)
-{
-	HMAC(EVP_md5(), key, 16, data, datalen, digest, NULL);
-}
-#else
 #include "md5.h"
 #include "hmacmd5.h"
-// Move a hmac_md5_init() from crypt_all to set_key(),
-// and store &ctx in saved_key.
-//
-// Pro: saves another key setup using same key
-// Con: larger saved_key (288 bytes vs 16)
-//
-// This boosted performance with about 8%
-#define SPLIT_HMACMD5
-#endif
 
 #ifndef uchar
 #define uchar unsigned char
@@ -80,8 +63,7 @@ static void hmac_md5(const unsigned char *key, const unsigned char *data, int da
 #define ALGORITHM_NAME       "netlmv2"
 #define BENCHMARK_COMMENT    ""
 #define BENCHMARK_LENGTH     0
-#define PLAINTEXT_LENGTH     54 /* lmcons.h - PWLEN (256) ? 127 ? */
-#define UTF8_PLAINTEXT_LEN   125
+#define PLAINTEXT_LENGTH     125 /* lmcons.h - PWLEN (256) ? 127 ? */
 #define USERNAME_LENGTH      20 /* lmcons.h - UNLEN (256) / LM20_UNLEN (20) */
 #define DOMAIN_LENGTH        15 /* lmcons.h - CNLEN / DNLEN */
 #define BINARY_SIZE          16
@@ -91,13 +73,12 @@ static void hmac_md5(const unsigned char *key, const unsigned char *data, int da
 #define TOTAL_LENGTH         12 + USERNAME_LENGTH + DOMAIN_LENGTH + CHALLENGE_LENGTH + CIPHERTEXT_LENGTH
 
 // these may be altered in init() if running OMP
-// and that formula is subject to change
-#define MIN_KEYS_PER_CRYPT	    1
-#define THREAD_RATIO            64
+#define MIN_KEYS_PER_CRYPT	1
+#define THREAD_RATIO		64
 #ifdef _OPENMP
-#define MAX_KEYS_PER_CRYPT	    0x10000
+#define MAX_KEYS_PER_CRYPT	0x10000
 #else
-#define MAX_KEYS_PER_CRYPT	    THREAD_RATIO
+#define MAX_KEYS_PER_CRYPT	THREAD_RATIO
 #endif
 
 static struct fmt_tests tests[] = {
@@ -111,16 +92,13 @@ static struct fmt_tests tests[] = {
   {NULL}
 };
 
-static unsigned char saved_plain[MAX_KEYS_PER_CRYPT][UTF8_PLAINTEXT_LEN+1];
+static unsigned char saved_plain[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int saved_len[MAX_KEYS_PER_CRYPT];
+static int keys_prepared;
+static HMACMD5Context saved_ctx[MAX_KEYS_PER_CRYPT];
 static unsigned char *challenge;
 static ARCH_WORD_32 output[MAX_KEYS_PER_CRYPT][BINARY_SIZE/sizeof(ARCH_WORD_32)];
 
-#ifdef SPLIT_HMACMD5
-static HMACMD5Context saved_key[MAX_KEYS_PER_CRYPT];
-#else
-static unsigned char saved_key[MAX_KEYS_PER_CRYPT][16];
-#endif
-
 #if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
 #if (SIZEOF_SHORT == 4)
 #define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16;
@@ -154,10 +132,6 @@ static void init(struct fmt_main *pFmt)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_NETLMv2.params.max_keys_per_crypt = n;
 #endif
-	if (options.utf8) {
-		// in utf-8, up to four bytes can compose one character
-		fmt_NETLMv2.params.plaintext_length = UTF8_PLAINTEXT_LEN;
-	}
 }
 
 static int netlmv2_valid(char *ciphertext, struct fmt_main *pFmt)
@@ -296,20 +270,35 @@ static void netlmv2_crypt_all(int count)
 	unsigned char ntlm_v2_hash[16];
 	int i;
 
+	if (!keys_prepared) {
 #ifdef _OPENMP
-#pragma omp parallel for default(none) private(i, ntlm_v2_hash) shared(count, saved_key, challenge, output)
+#pragma omp parallel for
+#endif
+		for (i = 0; i < count; i++) {
+			int len;
+			unsigned char ntlm[16];
+			/* Generate 16-byte NTLM hash */
+			len = E_md4hash(saved_plain[i], saved_len[i], ntlm);
+
+			// We do key setup of the next HMAC_MD5 here. rest in inner loop
+			hmac_md5_init_K16(ntlm, &saved_ctx[i]);
+
+			if (len <= 0)
+				saved_plain[i][-len] = 0; // match truncation
+		}
+		keys_prepared = 1;
+	}
+
+#ifdef _OPENMP
+#pragma omp parallel for default(none) private(i, ntlm_v2_hash) shared(count, saved_ctx, challenge, output)
 #endif
 	for(i=0; i<count; i++) {
 		/* Generate 16-byte NTLMv2 Hash */
 		/* HMAC-MD5(Username + Domain, NTLM Hash) */
-#ifdef SPLIT_HMACMD5
 		HMACMD5Context ctx; // can't be moved above the OMP pragma
-		memcpy(&ctx, &saved_key[i], sizeof(ctx));
+		memcpy(&ctx, &saved_ctx[i], sizeof(ctx));
 		hmac_md5_update(&challenge[17], (int)challenge[16], &ctx);
 		hmac_md5_final(ntlm_v2_hash, &ctx);
-#else
-		hmac_md5(saved_key[i], &challenge[17], (int)challenge[16], ntlm_v2_hash);
-#endif
 
 		/* Generate 16-byte non-client nonce portion of LMv2 Response */
 		/* HMAC-MD5(Challenge + Nonce, NTLMv2 Hash) + Nonce */
@@ -387,28 +376,9 @@ static void netlmv2_set_salt(void *salt)
 
 static void netlmv2_set_key(char *key, int index)
 {
-	int len;
-#ifdef SPLIT_HMACMD5
-	unsigned char ntlm[16];
-#endif
-
-	len = strlen(key);
-	memcpy((char *)saved_plain[index], key, len + 1);
-
-#ifdef SPLIT_HMACMD5
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash(saved_plain[index], len, ntlm);
-
-	// We do key setup of the next HMAC_MD5 here. rest in crypt_all()
-	// &saved_key is now &ctx
-	hmac_md5_init_K16(ntlm, &saved_key[index]);
-#else
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash(saved_plain[index], len, saved_key[index]);
-#endif
-
-	if (len <= 0)
-		saved_plain[index][-len] = 0; // match truncation
+	saved_len[index] = strlen(key);
+	memcpy((char *)saved_plain[index], key, saved_len[index] + 1);
+	keys_prepared = 0;
 }
 
 static char *netlmv2_get_key(int index)
diff --git a/src/NETNTLM_fmt_plug.c b/src/NETNTLM_fmt_plug.c
index 612ac74..ab7430a 100644
--- a/src/NETNTLM_fmt_plug.c
+++ b/src/NETNTLM_fmt_plug.c
@@ -58,27 +58,25 @@
 #define uchar unsigned char
 #endif
 
-#define FORMAT_LABEL         "netntlm"
-#define FORMAT_NAME          "NTLMv1 C/R MD4 DES [ESS MD5]"
-#define ALGORITHM_NAME       "netntlm"
-#define BENCHMARK_COMMENT    ""
-#define BENCHMARK_LENGTH     0
-#define PLAINTEXT_LENGTH     54 /* ?127? */
-#define UTF8_PLAINTEXT_LEN   125
-#define BINARY_SIZE          24
-#define PARTIAL_BINARY_SIZE  8
-#define SALT_SIZE            8
-#define CIPHERTEXT_LENGTH    48
-#define TOTAL_LENGTH         (10 + 2 * 2 * SALT_SIZE + CIPHERTEXT_LENGTH)
+#define FORMAT_LABEL		"netntlm"
+#define FORMAT_NAME		"NTLMv1 C/R MD4 DES [ESS MD5]"
+#define ALGORITHM_NAME		"netntlm"
+#define BENCHMARK_COMMENT	""
+#define BENCHMARK_LENGTH	0
+#define PLAINTEXT_LENGTH	125
+#define BINARY_SIZE		24
+#define PARTIAL_BINARY_SIZE	8
+#define SALT_SIZE		8
+#define CIPHERTEXT_LENGTH	48
+#define TOTAL_LENGTH		(10 + 2 * 2 * SALT_SIZE + CIPHERTEXT_LENGTH)
 
 // these may be altered in init() if running OMP
-// and that formula is subject to change
-#define MIN_KEYS_PER_CRYPT	    1
-#define THREAD_RATIO            128
+#define MIN_KEYS_PER_CRYPT	1
+#define THREAD_RATIO		128
 #ifdef _OPENMP
-#define MAX_KEYS_PER_CRYPT	    0x10000
+#define MAX_KEYS_PER_CRYPT	0x10000
 #else
-#define MAX_KEYS_PER_CRYPT	    THREAD_RATIO
+#define MAX_KEYS_PER_CRYPT	THREAD_RATIO
 #endif
 
 static struct fmt_tests tests[] = {
@@ -98,10 +96,12 @@ static struct fmt_tests tests[] = {
   {NULL}
 };
 
-static char saved_plain[MAX_KEYS_PER_CRYPT][UTF8_PLAINTEXT_LEN+1];
+static char saved_plain[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int saved_len[MAX_KEYS_PER_CRYPT];
 static uchar *challenge;
 static ARCH_WORD_32 output[MAX_KEYS_PER_CRYPT][PARTIAL_BINARY_SIZE/sizeof(ARCH_WORD_32)];
 static uchar saved_key[MAX_KEYS_PER_CRYPT][21]; // NT hash
+static int keys_prepared;
 
 extern struct fmt_main fmt_NETNTLM;
 static void init(struct fmt_main *pFmt)
@@ -113,15 +113,11 @@ static void init(struct fmt_main *pFmt)
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_NETNTLM.params.min_keys_per_crypt = n;
-	n = n * n * ((n >> 1) + 1) * THREAD_RATIO;
+	n = n * (n << 1) * THREAD_RATIO;
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_NETNTLM.params.max_keys_per_crypt = n;
 #endif
-	if (options.utf8) {
-		// in utf-8, up to four bytes can compose one character
-		fmt_NETNTLM.params.plaintext_length = UTF8_PLAINTEXT_LEN;
-	}
 }
 
 static int netntlm_valid(char *ciphertext, struct fmt_main *pFmt)
@@ -222,6 +218,24 @@ static void netntlm_crypt_all(int count)
 	DES_key_schedule ks;
 	int i;
 
+	if (!keys_prepared) {
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+		for (i = 0; i < count; i++) {
+			int len;
+
+			/* Generate 16-byte NTLM hash */
+			len = E_md4hash((uchar *) saved_plain[i], saved_len[i], saved_key[i]);
+
+			if (len <= 0)
+				saved_plain[i][-len] = 0; // match truncation
+
+			/* Hash is NULL padded to 21-bytes in cmp_exact if needed */
+		}
+		keys_prepared = 1;
+	}
+
 #ifdef _OPENMP
 #pragma omp parallel for default(none) private(i, ks) shared(count, output, saved_key, challenge)
 #endif
@@ -306,16 +320,9 @@ static void netntlm_set_salt(void *salt)
 
 static void netntlm_set_key(char *key, int index)
 {
-	int len = strlen(key);
-	memcpy(saved_plain[index], key, len + 1);
-
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash((uchar *) saved_plain[index], len, saved_key[index]);
-
-	if (len <= 0)
-		saved_plain[index][-len] = 0; // match truncation
-
-	/* Hash is NULL padded to 21-bytes in cmp_exact if needed */
+	saved_len[index] = strlen(key);
+	memcpy(saved_plain[index], key, saved_len[index] + 1);
+	keys_prepared = 0;
 }
 
 static char *netntlm_get_key(int index)
diff --git a/src/NETNTLMv2_fmt_plug.c b/src/NETNTLMv2_fmt_plug.c
index 3c6b576..ace6f0d 100644
--- a/src/NETNTLMv2_fmt_plug.c
+++ b/src/NETNTLMv2_fmt_plug.c
@@ -49,25 +49,8 @@
 #include "formats.h"
 #include "options.h"
 
-#if 0
-#warning INFO: We are using OpenSSL HMAC_MD5
-#include <openssl/hmac.h>
-static void hmac_md5(const unsigned char *key, const unsigned char *data, int datalen, unsigned char *digest)
-{
-	HMAC(EVP_md5(), key, 16, data, datalen, digest, NULL);
-}
-#else
 #include "md5.h"
 #include "hmacmd5.h"
-// Move a hmac_md5_init() from crypt_all to set_key(),
-// and store &ctx in saved_key.
-//
-// Pro: saves another key setup using same key
-// Con: larger saved_key (288 bytes vs 16)
-//
-// This boosted performance with about 8%
-#define SPLIT_HMACMD5
-#endif
 
 #include "unicode.h"
 
@@ -75,30 +58,28 @@ static void hmac_md5(const unsigned char *key, const unsigned char *data, int da
 #define uchar unsigned char
 #endif
 
-#define FORMAT_LABEL         "netntlmv2"
-#define FORMAT_NAME          "NTLMv2 C/R MD4 HMAC-MD5"
-#define ALGORITHM_NAME       "netntlmv2"
-#define BENCHMARK_COMMENT    ""
-#define BENCHMARK_LENGTH     0
-#define PLAINTEXT_LENGTH     54 /* lmcons.h - PWLEN (256) ? 127 ? */
-#define UTF8_PLAINTEXT_LEN   125
-#define USERNAME_LENGTH      20 /* lmcons.h - UNLEN (256) / LM20_UNLEN (20) */
-#define DOMAIN_LENGTH        15 /* lmcons.h - CNLEN / DNLEN */
-#define BINARY_SIZE          16
-#define SERVER_CHALL_LENGTH  16
-#define CLIENT_CHALL_LENGTH_MAX  1024 /* FIXME - Max Target Information Size Unknown */
-#define SALT_SIZE_MAX        2 * USERNAME_LENGTH + 2 * DOMAIN_LENGTH + 3 + SERVER_CHALL_LENGTH/2 + CLIENT_CHALL_LENGTH_MAX/2
-#define CIPHERTEXT_LENGTH    32
-#define TOTAL_LENGTH         12 + USERNAME_LENGTH + DOMAIN_LENGTH + SERVER_CHALL_LENGTH + CLIENT_CHALL_LENGTH_MAX + CIPHERTEXT_LENGTH
+#define FORMAT_LABEL		"netntlmv2"
+#define FORMAT_NAME		"NTLMv2 C/R MD4 HMAC-MD5"
+#define ALGORITHM_NAME		"netntlmv2"
+#define BENCHMARK_COMMENT	""
+#define BENCHMARK_LENGTH	0
+#define PLAINTEXT_LENGTH	125 /* lmcons.h - PWLEN (256) ? 127 ? */
+#define USERNAME_LENGTH		20 /* lmcons.h - UNLEN (256) / LM20_UNLEN (20) */
+#define DOMAIN_LENGTH		15 /* lmcons.h - CNLEN / DNLEN */
+#define BINARY_SIZE		16
+#define SERVER_CHALL_LENGTH	16
+#define CLIENT_CHALL_LENGTH_MAX	1024 /* FIXME - Max Target Information Size Unknown */
+#define SALT_SIZE_MAX		2 * USERNAME_LENGTH + 2 * DOMAIN_LENGTH + 3 + SERVER_CHALL_LENGTH/2 + CLIENT_CHALL_LENGTH_MAX/2
+#define CIPHERTEXT_LENGTH	32
+#define TOTAL_LENGTH		12 + USERNAME_LENGTH + DOMAIN_LENGTH + SERVER_CHALL_LENGTH + CLIENT_CHALL_LENGTH_MAX + CIPHERTEXT_LENGTH
 
 // these may be altered in init() if running OMP
-// and that formula is subject to change
-#define MIN_KEYS_PER_CRYPT	    1
-#define THREAD_RATIO            256
+#define MIN_KEYS_PER_CRYPT	1
+#define THREAD_RATIO		256
 #ifdef _OPENMP
-#define MAX_KEYS_PER_CRYPT	    0x10000
+#define MAX_KEYS_PER_CRYPT	0x20000
 #else
-#define MAX_KEYS_PER_CRYPT	    THREAD_RATIO
+#define MAX_KEYS_PER_CRYPT	THREAD_RATIO
 #endif
 
 static struct fmt_tests tests[] = {
@@ -118,14 +99,12 @@ static struct fmt_tests tests[] = {
   {NULL}
 };
 
-static uchar saved_plain[MAX_KEYS_PER_CRYPT][UTF8_PLAINTEXT_LEN+1];
+static uchar saved_plain[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int saved_len[MAX_KEYS_PER_CRYPT];
 static uchar *challenge;
 static ARCH_WORD_32 output[MAX_KEYS_PER_CRYPT][BINARY_SIZE/sizeof(ARCH_WORD_32)];
-#ifdef SPLIT_HMACMD5
-static HMACMD5Context saved_key[MAX_KEYS_PER_CRYPT];
-#else
-static unsigned char saved_key[MAX_KEYS_PER_CRYPT][16];
-#endif
+static HMACMD5Context saved_ctx[MAX_KEYS_PER_CRYPT];
+static int keys_prepared;
 
 #if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H)
 #if (SIZEOF_SHORT == 4)
@@ -155,15 +134,11 @@ static void init(struct fmt_main *pFmt)
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_NETNTLMv2.params.min_keys_per_crypt = n;
-	n = n * n * ((n >> 1) + 1) * THREAD_RATIO;
+	n = n * (n << 1) * THREAD_RATIO;
 	if (n > MAX_KEYS_PER_CRYPT)
 		n = MAX_KEYS_PER_CRYPT;
 	fmt_NETNTLMv2.params.max_keys_per_crypt = n;
 #endif
-	if (options.utf8) {
-		// in utf-8, up to four bytes can compose one character
-		fmt_NETNTLMv2.params.plaintext_length = UTF8_PLAINTEXT_LEN;
-	}
 }
 
 static int netntlmv2_valid(char *ciphertext, struct fmt_main *pFmt)
@@ -308,20 +283,37 @@ static void netntlmv2_crypt_all(int count)
 	identity_length = challenge[0];
 	challenge_size = (*(challenge + 1 + identity_length + 1) << 8) | *(challenge + 1 + identity_length + 2);
 
+	if (!keys_prepared) {
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+		for (i = 0; i < count; i++) {
+			unsigned char ntlm[16];
+			int len;
+
+			/* Generate 16-byte NTLM hash */
+			len = E_md4hash(saved_plain[i], saved_len[i], ntlm);
+
+			// We do key setup of the next HMAC_MD5 here. rest in inner loop
+			hmac_md5_init_K16(ntlm, &saved_ctx[i]);
+
+			if (len <= 0)
+				saved_plain[i][-len] = 0; // match truncation
+		}
+		keys_prepared = 1;
+	}
+
 #ifdef _OPENMP
-#pragma omp parallel for default(none) private(i, ntlm_v2_hash) shared(count, output, saved_key, challenge, challenge_size, identity_length)
+#pragma omp parallel for default(none) private(i, ntlm_v2_hash) shared(count, output, saved_ctx, challenge, challenge_size, identity_length)
 #endif
 	for(i=0; i<count; i++) {
 		/* Generate 16-byte NTLMv2 Hash */
 		/* HMAC-MD5(Username + Domain, NTLM Hash) */
-#ifdef SPLIT_HMACMD5
 		HMACMD5Context ctx; // can't be moved above the OMP pragma
-		memcpy(&ctx, &saved_key[i], sizeof(ctx));
+		memcpy(&ctx, &saved_ctx[i], sizeof(ctx));
 		hmac_md5_update((unsigned char *)&challenge[1], identity_length, &ctx);
 		hmac_md5_final(ntlm_v2_hash, &ctx);
-#else
-		hmac_md5(saved_key[i], (unsigned char *)&challenge[1], identity_length, ntlm_v2_hash);
-#endif
+
 		/* --- Blob Construction --- */
 
 		/*
@@ -443,28 +435,9 @@ static void netntlmv2_set_salt(void *salt)
 
 static void netntlmv2_set_key(char *key, int index)
 {
-	int len;
-#ifdef SPLIT_HMACMD5
-	unsigned char ntlm[16];
-#endif
-
-	len = strlen(key);
-	memcpy((char *)saved_plain[index], key, len + 1);
-
-#ifdef SPLIT_HMACMD5
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash(saved_plain[index], len, ntlm);
-
-	// We do key setup of the next HMAC_MD5 here. rest in crypt_all()
-	// &saved_key is now &ctx
-	hmac_md5_init_K16(ntlm, &saved_key[index]);
-#else
-	/* Generate 16-byte NTLM hash */
-	len = E_md4hash(saved_plain[index], len, saved_key[index]);
-#endif
-
-	if (len <= 0)
-		saved_plain[index][-len] = 0; // match truncation
+	saved_len[index]= strlen(key);
+	memcpy((char *)saved_plain[index], key, saved_len[index]+ 1);
+	keys_prepared = 0;
 }
 
 static char *netntlmv2_get_key(int index)
diff --git a/src/mskrb5_fmt_plug.c b/src/mskrb5_fmt_plug.c
index e3d3f31..12e183a 100644
--- a/src/mskrb5_fmt_plug.c
+++ b/src/mskrb5_fmt_plug.c
@@ -273,7 +273,7 @@ static void crypt_all(int count)
 	const unsigned char one[] = { 1, 0, 0, 0 };
 	int i;
 
-	if (!keys_prepared)	{
+	if (!keys_prepared) {
 #ifdef _OPENMP
 #pragma omp parallel for
 #endif
-- 
1.7.4.1

