From 1c5a3eb164d434e514e7293c4d5a8adfb28cd8ef Mon Sep 17 00:00:00 2001
From: magnum <magnum>
Date: Tue, 11 Oct 2011 00:28:23 +0200
Subject: [PATCH] j7: sapB/sapG, added OMP and proper hash functions

---
 src/sapB_fmt_plug.c |  304 +++++++++++++++++++++++++++++++--------------------
 src/sapG_fmt_plug.c |  162 +++++++++++++++------------
 2 files changed, 278 insertions(+), 188 deletions(-)

diff --git a/src/sapB_fmt_plug.c b/src/sapB_fmt_plug.c
index 070e0e2..4b61616 100644
--- a/src/sapB_fmt_plug.c
+++ b/src/sapB_fmt_plug.c
@@ -7,7 +7,7 @@
  * (c) x7d8 sap loverz, public domain, btw
  * cheers: see test-cases.
  *
- * sligthly modified by magnum 2011 to support the --encoding option
+ * sligthly modified by magnum 2011 to support OMP and --encoding
  * No rights reserved.
  */
 
@@ -63,25 +63,27 @@ unsigned char bcodeArr[BCODE_ARRAY_LENGTH]=
 #define BINARY_SIZE			8	/* half of md5 */
 
 #define MIN_KEYS_PER_CRYPT		1
-#define MAX_KEYS_PER_CRYPT		1
+#define MAX_KEYS_PER_CRYPT		1920
 
 static struct fmt_tests sapbcode_tests[] = {
  	{"F                                       $E3A65AAA9676060F", "X"},
 	{"JOHNNY                                  $7F7207932E4DE471", "CYBERPUNK"},
 	{"VAN                                     $487A2A40A7BA2258", "HAUSER"},
-	{"ROOT                                    $8366A4E9E6B72CB0", "KID"},
-	{"MAN                                     $9F48E7CE5B184D2E", "u"},
+	{"RoOT                                    $8366A4E9E6B72CB0", "KID"},
+	{"MAN                                     $9F48E7CE5B184D2E", "U"},
 	{"----------------------------------------$08CEDAFED0C750A0", "-------"},
-	{"SAP*                                    $7016BFF7C5472F1B", "MAsTeR"},
+	{"SAP*                                    $7016BFF7C5472F1B", "MASTER"},
 	{"DDIC                                    $C94E2F7DD0178374", "DDIC"},
-	{"DOLLAR$$$---                            $C3413C498C48EB67", "dollar$$$---"},
+	{"dollar$$$---                            $C3413C498C48EB67", "DOLLAR$$$---"},
 	{NULL}
 };
 
-static char saved_key[PLAINTEXT_LENGTH + 1];
-static char crypt_key[BINARY_SIZE];
-static MD5_CTX ctx;
-static char theSalt[SALT_SIZE];
+static char saved_key[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static char crypt_key[MAX_KEYS_PER_CRYPT][BINARY_SIZE];
+static char pwConverted[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH+1];
+static int strlenPW[MAX_KEYS_PER_CRYPT];
+static char unConverted[SALT_SIZE+1];
+static int strlenUN;
 
 static int sapbcode_valid(char *ciphertext, struct fmt_main *pFmt)
 {
@@ -101,33 +103,6 @@ static int sapbcode_valid(char *ciphertext, struct fmt_main *pFmt)
 	return 1;
 }
 
-static void sapbcode_set_salt(void *salt)
-{
-	memcpy(theSalt, salt, SALT_SIZE);
-}
-
-static void sapbcode_set_key(char *key, int index) {
-	strnzcpy(saved_key, key, PLAINTEXT_LENGTH+1);
-}
-
-static char *sapbcode_get_key(int index) {
-	return saved_key;
-}
-
-static int sapbcode_cmp_all(void *binary, int index) {
-	return !memcmp(binary, crypt_key, BINARY_SIZE);
-}
-
-static int sapbcode_cmp_exact(char *source, int count){
-  return 1;
-}
-
-static int sapbcode_cmp_one(void * binary, int index)
-{
-	return sapbcode_cmp_all(binary, index);
-}
-
-
 /*
  * this function is needed to determine the actual size of the salt (==username)
  * theSalt has to point at the beginning of the actual salt. no more checks are done; relies on valid()
@@ -135,9 +110,9 @@ static int sapbcode_cmp_one(void * binary, int index)
  * "strip" the padding (blanks at the end) for the calculation....
  * usernames w/ spaces at the end are not supported (SAP does not support them either)
  */
-int calcActualSaltSize_B(char* theSalt)
+static inline unsigned int calcActualSaltSize_B(char* theSalt)
 {
-    int i;
+	unsigned int i;
 	if (NULL==theSalt)
 		return 0;
 	i=SALT_SIZE-1;
@@ -145,83 +120,116 @@ int calcActualSaltSize_B(char* theSalt)
 	return i+2;
 }
 
-
-#define TEMP_ARRAY_SIZE 4*16
-static void sapbcode_crypt_all(int count) {
-	static unsigned char temp_key[BINARY_SIZE*2];
-	static unsigned char final_key[BINARY_SIZE*2];
-	static char username[SALT_SIZE+1], password[PLAINTEXT_LENGTH+1];
-	static char unConverted[SALT_SIZE+1], pwConverted[PLAINTEXT_LENGTH+1];
-	unsigned int i;
-	unsigned int sum20;
-	int I1, I2;
-	int revI1;
-	int I3;
-	int strlenUN, strlenPW;
-	char destArray[TEMP_ARRAY_SIZE];
-	int I4;
-
+static void sapbcode_set_salt(void *salt)
+{
+	int i;
+	char *theSalt = salt;
 	//username: theSalt (we have to determine the right length...)
-	//password: saved_key
-	strnzcpy(username, theSalt, calcActualSaltSize_B(theSalt)+1);
-	strnzcpy(password, saved_key, PLAINTEXT_LENGTH+1);
-
-  	enc_strupper(password); //only UPPERCASE passwords accepted for BCODE
+	strlenUN = calcActualSaltSize_B(salt);
 
 	//transform...
-	for (i=0; i<strlen(username); i++)
-		unConverted[i]=transtable[ARCH_INDEX(username[i])];
+	for (i=0; i<strlenUN; i++)
+		unConverted[i] = transtable[ARCH_INDEX(theSalt[i])];
 	unConverted[i]='\0';
+}
+
+static void sapbcode_set_key(char *key, int index)
+{
+	int i;
 
-	for (i=0; i<strlen(password); i++)
-		pwConverted[i]=transtable[ARCH_INDEX(password[i])];
-	pwConverted[i]='\0';
+	strnzcpy(saved_key[index], key, PLAINTEXT_LENGTH+1);
+	enc_strupper(saved_key[index]); //only UPPERCASE passwords accepted for BCODE
+
+	strlenPW[index]=strlen(saved_key[index]);
+
+	for (i=0; i<strlenPW[index]; i++)
+		pwConverted[index][i] = transtable[ARCH_INDEX(saved_key[index][i])];
+	pwConverted[index][i]='\0';
+}
+
+static char *sapbcode_get_key(int index) {
+	return saved_key[index];
+}
+
+static int sapbcode_cmp_all(void *binary, int count) {
+	int index;
+	for (index = 0; index < count; index++)
+		if (!memcmp(binary, crypt_key[index], BINARY_SIZE))
+			return 1;
+	return 0;
+}
+
+static int sapbcode_cmp_exact(char *source, int index){
+	return 1;
+}
 
-	MD5_Init(&ctx);
-	MD5_Update(&ctx, pwConverted, strlen(pwConverted));
-	MD5_Update(&ctx, unConverted, strlen(unConverted));
-	MD5_Final(temp_key,&ctx);
+static int sapbcode_cmp_one(void * binary, int index)
+{
+	return !memcmp(binary, crypt_key[index], BINARY_SIZE);
+}
 
-	//some magic in between....yes, #4 is ignored...
-	sum20 = temp_key[5]%4 + temp_key[3]%4 + temp_key[2]%4 + temp_key[1]%4 + temp_key[0]%4 +0x20;
 
+#define TEMP_ARRAY_SIZE 4*16
+static void sapbcode_crypt_all(int count) {
+	int index;
+
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+	for (index = 0; index < count; index++) {
+		unsigned char temp_key[BINARY_SIZE*2];
+		unsigned char final_key[BINARY_SIZE*2];
+		unsigned int i;
+		unsigned int sum20;
+		int I1, I2;
+		int revI1;
+		int I3;
+		char destArray[TEMP_ARRAY_SIZE];
+		int I4;
+		MD5_CTX ctx;
+
+		MD5_Init(&ctx);
+		MD5_Update(&ctx, pwConverted[index], strlenPW[index]);
+		MD5_Update(&ctx, unConverted, strlenUN);
+		MD5_Final(temp_key,&ctx);
+
+		//some magic in between....yes, #4 is ignored...
+		sum20 = temp_key[5]%4 + temp_key[3]%4 + temp_key[2]%4 + temp_key[1]%4 + temp_key[0]%4 + 0x20;
 
-	strlenUN=strlen(username);
-	strlenPW=strlen(password);
-	memset(destArray,0,TEMP_ARRAY_SIZE);
 #define DEFAULT_OFFSET 15
-	I1=0;
-	I2=0;
-	revI1=0;
-	I3=0;
-
-	//now: walld0rf-magic [tm], (c), <g>
-	do {
-		if (I1<strlenPW) {
-			if ((temp_key[DEFAULT_OFFSET+revI1] % 2) != 0)
-				destArray[I2++]=bcodeArr[BCODE_ARRAY_LENGTH+revI1-1];
-			destArray[I2++]=pwConverted[I1++];
-			revI1--;
-		}
-		if (I3<strlenUN)
-			destArray[I2++]=unConverted[I3++];
-
-		I4=I2-I1-I3;
-		I2++;
-		destArray[I2-1]=bcodeArr[I4];
-		I2++;
-	} while (I2<sum20);
-	//end of walld0rf-magic [tm], (c), <g>
-
-	MD5_Init(&ctx);
-	MD5_Update(&ctx, destArray, sum20);
-	MD5_Final(final_key, &ctx);
-
-	for (i=0; i<8; i++)
-		crypt_key[i]=final_key[i+8]^final_key[i];
+		I1 = 0;
+		I2 = 0;
+		revI1 = 0;
+		I3 = 0;
+
+		//now: walld0rf-magic [tm], (c), <g>
+		do {
+			if (I1 < strlenPW[index]) {
+				if ((temp_key[DEFAULT_OFFSET + revI1] % 2) != 0)
+					destArray[I2++] = bcodeArr[BCODE_ARRAY_LENGTH + revI1 - 1];
+				destArray[I2++] = pwConverted[index][I1++];
+				revI1--;
+			}
+			if (I3 < strlenUN)
+				destArray[I2++] = unConverted[I3++];
+
+			I4 = I2 - I1 - I3;
+			I2++;
+			destArray[I2-1] = bcodeArr[I4];
+			destArray[I2++] = 0;
+		} while (I2 < sum20);
+		//end of walld0rf-magic [tm], (c), <g>
+
+		MD5_Init(&ctx);
+		MD5_Update(&ctx, destArray, sum20);
+		MD5_Final(final_key, &ctx);
+
+		for (i = 0; i < 8; i++)
+			crypt_key[index][i] = final_key[i + 8] ^ final_key[i];
+	}
 }
 
-static void * sapbcode_binary(char *ciphertext)
+static void *sapbcode_binary(char *ciphertext)
 {
 	static char realcipher[BINARY_SIZE];
 	int i;
@@ -242,7 +250,7 @@ static void *sapbcode_get_salt(char *ciphertext)
 	return uglyStaticStackSalt;
 }
 
-char *sapbcode_split(char *ciphertext, int index)
+static char *sapbcode_split(char *ciphertext, int index)
 {
 	static char out[CIPHERTEXT_LENGTH + 1];
   	memset(out, 0, CIPHERTEXT_LENGTH + 1);
@@ -251,6 +259,68 @@ char *sapbcode_split(char *ciphertext, int index)
 	return out;
 }
 
+static int binary_hash_0(void *binary)
+{
+	return *(ARCH_WORD_32*)binary & 0xF;
+}
+
+static int binary_hash_1(void *binary)
+{
+	return *(ARCH_WORD_32*)binary & 0xFF;
+}
+
+static int binary_hash_2(void *binary)
+{
+	return *(ARCH_WORD_32*)binary & 0xFFF;
+}
+
+static int binary_hash_3(void *binary)
+{
+	return *(ARCH_WORD_32*)binary & 0xFFFF;
+}
+
+static int binary_hash_4(void *binary)
+{
+	return *(ARCH_WORD_32*)binary & 0xFFFFF;
+}
+
+static int get_hash_0(int index)
+{
+	return *(ARCH_WORD_32*)crypt_key[index] & 0xF;
+}
+
+static int get_hash_1(int index)
+{
+	return *(ARCH_WORD_32*)crypt_key[index] & 0xFF;
+}
+
+static int get_hash_2(int index)
+{
+	return *(ARCH_WORD_32*)crypt_key[index] & 0xFFF;
+}
+
+static int get_hash_3(int index)
+{
+	return *(ARCH_WORD_32*)crypt_key[index] & 0xFFFF;
+}
+
+static int get_hash_4(int index)
+{
+	return *(ARCH_WORD_32*)crypt_key[index] & 0xFFFFF;
+}
+
+// Public domain hash function by DJ Bernstein (salt is a username)
+static int salt_hash(void *salt)
+{
+	unsigned char *s = (unsigned char*)salt;
+	unsigned int hash = 5381;
+
+	while (*s)
+		hash = ((hash << 5) + hash) ^ *s++;
+
+	return hash & (SALT_HASH_SIZE - 1);
+}
+
 struct fmt_main fmt_sapB = {
 	{
 		FORMAT_LABEL,
@@ -263,7 +333,7 @@ struct fmt_main fmt_sapB = {
 		SALT_SIZE,
 		MIN_KEYS_PER_CRYPT,
 		MAX_KEYS_PER_CRYPT,
-		FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE,
+		FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE | FMT_OMP,
 		sapbcode_tests
 	}, {
 		fmt_default_init,
@@ -273,24 +343,24 @@ struct fmt_main fmt_sapB = {
 		sapbcode_binary,
 		sapbcode_get_salt,
 		{
-			fmt_default_binary_hash,
-			fmt_default_binary_hash,
-			fmt_default_binary_hash,
-			fmt_default_binary_hash,
-			fmt_default_binary_hash
+			binary_hash_0,
+			binary_hash_1,
+			binary_hash_2,
+			binary_hash_3,
+			binary_hash_4
 		},
-		fmt_default_salt_hash,
+		salt_hash,
 		sapbcode_set_salt,
 		sapbcode_set_key,
 		sapbcode_get_key,
 		fmt_default_clear_keys,
 		sapbcode_crypt_all,
 		{
-			fmt_default_get_hash,
-			fmt_default_get_hash,
-			fmt_default_get_hash,
-			fmt_default_get_hash,
-			fmt_default_get_hash
+			get_hash_0,
+			get_hash_1,
+			get_hash_2,
+			get_hash_3,
+			get_hash_4
 		},
 		sapbcode_cmp_all,
 		sapbcode_cmp_one,
diff --git a/src/sapG_fmt_plug.c b/src/sapG_fmt_plug.c
index 785953a..c817fd2 100644
--- a/src/sapG_fmt_plug.c
+++ b/src/sapG_fmt_plug.c
@@ -7,7 +7,7 @@
  * (c) x7d8 sap loverz, public domain, btw
  * cheers: see test-cases.
  *
- * sligthly modified by magnum 2011 to support the --encoding option.
+ * sligthly modified by magnum 2011 to support OMP and --encoding.
  * No rights reserved.
  */
 
@@ -51,7 +51,7 @@ unsigned char theMagicArray[MAGIC_ARRAY_SIZE]=
 #define CIPHERTEXT_LENGTH		SALT_SIZE + 1 + 40	/* SALT + $ + 2x20 bytes for SHA1-representation */
 
 #define MIN_KEYS_PER_CRYPT		1
-#define MAX_KEYS_PER_CRYPT		1
+#define MAX_KEYS_PER_CRYPT		1920
 
 
 static struct fmt_tests sapcodvng_tests[] = {
@@ -67,14 +67,13 @@ static struct fmt_tests sapcodvng_tests[] = {
 	{NULL}
 };
 
-static char saved_key[PLAINTEXT_LENGTH + 1];
-static UTF8 trPassword[PLAINTEXT_LENGTH + 1];
-static size_t pwLen;
-static ARCH_WORD_32 crypt_key[BINARY_SIZE / 4];
-static SHA_CTX ctx;
+static char saved_key[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static UTF8 trPassword[MAX_KEYS_PER_CRYPT][PLAINTEXT_LENGTH + 1];
+static int pwLen[MAX_KEYS_PER_CRYPT];
+static ARCH_WORD_32 crypt_key[MAX_KEYS_PER_CRYPT][BINARY_SIZE / 4];
 
 static char theSalt[SALT_SIZE];
-static size_t unLen;
+static unsigned int unLen;
 
 static int sapcodvng_valid(char *ciphertext, struct fmt_main *pFmt)
 {
@@ -107,9 +106,9 @@ static int sapcodvng_valid(char *ciphertext, struct fmt_main *pFmt)
  * "strip" the padding (blanks at the end) for the calculation....
  * usernames w/ spaces at the end are not supported (SAP does not support them either)
  */
-int calcActualSaltSize_G(char* theSalt)
+static inline unsigned int calcActualSaltSize_G(const char* theSalt)
 {
-    int i;
+	unsigned int i;
 	if (NULL==theSalt)
 		return 0;
 	i=SALT_SIZE-1;
@@ -120,7 +119,7 @@ int calcActualSaltSize_G(char* theSalt)
 static void sapcodvng_set_salt(void *salt)
 {
 	memcpy(theSalt, salt, SALT_SIZE);
-	unLen=calcActualSaltSize_G(theSalt);
+	unLen = calcActualSaltSize_G(theSalt);
 }
 
 static void *sapcodvng_get_salt(char *ciphertext)
@@ -135,44 +134,36 @@ static void sapcodvng_init(struct fmt_main *pFmt)
 
 static void sapcodvng_set_key(char *key, int index)
 {
-	strnzcpy(saved_key, key, PLAINTEXT_LENGTH + 1);
-	if (options.utf8 || options.ascii)
-		strnzcpy((char*)trPassword, key, PLAINTEXT_LENGTH + 1);
-	else {
-		// convert from codepage -> Unicode -> UTF-8
-		UTF16 tmp16[PLAINTEXT_LENGTH + 1];
-#if ARCH_LITTLE_ENDIAN
-		enc_to_utf16(tmp16, PLAINTEXT_LENGTH + 1, (UTF8*)key, strlen(key));
-#else
-		enc_to_utf16_be(tmp16, PLAINTEXT_LENGTH + 1, (UTF8*)key, strlen(key));
-#endif
-		utf16_to_utf8_r(trPassword, PLAINTEXT_LENGTH + 1, tmp16);
-	}
-	pwLen=strlen((char*)trPassword);
+	strnzcpy(saved_key[index], key, PLAINTEXT_LENGTH + 1);
+	pwLen[index] = -1;
 }
 
 static char *sapcodvng_get_key(int index) {
-	return saved_key;
+	return saved_key[index];
 }
 
-static int sapcodvng_cmp_all(void *binary, int index) {
-	return !memcmp(binary, crypt_key, BINARY_SIZE);
+static int sapcodvng_cmp_all(void *binary, int count) {
+	unsigned int index;
+	for (index = 0; index < count; index++)
+		if (!memcmp(binary, crypt_key[index], BINARY_SIZE))
+			return 1;
+	return 0;
 }
 
-static int sapcodvng_cmp_exact(char *source, int count){
-  return (1);
+static int sapcodvng_cmp_exact(char *source, int index){
+	return 1;
 }
 
-static int sapcodvng_cmp_one(void * binary, int index)
+static int sapcodvng_cmp_one(void *binary, int index)
 {
-	return sapcodvng_cmp_all(binary, index);
+	return !memcmp(binary, crypt_key[index], BINARY_SIZE);
 }
 
 /*
  * calculate the length of data that has to be hashed from the magic array. pass the first hash result in here.
  * this is part of the walld0rf-magic
  */
-unsigned int extractLengthOfMagicArray(unsigned char *pbHashArray)
+static inline unsigned int extractLengthOfMagicArray(unsigned const char *pbHashArray)
 {
 	unsigned int modSum=0, i;
 
@@ -186,7 +177,7 @@ unsigned int extractLengthOfMagicArray(unsigned char *pbHashArray)
  * Calculate the offset into the magic array. pass the first hash result in here
  * part of the walld0rf-magic
  */
-unsigned int extractOffsetToMagicArray(unsigned char *pbHashArray)
+static inline unsigned int extractOffsetToMagicArray(unsigned const char *pbHashArray)
 {
 	unsigned int modSum=0, i;
 
@@ -197,36 +188,56 @@ unsigned int extractOffsetToMagicArray(unsigned char *pbHashArray)
 }
 
 static void sapcodvng_crypt_all(int count) {
-	char temp_key[BINARY_SIZE+1];
-	unsigned int offsetMagicArray;
-	unsigned int lengthIntoMagicArray;
-	unsigned char secondHashData[PLAINTEXT_LENGTH*2+MAGIC_ARRAY_SIZE]; //max size...
-	size_t secondHashDataLen;
-	char tempVar[PLAINTEXT_LENGTH*2]; 	//PLAINTEXT_LENGTH is maxlen of password AND maxlen of username
-
-	//1.	we need to SHA1 the password and username
-	strnzcpy(tempVar, (char*)trPassword, PLAINTEXT_LENGTH);  //first: the password
-	strnzcpy(tempVar+strlen(tempVar), theSalt, unLen+1); //second: the salt(username)
-
-	SHA1_Init(&ctx);
-	SHA1_Update(&ctx, (unsigned char*)tempVar, strlen(tempVar));
-	SHA1_Final((unsigned char*)&temp_key, &ctx);
-
-	lengthIntoMagicArray=extractLengthOfMagicArray((unsigned char*)temp_key);
-	offsetMagicArray=extractOffsetToMagicArray((unsigned char*)temp_key);
-
-	//2.     now, hash again --> sha1($password+$partOfMagicArray+$username) --> this is CODVNG passcode...
-	memcpy(secondHashData, trPassword, pwLen);
-	memcpy(secondHashData+pwLen, &theMagicArray[offsetMagicArray], lengthIntoMagicArray);
-	memcpy(secondHashData+pwLen+lengthIntoMagicArray, theSalt, unLen+1);
-	secondHashDataLen=pwLen+lengthIntoMagicArray+unLen;
-
-	SHA1_Init(&ctx);
-	SHA1_Update(&ctx, secondHashData, secondHashDataLen);
-	SHA1_Final((unsigned char*)crypt_key, &ctx);
+	unsigned int i;
+
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+	for (i = 0; i < count; i++) {
+		unsigned char temp_key[BINARY_SIZE+1];
+		unsigned int offsetMagicArray;
+		unsigned int lengthIntoMagicArray;
+		unsigned char tempVar[PLAINTEXT_LENGTH+MAGIC_ARRAY_SIZE+SALT_SIZE]; //max size...
+		SHA_CTX ctx;
+
+		if (pwLen[i] < 0) {
+			if (options.utf8 || options.ascii)
+				strnzcpy((char*)trPassword[i], saved_key[i], PLAINTEXT_LENGTH + 1);
+			else {
+				// convert from codepage -> Unicode -> UTF-8
+				UTF16 tmp16[PLAINTEXT_LENGTH + 1];
+#if ARCH_LITTLE_ENDIAN
+				enc_to_utf16(tmp16, PLAINTEXT_LENGTH + 1, (UTF8*)saved_key[i], strlen(saved_key[i]));
+#else
+				enc_to_utf16_be(tmp16, PLAINTEXT_LENGTH + 1, (UTF8*)saved_key[i], strlen(saved_key[i]));
+#endif
+				utf16_to_utf8_r(trPassword[i], PLAINTEXT_LENGTH + 1, tmp16);
+			}
+			pwLen[i] = strlen((char*)trPassword[i]);
+		}
+
+		//1.	we need to SHA1 the password and username
+		memcpy(tempVar, trPassword[i], pwLen[i]);  //first: the password
+		memcpy(tempVar+pwLen[i], theSalt, unLen); //second: the salt(username)
+
+		SHA1_Init(&ctx);
+		SHA1_Update(&ctx, tempVar, pwLen[i] + unLen);
+		SHA1_Final((unsigned char*)temp_key, &ctx);
+
+		lengthIntoMagicArray=extractLengthOfMagicArray(temp_key);
+		offsetMagicArray=extractOffsetToMagicArray(temp_key);
+
+		//2.     now, hash again --> sha1($password+$partOfMagicArray+$username) --> this is CODVNG passcode...
+		memcpy(tempVar+pwLen[i], &theMagicArray[offsetMagicArray], lengthIntoMagicArray);
+		memcpy(tempVar+pwLen[i]+lengthIntoMagicArray, theSalt, unLen);
+
+		SHA1_Init(&ctx);
+		SHA1_Update(&ctx, tempVar, pwLen[i]+lengthIntoMagicArray+unLen);
+		SHA1_Final((unsigned char*)crypt_key[i], &ctx);
+	}
 }
 
-static void * sapcodvng_binary(char *ciphertext)
+static void *sapcodvng_binary(char *ciphertext)
 {
 	static char *realcipher;
 	int i;
@@ -241,7 +252,6 @@ static void * sapcodvng_binary(char *ciphertext)
 	return (void *)realcipher;
 }
 
-
 static int binary_hash_0(void *binary)
 {
 	return ((ARCH_WORD_32 *)binary)[0] & 0xF;
@@ -269,29 +279,40 @@ static int binary_hash_4(void *binary)
 
 static int get_hash_0(int index)
 {
-	return crypt_key[0] & 0xF;
+	return crypt_key[index][0] & 0xF;
 }
 
 static int get_hash_1(int index)
 {
-	return crypt_key[0] & 0xFF;
+	return crypt_key[index][0] & 0xFF;
 }
 
 static int get_hash_2(int index)
 {
-	return crypt_key[0] & 0xFFF;
+	return crypt_key[index][0] & 0xFFF;
 }
 
 static int get_hash_3(int index)
 {
-	return crypt_key[0] & 0xFFFF;
+	return crypt_key[index][0] & 0xFFFF;
 }
 
 static int get_hash_4(int index)
 {
-	return crypt_key[0] & 0xFFFFF;
+	return crypt_key[index][0] & 0xFFFFF;
 }
 
+// Public domain hash function by DJ Bernstein (salt is a username)
+static int salt_hash(void *salt)
+{
+	unsigned char *s = (unsigned char*)salt;
+	unsigned int hash = 5381;
+
+	while (*s)
+		hash = ((hash << 5) + hash) ^ *s++;
+
+	return hash & (SALT_HASH_SIZE - 1);
+}
 
 char *sapcodvng_split(char *ciphertext, int index)
 {
@@ -302,7 +323,6 @@ char *sapcodvng_split(char *ciphertext, int index)
 	return out;
 }
 
-
 struct fmt_main fmt_sapG = {
 	{
 		FORMAT_LABEL,
@@ -315,7 +335,7 @@ struct fmt_main fmt_sapG = {
 		SALT_SIZE,
 		MIN_KEYS_PER_CRYPT,
 		MAX_KEYS_PER_CRYPT,
-		FMT_CASE | FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE | FMT_UTF8,
+		FMT_CASE | FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE | FMT_UTF8 | FMT_OMP,
 		sapcodvng_tests
 	}, {
 		sapcodvng_init,
@@ -331,7 +351,7 @@ struct fmt_main fmt_sapG = {
 			binary_hash_3,
 			binary_hash_4
 		},
-		fmt_default_salt_hash,
+		salt_hash,
 		sapcodvng_set_salt,
 		sapcodvng_set_key,
 		sapcodvng_get_key,
-- 
1.7.4.1

