]> git.sesse.net Git - freerainbowtables/commitdiff
rcracki_mt updated to rti2
authorMartin Westergaard Jorgensen <martinwj2005@gmail.com>
Tue, 18 Aug 2009 06:40:30 +0000 (08:40 +0200)
committerMartin Westergaard Jorgensen <martinwj2005@gmail.com>
Tue, 18 Aug 2009 06:40:30 +0000 (08:40 +0200)
44 files changed:
Client Applications/rcracki_mt/BaseRTReader.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/BaseRTReader.h [new file with mode: 0644]
Client Applications/rcracki_mt/ChainWalkContext.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/ChainWalkContext.h [new file with mode: 0644]
Client Applications/rcracki_mt/ChainWalkSet.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/ChainWalkSet.h [new file with mode: 0644]
Client Applications/rcracki_mt/ChangeLog.txt [new file with mode: 0644]
Client Applications/rcracki_mt/CrackEngine.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/CrackEngine.h [new file with mode: 0644]
Client Applications/rcracki_mt/HashAlgorithm.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/HashAlgorithm.h [new file with mode: 0644]
Client Applications/rcracki_mt/HashRoutine.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/HashRoutine.h [new file with mode: 0644]
Client Applications/rcracki_mt/HashSet.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/HashSet.h [new file with mode: 0644]
Client Applications/rcracki_mt/Makefile [new file with mode: 0644]
Client Applications/rcracki_mt/MemoryPool.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/MemoryPool.h [new file with mode: 0644]
Client Applications/rcracki_mt/Public.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/Public.h [new file with mode: 0644]
Client Applications/rcracki_mt/README.txt [new file with mode: 0644]
Client Applications/rcracki_mt/RTI2Reader.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/RTI2Reader.h [new file with mode: 0644]
Client Applications/rcracki_mt/RainbowCrack.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/charset.txt [new file with mode: 0644]
Client Applications/rcracki_mt/fast_md5.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/fast_md5.h [new file with mode: 0644]
Client Applications/rcracki_mt/libeay32.dll [new file with mode: 0644]
Client Applications/rcracki_mt/libeay32.lib [new file with mode: 0644]
Client Applications/rcracki_mt/lm2ntlm.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/lm2ntlm.h [new file with mode: 0644]
Client Applications/rcracki_mt/md4.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/md4.h [new file with mode: 0644]
Client Applications/rcracki_mt/pthreadVC2.dll [new file with mode: 0644]
Client Applications/rcracki_mt/pthreadVC2.lib [new file with mode: 0644]
Client Applications/rcracki_mt/rcrackiThread.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/rcrackiThread.h [new file with mode: 0644]
Client Applications/rcracki_mt/rcracki_mt.exe [new file with mode: 0644]
Client Applications/rcracki_mt/rcracki_mt.ini [new file with mode: 0644]
Client Applications/rcracki_mt/rcracki_mt.sln [new file with mode: 0644]
Client Applications/rcracki_mt/rcracki_mt.suo [new file with mode: 0644]
Client Applications/rcracki_mt/rcracki_mt.vcproj [new file with mode: 0644]
Client Applications/rcracki_mt/sha1.cpp [new file with mode: 0644]
Client Applications/rcracki_mt/sha1.h [new file with mode: 0644]

diff --git a/Client Applications/rcracki_mt/BaseRTReader.cpp b/Client Applications/rcracki_mt/BaseRTReader.cpp
new file mode 100644 (file)
index 0000000..d762e26
--- /dev/null
@@ -0,0 +1,2 @@
+#include "BaseRTReader.h"
+
diff --git a/Client Applications/rcracki_mt/BaseRTReader.h b/Client Applications/rcracki_mt/BaseRTReader.h
new file mode 100644 (file)
index 0000000..4dbaf86
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __BASERTREADER_H__
+#define __BASERTREADER_H__
+
+#include "Public.h"
+#include <string>
+#ifdef WIN32
+#include <io.h>
+#endif
+using namespace std;
+
+class BaseRTReader
+{
+public:
+       virtual int ReadChains(unsigned int &numChains, RainbowChainO *pData) = 0;
+       virtual unsigned int GetChainsLeft() = 0;
+       
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/ChainWalkContext.cpp b/Client Applications/rcracki_mt/ChainWalkContext.cpp
new file mode 100644 (file)
index 0000000..f6e24b3
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "ChainWalkContext.h"
+
+#include <ctype.h>
+
+//////////////////////////////////////////////////////////////////////
+
+string CChainWalkContext::m_sHashRoutineName;
+HASHROUTINE CChainWalkContext::m_pHashRoutine;
+int CChainWalkContext::m_nHashLen;
+int CChainWalkContext::m_nPlainLenMinTotal = 0;
+int CChainWalkContext::m_nPlainLenMaxTotal = 0;
+int CChainWalkContext::m_nHybridCharset = 0;
+bool CChainWalkContext::isOldRtFormat = false;
+bool CChainWalkContext::isNewRtFormat = false;
+vector<stCharset> CChainWalkContext::m_vCharset;
+uint64 CChainWalkContext::m_nPlainSpaceUpToX[MAX_PLAIN_LEN + 1];
+uint64 CChainWalkContext::m_nPlainSpaceTotal;
+unsigned char CChainWalkContext::m_Salt[MAX_SALT_LEN];
+int CChainWalkContext::m_nSaltLen = 0;
+int CChainWalkContext::m_nRainbowTableIndex;
+uint64 CChainWalkContext::m_nReduceOffset;
+
+//////////////////////////////////////////////////////////////////////
+
+CChainWalkContext::CChainWalkContext()
+{
+}
+
+CChainWalkContext::~CChainWalkContext()
+{
+}
+
+bool CChainWalkContext::LoadCharset(string sName)
+{
+       m_vCharset.clear();
+       if (sName == "byte")
+       {
+               stCharset tCharset;
+               int i;
+               for (i = 0x00; i <= 0xff; i++)
+                       tCharset.m_PlainCharset[i] = i;
+               tCharset.m_nPlainCharsetLen = 256;
+               tCharset.m_sPlainCharsetName = sName;
+               tCharset.m_sPlainCharsetContent = "0x00, 0x01, ... 0xff";
+               m_vCharset.push_back(tCharset);
+               return true;
+       }
+       if(sName.substr(0, 6) == "hybrid") // Hybrid charset consisting of 2 charsets
+       {
+               m_nHybridCharset = 1;           
+       }
+       else
+       {
+               m_nHybridCharset = 0;
+       }
+       
+       bool readCharset = false;
+       vector<string> vLine;
+       if (ReadLinesFromFile("charset.txt", vLine)) {
+               readCharset = true;
+       }
+       else if (ReadLinesFromFile(GetApplicationPath() + "charset.txt", vLine)) {
+               readCharset = true;
+       }
+       if (readCharset)
+       {
+               int i;
+               for (i = 0; i < vLine.size(); i++)
+               {
+                       // Filter comment
+                       if (vLine[i][0] == '#')
+                               continue;
+
+                       vector<string> vPart;
+                       if (SeperateString(vLine[i], "=", vPart))
+                       {
+                               // sCharsetName
+                               string sCharsetName = TrimString(vPart[0]);
+                               if (sCharsetName == "")
+                                       continue;
+                                                               
+                               // sCharsetName charset check
+                               bool fCharsetNameCheckPass = true;
+                               int j;
+                               for (j = 0; j < sCharsetName.size(); j++)
+                               {
+                                       if (   !isalpha(sCharsetName[j])
+                                               && !isdigit(sCharsetName[j])
+                                               && (sCharsetName[j] != '-'))
+                                       {
+                                               fCharsetNameCheckPass = false;
+                                               break;
+                                       }
+                               }
+                               if (!fCharsetNameCheckPass)
+                               {
+                                       printf("invalid charset name %s in charset configuration file\n", sCharsetName.c_str());
+                                       continue;
+                               }
+
+                               // sCharsetContent
+                               string sCharsetContent = TrimString(vPart[1]);
+                               if (sCharsetContent == "" || sCharsetContent == "[]")
+                                       continue;
+                               if (sCharsetContent[0] != '[' || sCharsetContent[sCharsetContent.size() - 1] != ']')
+                               {
+                                       printf("invalid charset content %s in charset configuration file\n", sCharsetContent.c_str());
+                                       continue;
+                               }
+                               sCharsetContent = sCharsetContent.substr(1, sCharsetContent.size() - 2);
+                               if (sCharsetContent.size() > 256)
+                               {
+                                       printf("charset content %s too long\n", sCharsetContent.c_str());
+                                       continue;
+                               }
+
+                               //printf("%s = [%s]\n", sCharsetName.c_str(), sCharsetContent.c_str());
+
+                               // Is it the wanted charset?
+                               if(m_nHybridCharset == 1)
+                               {
+                                       vector<tCharset> vCharsets;
+                                       GetHybridCharsets(sName, vCharsets);
+                                       if(sCharsetName == vCharsets[m_vCharset.size()].sName)
+                                       {
+                                               stCharset tCharset = {0};
+                                               tCharset.m_nPlainCharsetLen = sCharsetContent.size();                                                   
+                                               memcpy(tCharset.m_PlainCharset, sCharsetContent.c_str(), tCharset.m_nPlainCharsetLen);
+                                               tCharset.m_sPlainCharsetName = sCharsetName;
+                                               tCharset.m_sPlainCharsetContent = sCharsetContent;      
+                                               tCharset.m_nPlainLenMin = vCharsets[m_vCharset.size()].nPlainLenMin;
+                                               tCharset.m_nPlainLenMax = vCharsets[m_vCharset.size()].nPlainLenMax;
+                                               m_vCharset.push_back(tCharset);
+                                               if(vCharsets.size() == m_vCharset.size())
+                                                       return true;
+                                               i = 0; // Start the lookup over again for the next charset
+                                       }                                               
+                               }
+                               else if (sCharsetName == sName)
+                               {
+                                       stCharset tCharset;
+                                       tCharset.m_nPlainCharsetLen = sCharsetContent.size();                                                   
+                                       memcpy(tCharset.m_PlainCharset, sCharsetContent.c_str(), tCharset.m_nPlainCharsetLen);
+                                       tCharset.m_sPlainCharsetName = sCharsetName;
+                                       tCharset.m_sPlainCharsetContent = sCharsetContent;                                                      
+                                       m_vCharset.push_back(tCharset);
+                                       return true;
+                               }
+                       }
+               }
+               printf("charset %s not found in charset.txt\n", sName.c_str());
+       }
+       else
+               printf("can't open charset configuration file\n");
+       return false;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+bool CChainWalkContext::SetHashRoutine(string sHashRoutineName)
+{
+       CHashRoutine hr;
+       hr.GetHashRoutine(sHashRoutineName, m_pHashRoutine, m_nHashLen);
+       if (m_pHashRoutine != NULL)
+       {
+               m_sHashRoutineName = sHashRoutineName;
+               return true;
+       }
+       else
+               return false;
+}
+
+bool CChainWalkContext::SetPlainCharset(string sCharsetName, int nPlainLenMin, int nPlainLenMax)
+{
+       // m_PlainCharset, m_nPlainCharsetLen, m_sPlainCharsetName, m_sPlainCharsetContent
+       if (!LoadCharset(sCharsetName))
+               return false;
+
+       if(m_vCharset.size() == 1) // Not hybrid charset
+       {
+               // m_nPlainLenMin, m_nPlainLenMax
+               if (nPlainLenMin < 1 || nPlainLenMax > MAX_PLAIN_LEN || nPlainLenMin > nPlainLenMax)
+               {
+                       printf("invalid plaintext length range: %d - %d\n", nPlainLenMin, nPlainLenMax);
+                       return false;
+               }
+               m_vCharset[0].m_nPlainLenMin = nPlainLenMin;
+               m_vCharset[0].m_nPlainLenMax = nPlainLenMax;
+       }
+       // m_nPlainSpaceUpToX
+       m_nPlainSpaceUpToX[0] = 0;
+       m_nPlainLenMaxTotal = 0;
+       m_nPlainLenMinTotal = 0;
+       uint64 nTemp = 1;
+       int j, k = 1;
+       for(j = 0; j < m_vCharset.size(); j++)
+       {
+               int i;
+               m_nPlainLenMaxTotal += m_vCharset[j].m_nPlainLenMax;
+               m_nPlainLenMinTotal += m_vCharset[j].m_nPlainLenMin;
+               for (i = 1; i <= m_vCharset[j].m_nPlainLenMax; i++)
+               {                       
+                       nTemp *= m_vCharset[j].m_nPlainCharsetLen;
+                       if (i < m_vCharset[j].m_nPlainLenMin)
+                               m_nPlainSpaceUpToX[k] = 0;
+                       else
+                               m_nPlainSpaceUpToX[k] = m_nPlainSpaceUpToX[k - 1] + nTemp;
+                       k++;
+               }               
+       }
+       // m_nPlainSpaceTotal
+       m_nPlainSpaceTotal = m_nPlainSpaceUpToX[m_nPlainLenMaxTotal];
+
+       return true;
+}
+
+bool CChainWalkContext::SetRainbowTableIndex(int nRainbowTableIndex)
+{
+       if (nRainbowTableIndex < 0)
+               return false;
+       m_nRainbowTableIndex = nRainbowTableIndex;
+       m_nReduceOffset = 65536 * nRainbowTableIndex;
+
+       return true;
+}
+
+bool CChainWalkContext::SetSalt(unsigned char *Salt, int nSaltLength)
+{
+       memcpy(&m_Salt[0], Salt, nSaltLength);
+       
+       m_nSaltLen = nSaltLength;
+//     m_sSalt = sSalt;
+       return true;
+}
+
+bool CChainWalkContext::SetupWithPathName(string sPathName, int& nRainbowChainLen, int& nRainbowChainCount)
+{
+       // something like lm_alpha#1-7_0_100x16_test.rt
+
+#ifdef _WIN32
+       int nIndex = sPathName.find_last_of('\\');
+#else
+       int nIndex = sPathName.find_last_of('/');
+#endif
+       if (nIndex != -1)
+               sPathName = sPathName.substr(nIndex + 1);
+
+       if (sPathName.size() < 3)
+       {
+               printf("%s is not a rainbow table\n", sPathName.c_str());
+               return false;
+       }
+       if (sPathName.substr(sPathName.size() - 5) == ".rti2")
+       {
+               isNewRtFormat = true;
+       }
+       else if (sPathName.substr(sPathName.size() - 4) == ".rti")
+       {
+               isOldRtFormat = false;
+       }
+       else if (sPathName.substr(sPathName.size() - 3) == ".rt")
+       {
+               isOldRtFormat = true;
+       }
+       else
+       {
+               printf("%s is not a rainbow table\n", sPathName.c_str());
+               return false;
+       }
+
+       // Parse
+       vector<string> vPart;
+       if (!SeperateString(sPathName, "___x_", vPart))
+       {
+               printf("filename %s not identified\n", sPathName.c_str());
+               return false;
+       }
+
+       string sHashRoutineName   = vPart[0];
+       int nRainbowTableIndex    = atoi(vPart[2].c_str());
+       nRainbowChainLen          = atoi(vPart[3].c_str());
+       nRainbowChainCount        = atoi(vPart[4].c_str());
+
+       // Parse charset definition
+       string sCharsetDefinition = vPart[1];
+       string sCharsetName;
+       int nPlainLenMin = 0, nPlainLenMax = 0;         
+
+//     printf("Charset: %s", sCharsetDefinition.c_str());
+       
+       if(sCharsetDefinition.substr(0, 6) == "hybrid") // Hybrid table
+       {
+               sCharsetName = sCharsetDefinition;
+       }
+       else
+       {
+               if (sCharsetDefinition.find('#') == -1)         // For backward compatibility, "#1-7" is implied
+               {                       
+                       sCharsetName = sCharsetDefinition;
+                       nPlainLenMin = 1;
+                       nPlainLenMax = 7;
+               }
+               else
+               {
+                       vector<string> vCharsetDefinitionPart;
+                       if (!SeperateString(sCharsetDefinition, "#-", vCharsetDefinitionPart))
+                       {
+                               printf("filename %s not identified\n", sPathName.c_str());
+                               return false;   
+                       }
+                       else
+                       {
+                               sCharsetName = vCharsetDefinitionPart[0];
+                               nPlainLenMin = atoi(vCharsetDefinitionPart[1].c_str());
+                               nPlainLenMax = atoi(vCharsetDefinitionPart[2].c_str());
+                       }
+               }
+       }
+       // Setup
+       if (!SetHashRoutine(sHashRoutineName))
+       {
+               printf("hash routine %s not supported\n", sHashRoutineName.c_str());
+               return false;
+       }
+       if (!SetPlainCharset(sCharsetName, nPlainLenMin, nPlainLenMax))
+               return false;
+       if (!SetRainbowTableIndex(nRainbowTableIndex))
+       {
+               printf("invalid rainbow table index %d\n", nRainbowTableIndex);
+               return false;
+       }
+       m_nPlainSpaceTotal = m_nPlainSpaceUpToX[m_nPlainLenMaxTotal];
+       return true;
+}
+
+string CChainWalkContext::GetHashRoutineName()
+{
+       return m_sHashRoutineName;
+}
+
+int CChainWalkContext::GetHashLen()
+{
+       return m_nHashLen;
+}
+
+string CChainWalkContext::GetPlainCharsetName()
+{
+       return m_vCharset[0].m_sPlainCharsetName;
+}
+
+string CChainWalkContext::GetPlainCharsetContent()
+{
+       return m_vCharset[0].m_sPlainCharsetContent;
+}
+
+int CChainWalkContext::GetPlainLenMin()
+{
+       return m_vCharset[0].m_nPlainLenMin;
+}
+
+int CChainWalkContext::GetPlainLenMax()
+{
+       return m_vCharset[0].m_nPlainLenMax;
+}
+
+uint64 CChainWalkContext::GetPlainSpaceTotal()
+{
+       return m_nPlainSpaceTotal;
+}
+
+int CChainWalkContext::GetRainbowTableIndex()
+{
+       return m_nRainbowTableIndex;
+}
+
+void CChainWalkContext::Dump()
+{
+       printf("hash routine: %s\n", m_sHashRoutineName.c_str());
+       printf("hash length: %d\n", m_nHashLen);
+
+       printf("plain charset: ");
+       int i;
+       for (i = 0; i < m_vCharset[0].m_nPlainCharsetLen; i++)
+       {
+               if (isprint(m_vCharset[0].m_PlainCharset[i]))
+                       printf("%c", m_vCharset[0].m_PlainCharset[i]);
+               else
+                       printf("?");
+       }
+       printf("\n");
+
+       printf("plain charset in hex: ");
+       for (i = 0; i < m_vCharset[0].m_nPlainCharsetLen; i++)
+               printf("%02x ", m_vCharset[0].m_PlainCharset[i]);
+       printf("\n");
+
+       printf("plain length range: %d - %d\n", m_vCharset[0].m_nPlainLenMin, m_vCharset[0].m_nPlainLenMax);
+       printf("plain charset name: %s\n", m_vCharset[0].m_sPlainCharsetName.c_str());
+       //printf("plain charset content: %s\n", m_sPlainCharsetContent.c_str());
+       //for (i = 0; i <= m_nPlainLenMax; i++)
+       //      printf("plain space up to %d: %s\n", i, uint64tostr(m_nPlainSpaceUpToX[i]).c_str());
+       printf("plain space total: %s\n", uint64tostr(m_nPlainSpaceTotal).c_str());
+
+       printf("rainbow table index: %d\n", m_nRainbowTableIndex);
+       printf("reduce offset: %s\n", uint64tostr(m_nReduceOffset).c_str());
+       printf("\n");
+}
+
+
+void CChainWalkContext::SetIndex(uint64 nIndex)
+{
+       m_nIndex = nIndex;
+}
+
+void CChainWalkContext::SetHash(unsigned char* pHash)
+{
+       memcpy(m_Hash, pHash, m_nHashLen);
+}
+
+void CChainWalkContext::IndexToPlain()
+{
+       int i;
+       m_nPlainLen = 0;
+       for (i = m_nPlainLenMaxTotal - 1; i >= m_nPlainLenMinTotal - 1; i--)
+       {
+               if (m_nIndex >= m_nPlainSpaceUpToX[i])
+               {
+                       m_nPlainLen = i + 1;
+                       break;
+               }
+       }
+       if(m_nPlainLen == 0)
+               m_nPlainLen = m_nPlainLenMinTotal;
+       uint64 nIndexOfX = m_nIndex - m_nPlainSpaceUpToX[m_nPlainLen - 1];
+
+// maybe this code should be used for some other 64 bit systems as well, added check for LP64 to try this
+#if defined(_WIN64) || defined(_LP64)
+       
+       // Slow version
+       for (i = m_nPlainLen - 1; i >= 0; i--)
+       {
+               int nCharsetLen = 0;
+               for(int j = 0; j < m_vCharset.size(); i++)
+               {
+                       nCharsetLen += m_vCharset[j].m_nPlainLenMax;
+                       if(i < nCharsetLen) // We found the correct charset
+                       {
+                               m_Plain[i] = m_vCharset[j].m_PlainCharset[nIndexOfX % m_nPlainCharsetLen];
+                               nIndexOfX /= m_vCharset[j].m_nPlainCharsetLen;
+                       }
+               }
+       }
+#else
+
+
+       // Fast version
+       for (i = m_nPlainLen - 1; i >= 0; i--)
+       {
+#ifdef _WIN32
+               if (nIndexOfX < 0x100000000I64)
+                       break;
+#else
+               if (nIndexOfX < 0x100000000llu)
+                       break;
+#endif
+               int nCharsetLen = 0;
+               for(int j = 0; j < m_vCharset.size(); j++)
+               {
+                       nCharsetLen += m_vCharset[j].m_nPlainLenMax;
+                       if(i < nCharsetLen) // We found the correct charset
+                       {
+                               m_Plain[i] = m_vCharset[j].m_PlainCharset[nIndexOfX % m_vCharset[j].m_nPlainCharsetLen];
+                               nIndexOfX /= m_vCharset[j].m_nPlainCharsetLen;
+                               break;
+                       }
+               }
+       }
+
+       unsigned int nIndexOfX32 = (unsigned int)nIndexOfX;
+       for (; i >= 0; i--)
+       {
+               int nCharsetLen = 0;
+               for(int j = 0; j < m_vCharset.size(); j++)
+               {
+                       nCharsetLen += m_vCharset[j].m_nPlainLenMax;
+                       if(i < nCharsetLen) // We found the correct charset
+                       {
+
+//             m_Plain[i] = m_PlainCharset[nIndexOfX32 % m_vCharset[j].m_nPlainCharsetLen];
+//             nIndexOfX32 /= m_vCharset[j].m_nPlainCharsetLen;
+
+               unsigned int nPlainCharsetLen = m_vCharset[j].m_nPlainCharsetLen;
+               unsigned int nTemp;
+#ifdef _WIN32
+               __asm
+               {
+                       mov eax, nIndexOfX32
+                       xor edx, edx
+                       div nPlainCharsetLen
+                       mov nIndexOfX32, eax
+                       mov nTemp, edx
+               }
+               m_Plain[i] = m_vCharset[j].m_PlainCharset[nTemp];
+#else
+               __asm__ __volatile__ (  "mov %2, %%eax;"
+                                                               "xor %%edx, %%edx;"
+                                                               "divl %3;"
+                                                               "mov %%eax, %0;"
+                                                               "mov %%edx, %1;"
+                                                               : "=m"(nIndexOfX32), "=m"(nTemp)
+                                                               : "m"(nIndexOfX32), "m"(nPlainCharsetLen)
+                                                               : "%eax", "%edx"
+                                                        );
+               m_Plain[i] = m_vCharset[j].m_PlainCharset[nTemp];
+#endif
+               break;
+                       }
+               }
+       }
+#endif
+}
+
+void CChainWalkContext::PlainToHash()
+{      
+       m_pHashRoutine(m_Plain, m_nPlainLen, m_Hash);
+}
+
+void CChainWalkContext::HashToIndex(int nPos)
+{
+       m_nIndex = (*(uint64*)m_Hash + m_nReduceOffset + nPos) % m_nPlainSpaceTotal;
+}
+
+uint64 CChainWalkContext::GetIndex()
+{
+       return m_nIndex;
+}
+const uint64 *CChainWalkContext::GetIndexPtr()
+{
+       return &m_nIndex;
+}
+
+string CChainWalkContext::GetPlain()
+{
+       string sRet;
+       int i;
+       for (i = 0; i < m_nPlainLen; i++)
+       {
+               char c = m_Plain[i];
+               //if (c >= 32 && c <= 126)
+               //if (c >= 32)
+                       sRet += c;
+               //else
+               //      sRet += '?';
+       }
+       
+       return sRet;
+}
+
+string CChainWalkContext::GetBinary()
+{
+       return HexToStr(m_Plain, m_nPlainLen);
+}
+/*
+string CChainWalkContext::GetPlainBinary()
+{
+       string sRet;
+       sRet += GetPlain();
+       int i;
+       for (i = 0; i < m_nPlainLenMax - m_nPlainLen; i++)
+               sRet += ' ';
+
+       sRet += "|";
+
+       sRet += GetBinary();
+       for (i = 0; i < m_nPlainLenMax - m_nPlainLen; i++)
+               sRet += "  ";
+
+       return sRet;
+}
+*/
+string CChainWalkContext::GetHash()
+{
+       return HexToStr(m_Hash, m_nHashLen);
+}
+
+bool CChainWalkContext::CheckHash(unsigned char* pHash)
+{
+       if (memcmp(m_Hash, pHash, m_nHashLen) == 0)
+               return true;
+
+       return false;
+}
+
+bool CChainWalkContext::isOldFormat()
+{
+       return isOldRtFormat;
+}
+bool CChainWalkContext::isNewFormat()
+{
+       return isNewRtFormat;
+}
+
diff --git a/Client Applications/rcracki_mt/ChainWalkContext.h b/Client Applications/rcracki_mt/ChainWalkContext.h
new file mode 100644 (file)
index 0000000..e7aea41
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _CHAINWALKCONTEXT_H
+#define _CHAINWALKCONTEXT_H
+
+#include "HashRoutine.h"
+#include "Public.h"
+
+typedef struct 
+{
+       unsigned char m_PlainCharset[255];
+       int m_nPlainCharsetLen;
+       int m_nPlainLenMin;
+       int m_nPlainLenMax;
+       string m_sPlainCharsetName;
+       string m_sPlainCharsetContent;
+} stCharset;
+class CChainWalkContext 
+{
+public:
+       CChainWalkContext();
+       virtual ~CChainWalkContext();
+
+private:
+       static string m_sHashRoutineName;       
+       static HASHROUTINE m_pHashRoutine;                                                      // Configuration
+       static int m_nHashLen;                                                                          // Configuration
+       static bool isOldRtFormat;
+       static bool isNewRtFormat;
+       static vector<stCharset> m_vCharset;
+       static int m_nPlainLenMinTotal, m_nPlainLenMaxTotal;
+       static uint64 m_nPlainSpaceUpToX[MAX_PLAIN_LEN + 1];            // Performance consideration
+       static uint64 m_nPlainSpaceTotal;                                                       // Performance consideration
+       static int m_nHybridCharset;
+       static int m_nRainbowTableIndex;                                                        // Configuration
+       static uint64 m_nReduceOffset;                                                          // Performance consideration
+
+       // Context
+       uint64 m_nIndex;
+       unsigned char m_Plain[MAX_PLAIN_LEN];
+       int m_nPlainLen;
+       unsigned char m_Hash[MAX_HASH_LEN];
+       static unsigned char m_Salt[MAX_SALT_LEN];
+       static int m_nSaltLen;
+private:
+       static bool LoadCharset(string sCharset);
+
+public:
+       static bool SetHashRoutine(string sHashRoutineName);                                                                                            // Configuration
+       static bool SetPlainCharset(string sCharsetName, int nPlainLenMin, int nPlainLenMax);                           // Configuration
+       static bool SetRainbowTableIndex(int nRainbowTableIndex);       
+       static bool SetSalt(unsigned char *Salt, int nSaltLength);// Configuration
+       static bool SetupWithPathName(string sPathName, int& nRainbowChainLen, int& nRainbowChainCount);        // Wrapper
+       static string GetHashRoutineName();
+       static int GetHashLen();
+       static string GetPlainCharsetName();
+       static string GetPlainCharsetContent();
+       static int GetPlainLenMin();
+       static int GetPlainLenMax();
+       static uint64 GetPlainSpaceTotal();
+       static int GetRainbowTableIndex();
+       static void Dump();
+       static bool isOldFormat();
+       static bool isNewFormat();
+
+       void SetIndex(uint64 nIndex);
+       void SetHash(unsigned char* pHash);             // The length should be m_nHashLen
+
+       void IndexToPlain();
+       void PlainToHash();
+       void HashToIndex(int nPos);
+
+       uint64 GetIndex();
+       const uint64* GetIndexPtr();
+       string GetPlain();
+       string GetBinary();
+       string GetHash();
+       bool CheckHash(unsigned char* pHash);   // The length should be m_nHashLen
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/ChainWalkSet.cpp b/Client Applications/rcracki_mt/ChainWalkSet.cpp
new file mode 100644 (file)
index 0000000..3069fee
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786)
+#endif
+
+#include "ChainWalkSet.h"
+
+CChainWalkSet::CChainWalkSet()
+{
+       m_sHashRoutineName   = "";
+       m_sPlainCharsetName  = "";
+       m_nPlainLenMin       = 0;
+       m_nPlainLenMax       = 0;
+       m_nRainbowTableIndex = 0;
+       m_nRainbowChainLen   = 0;
+       debug = false;
+       sPrecalcPathName     = "";
+       preCalcPart          = 0;
+}
+
+CChainWalkSet::~CChainWalkSet()
+{
+       DiscardAll();
+}
+
+void CChainWalkSet::DiscardAll()
+{
+       //printf("debug: discarding all walk...\n");
+
+       list<ChainWalk>::iterator it;
+       for (it = m_lChainWalk.begin(); it != m_lChainWalk.end(); it++)
+               delete it->pIndexE;
+       m_lChainWalk.clear();
+}
+
+string CChainWalkSet::CheckOrRotatePreCalcFile()
+{
+       char sPreCalcFileName[255];
+
+       // 255 files limit to be sure
+       for (; preCalcPart < 255; preCalcPart++)
+       {
+               sprintf(sPreCalcFileName, "%s.%d", sPrecalcPathName.c_str(), preCalcPart);
+               string sReturnPreCalcPath(sPreCalcFileName);
+
+               unsigned int fileLen = 0;
+
+               FILE* file = fopen(sReturnPreCalcPath.c_str(), "ab");
+               if(file!=NULL)
+               {
+                       fileLen = GetFileLen(file);
+                       unsigned int nextFileLen = fileLen + (sizeof(uint64) * (m_nRainbowChainLen-1));
+                       // Rotate to next file if we are going to pass 2GB filesize
+                       if (nextFileLen < ((unsigned)2 * 1024 * 1024 * 1024))
+                       {
+                               // We might want to vPrecalcFiles.push_back(sReturnPreCalcPath) if we just created this file
+                               // We don't as only newly generated chainwalksets will be stored to this new file, so we don't have to look there
+                               if (debug) printf("Debug: Using for precalc: %s\n", sReturnPreCalcPath.c_str());
+                               fclose(file);
+                               return sReturnPreCalcPath;
+                       }
+                       fclose(file);
+               }
+       }
+}
+
+void CChainWalkSet::updateUsedPrecalcFiles()
+{
+       // we might also use this function to search a wildcard path of precalc files
+       vPrecalcFiles.clear();
+       char sPreCalcFileName[255];
+
+       int i;
+       // 255 files max
+       for (i = 0; i < 255; i++)
+       {
+               sprintf(sPreCalcFileName, "%s.%d", sPrecalcPathName.c_str(), i);
+               string sTryPreCalcPath(sPreCalcFileName);
+               FILE* file = fopen(sTryPreCalcPath.c_str(), "rb");
+               if(file!=NULL) {
+                       vPrecalcFiles.push_back(sTryPreCalcPath);
+                       fclose(file);
+               }
+               else {
+                       break;
+               }
+       }
+}
+
+void CChainWalkSet::removePrecalcFiles()
+{
+       if (debug) printf("Debug: Removing precalc files.\n");
+       updateUsedPrecalcFiles();
+       string sCurrentPrecalcPathName = "";
+       string sCurrentPrecalcIndexPathName = "";
+       
+       int i;
+       for (i = 0; i < (int)vPrecalcFiles.size(); i++)
+       {
+               sCurrentPrecalcPathName = vPrecalcFiles[i];
+               sCurrentPrecalcIndexPathName = sCurrentPrecalcPathName + ".index";
+
+               if (debug) printf("Debug: Removing precalc file: %s\n", sCurrentPrecalcPathName.c_str());
+
+               if (remove(sCurrentPrecalcPathName.c_str()) != 0)
+                       if (debug) printf("Debug: Failed removing precalc file: %s\n", sCurrentPrecalcPathName.c_str());
+
+               if (debug) printf("Debug: Removing precalc index file: %s\n", sCurrentPrecalcIndexPathName.c_str());
+
+               if (remove(sCurrentPrecalcIndexPathName.c_str()) != 0)
+                       if (debug) printf("Debug: Failed removing precalc index file: %s\n", sCurrentPrecalcIndexPathName.c_str());
+
+       }
+}
+
+bool CChainWalkSet::FindInFile(uint64* pIndexE, unsigned char* pHash, int nHashLen)
+{
+       int gotPrecalcOnLine = -1;
+       char precalculationLine[255];
+       sprintf(precalculationLine, "%s_%s#%d-%d_%d_%d:%s\n", m_sHashRoutineName.c_str(), m_sPlainCharsetName.c_str(), m_nPlainLenMin, m_nPlainLenMax, m_nRainbowTableIndex, m_nRainbowChainLen, HexToStr(pHash, nHashLen).c_str() );
+       string precalcString(precalculationLine);
+
+       string sCurrentPrecalcPathName = "";
+       string sCurrentPrecalcIndexPathName = "";
+       int offset;
+
+       int i;
+       for (i = 0; i < (int)vPrecalcFiles.size() && gotPrecalcOnLine == -1; i++)
+       {
+               sCurrentPrecalcPathName = vPrecalcFiles[i];
+               sCurrentPrecalcIndexPathName = sCurrentPrecalcPathName + ".index";
+
+               offset = 0;
+
+               vector<string> precalcLines;
+               if (ReadLinesFromFile(sCurrentPrecalcIndexPathName.c_str(), precalcLines))
+               {
+                       int j;
+                       for (j = 0; j < (int)precalcLines.size(); j++)
+                       {
+                               if (precalcString.compare(0, precalcString.size()-1, precalcLines[j]) == 0)
+                               {
+                                       gotPrecalcOnLine = j;
+                                       break;
+                               }
+
+                               // Parse
+                               vector<string> vPart;
+                               if (SeperateString(precalcLines[j], "___:", vPart))
+                               {
+                                       // add to offset
+                                       offset += ((atoi(vPart[3].c_str())-1) * sizeof(uint64));
+                               }
+                               else {
+                                       // corrupt file
+                                       printf("Corrupted precalculation file!\n");
+                                       gotPrecalcOnLine = -1;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (gotPrecalcOnLine > -1)
+       {
+               if (debug) printf("Debug: Reading pre calculations from file, line %d offset %d\n", gotPrecalcOnLine, offset);
+               
+               FILE* fp = fopen(sCurrentPrecalcPathName.c_str(), "rb");
+
+               if (fp!=NULL) {
+                       fseek(fp, offset, SEEK_SET);
+
+                       // We should do some verification here, for example by recalculating the middle chain, to catch corrupted files
+                       if(fread(pIndexE, sizeof(uint64), m_nRainbowChainLen-1, fp) != m_nRainbowChainLen-1)
+                               printf("File read error.");
+                       fclose(fp);
+               }
+               else
+                       printf("Cannot open precalculation file %s.\n", sCurrentPrecalcPathName.c_str());
+
+               //printf("\npIndexE[0]: %s\n", uint64tostr(pIndexE[0]).c_str());
+               //printf("\npIndexE[nRainbowChainLen-2]: %s\n", uint64tostr(pIndexE[m_nRainbowChainLen-2]).c_str());
+
+               return true;
+       }
+
+       return false;
+
+}
+
+void CChainWalkSet::StoreToFile(uint64* pIndexE, unsigned char* pHash, int nHashLen)
+{
+       if (debug) printf("\nDebug: Storing precalc\n");
+       
+       string sCurrentPrecalcPathName = CheckOrRotatePreCalcFile();
+       string sCurrentPrecalcIndexPathName = sCurrentPrecalcPathName + ".index";
+
+       FILE* fp = fopen(sCurrentPrecalcPathName.c_str(), "ab");
+       if(fp!=NULL)
+       {
+               if(fwrite(pIndexE, sizeof(uint64), m_nRainbowChainLen-1, fp) != m_nRainbowChainLen-1)
+                       printf("File write error.");
+               else
+               {
+                       FILE* file = fopen(sCurrentPrecalcIndexPathName.c_str(), "a");
+                       if (file!=NULL)
+                       {
+                               char precalculationLine[255];
+                               sprintf(precalculationLine, "%s_%s#%d-%d_%d_%d:%s\n", m_sHashRoutineName.c_str(), m_sPlainCharsetName.c_str(), m_nPlainLenMin, m_nPlainLenMax, m_nRainbowTableIndex, m_nRainbowChainLen, HexToStr(pHash, nHashLen).c_str() );
+                               fputs (precalculationLine, file);
+                               fclose (file);
+                       }
+               }
+               fclose(fp);
+               }
+       else
+               printf("Cannot open precalculation file %s\n", sCurrentPrecalcPathName.c_str());
+
+}
+
+uint64* CChainWalkSet::RequestWalk(unsigned char* pHash, int nHashLen,
+                                                                  string sHashRoutineName,
+                                                                  string sPlainCharsetName, int nPlainLenMin, int nPlainLenMax, 
+                                                                  int nRainbowTableIndex, 
+                                                                  int nRainbowChainLen,
+                                                                  bool& fNewlyGenerated,
+                                                                  bool setDebug,
+                                                                  string sPrecalc)
+{
+       debug = setDebug;
+       sPrecalcPathName = sPrecalc;
+
+       if (   m_sHashRoutineName   != sHashRoutineName
+               || m_sPlainCharsetName  != sPlainCharsetName
+               || m_nPlainLenMin       != nPlainLenMin
+               || m_nPlainLenMax       != nPlainLenMax
+               || m_nRainbowTableIndex != nRainbowTableIndex
+               || m_nRainbowChainLen   != nRainbowChainLen)
+       {
+               DiscardAll();
+
+               m_sHashRoutineName   = sHashRoutineName;
+               m_sPlainCharsetName  = sPlainCharsetName;
+               m_nPlainLenMin       = nPlainLenMin;
+               m_nPlainLenMax       = nPlainLenMax;
+               m_nRainbowTableIndex = nRainbowTableIndex;
+               m_nRainbowChainLen   = nRainbowChainLen;
+
+               ChainWalk cw;
+               memcpy(cw.Hash, pHash, nHashLen);
+               cw.pIndexE = new uint64[nRainbowChainLen - 1];
+               m_lChainWalk.push_back(cw);
+
+               // Only update this list when we search through another rainbow table
+               updateUsedPrecalcFiles();
+
+               if (!FindInFile(cw.pIndexE, pHash, nHashLen))
+                       fNewlyGenerated = true;
+               else
+                       fNewlyGenerated = false;
+               return cw.pIndexE;
+       }
+
+       list<ChainWalk>::iterator it;
+       for (it = m_lChainWalk.begin(); it != m_lChainWalk.end(); it++)
+       {
+               if (memcmp(it->Hash, pHash, nHashLen) == 0)
+               {
+                       fNewlyGenerated = false;
+                       return it->pIndexE;
+               }
+       }
+
+       ChainWalk cw;
+       memcpy(cw.Hash, pHash, nHashLen);
+       cw.pIndexE = new uint64[nRainbowChainLen - 1];
+       m_lChainWalk.push_back(cw);
+
+       if (!FindInFile(cw.pIndexE, pHash, nHashLen))
+                       fNewlyGenerated = true;
+               else
+                       fNewlyGenerated = false;
+       return cw.pIndexE;
+}
+
+void CChainWalkSet::DiscardWalk(uint64* pIndexE)
+{
+       list<ChainWalk>::iterator it;
+       for (it = m_lChainWalk.begin(); it != m_lChainWalk.end(); it++)
+       {
+               if (it->pIndexE == pIndexE)
+               {
+                       delete it->pIndexE;
+                       m_lChainWalk.erase(it);
+                       return;
+               }
+       }
+
+       printf("debug: pIndexE not found\n");
+}
diff --git a/Client Applications/rcracki_mt/ChainWalkSet.h b/Client Applications/rcracki_mt/ChainWalkSet.h
new file mode 100644 (file)
index 0000000..05622cf
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _CHAINWALKSET_H
+#define _CHAINWALKSET_H
+
+#include "Public.h"
+
+struct ChainWalk
+{
+       unsigned char Hash[MAX_HASH_LEN];
+       //int nHashLen;         // Implied
+       uint64* pIndexE;        // mapStartPosIndexE, Len = nRainbowChainLen - 1
+};
+
+class CChainWalkSet
+{
+public:
+       CChainWalkSet();
+       virtual ~CChainWalkSet();
+
+private:
+       string m_sHashRoutineName;              // Discard all if not match
+       string m_sPlainCharsetName;             // Discard all if not match
+       int    m_nPlainLenMin;                  // Discard all if not match
+       int    m_nPlainLenMax;                  // Discard all if not match
+       int    m_nRainbowTableIndex;    // Discard all if not match
+       int    m_nRainbowChainLen;              // Discard all if not match
+       list<ChainWalk> m_lChainWalk;
+       bool   debug;
+       string sPrecalcPathName;
+       int    preCalcPart;
+       vector<string> vPrecalcFiles;
+
+private:
+       void DiscardAll();
+       bool FindInFile(uint64* pIndexE, unsigned char* pHash, int nHashLen);
+       string CheckOrRotatePreCalcFile();
+       void updateUsedPrecalcFiles();
+
+public:
+       uint64* RequestWalk(unsigned char* pHash, int nHashLen,
+                                               string sHashRoutineName,
+                                               string sPlainCharsetName, int nPlainLenMin, int nPlainLenMax, 
+                                               int nRainbowTableIndex, 
+                                               int nRainbowChainLen,
+                                               bool& fNewlyGenerated,
+                                               bool setDebug,
+                                               string sPrecalc);
+       void DiscardWalk(uint64* pIndexE);
+       void StoreToFile(uint64* pIndexE, unsigned char* pHash, int nHashLen);
+       void removePrecalcFiles();
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/ChangeLog.txt b/Client Applications/rcracki_mt/ChangeLog.txt
new file mode 100644 (file)
index 0000000..0b07cd0
--- /dev/null
@@ -0,0 +1,52 @@
+[rcracki_mt ChangeLog]
+
+0.6.2 (2 Juli 2009, 13:37):
+* Fixed linux support (tty stuff and now actually compiles)
+* Fixed precalculation code
+
+0.6.1 (14 May 2009, 22:12):
+* bug fixed where the list of rainbow tables is doubled when you resume a session and you have default RT locations in your ini
+
+0.6 (14 May 2009, 20:47):
+* Finding .rti files recursively
+* Fixed memory allocation bugs (also trying to save appropriate amount of memory for chainwalksets... these can become really large with the new tables)
+* Real pause/resume function, you can resume a session with -r
+* Session support, use -s session_name. Combine this with -r to resume a session other then the default
+* Ini file support, store some default values such as rainbow table directories.
+* Tab separated results (stdout)
+* Support pause during cracking and 'skip' during unicode correction for Linux
+* A readme / 'manual' !
+
+0.5 (16 Apr 2009, 22:47):
+* Support for the old non-indexed .rt format, it should work with both type of tables in one run... I didn't test this feature thoroughly
+* Using some other pieces of code for algorithms
+* Support for .lst files from Cain as input (patch from James Dickson) - use for example -c LMNT.lst
+* Fixed some bugs
+* Dunno anymore, left this version lying around for too long...
+
+0.4 (oops, a second 0.4) (13 Dec 2008, 18:20):
+* Improved file reading performance
+
+0.4 (27 Nov 2008, 00:09):
+* Source included
+* Memory usage down to about 50% (tnx sc00bz for pointing out the inefficiency, tnx jci for helping with the code)
+* Works under Linux! (using pthreads now instead of Windows threads)
+* Speed up: implemented MD4 reference implementation, not using OpenSSL for NTLM anymore (tnx Bitweasil for supplying 98% of the code)
+* Speed up: using OpenSSL a lot faster (tnx jci for pointing that out)
+* Probably some more small things i forgot
+
+0.3 (16 Nov 2008, 01:01):
+* Improved command line argument parsing (order no longer matters)
+* Option to write (temporary) output to a file, use -o pick_a_nice_filename.txt
+* Option to pause, press 'P' to pause/unpause (Windows only)
+* For pwdump searches: unicode correction is done when case correction fails
+
+0.2 (28 Oct 2008, 01:42):
+* False alarm checking now also multi threaded
+* Search one level of subdirectories for rainbow table files
+
+0.1 (27 Oct 2008, 00:14):
+* Initial multithreaded version, using Windows threads.
+* Using multiple threads for the pre-calculation part.
+* Added a simple 'progress' message, so you can see how many hashes are being pre-calculated
+
diff --git a/Client Applications/rcracki_mt/CrackEngine.cpp b/Client Applications/rcracki_mt/CrackEngine.cpp
new file mode 100644 (file)
index 0000000..3ed82de
--- /dev/null
@@ -0,0 +1,1291 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "CrackEngine.h"
+
+#include <time.h>
+#include "RTI2Reader.h"
+
+CCrackEngine::CCrackEngine()
+{
+       ResetStatistics();
+       writeOutput = false;
+       resumeSession = false;
+       debug = false;
+       keepPrecalcFiles = false;
+
+       sSessionPathName = "";
+       sProgressPathName = "";
+}
+
+CCrackEngine::~CCrackEngine()
+{
+}
+
+//////////////////////////////////////////////////////////////////////
+
+void CCrackEngine::ResetStatistics()
+{
+       m_fTotalDiskAccessTime               = 0.0f;
+       m_fTotalCryptanalysisTime            = 0.0f;
+       m_nTotalChainWalkStep                = 0;
+       m_nTotalFalseAlarm                   = 0;
+       m_nTotalChainWalkStepDueToFalseAlarm = 0;
+//     m_nTotalFalseAlarmSkipped                        = 0;
+}
+
+int CCrackEngine::BinarySearchOld(RainbowChainO* pChain, int nRainbowChainCount, uint64 nIndex)
+{
+       int nLow = 0;
+       int nHigh = nRainbowChainCount - 1;
+       while (nLow <= nHigh)
+       {
+               int nMid = (nLow + nHigh) / 2;
+               if (nIndex == pChain[nMid].nIndexE)
+                       return nMid;
+               else if (nIndex < pChain[nMid].nIndexE)
+                       nHigh = nMid - 1;
+               else
+                       nLow = nMid + 1;
+       }
+
+       return -1;
+}
+
+RainbowChain *CCrackEngine::BinarySearch(RainbowChain *pChain, int nChainCountRead, uint64 nIndex, IndexChain *pIndex, int nIndexSize, int nIndexStart)
+{
+       uint64 nPrefix = nIndex >> 16;
+       int nLow, nHigh;        
+       bool found = false;
+       int nChains = 0;
+       
+       if(nPrefix > (pIndex[nIndexSize-1].nPrefix & 0x000000FFFFFFFFFFULL)) // check if its in the index file
+       {
+               return NULL;
+       }
+
+       int nBLow = 0;
+       int nBHigh = nIndexSize - 1;
+       while (nBLow <= nBHigh)
+       {
+               int nBMid = (nBLow + nBHigh) / 2;
+               if (nPrefix == (pIndex[nBMid].nPrefix & 0x000000FFFFFFFFFFULL))
+               {
+                       //nLow = nChains;
+                       int nChains = 0;
+
+                       nLow = pIndex[nBMid].nFirstChain;
+                       nHigh = nLow + pIndex[nBMid].nChainCount;
+                       if(nLow >= nIndexStart && nLow <= nIndexStart + nChainCountRead) 
+                       {                                       
+                               if(nHigh > nIndexStart + nChainCountRead)
+                                       nHigh = nIndexStart + nChainCountRead;
+                       }
+                       else if(nLow < nIndexStart && nHigh >= nIndexStart)
+                       {
+                               nLow = nIndexStart;
+                       }
+                       else break;                                     
+                       found = true;
+                       break;
+               }
+               else if (nPrefix < (pIndex[nBMid].nPrefix & 0x000000FFFFFFFFFFULL))
+                       nBHigh = nBMid - 1;
+               else
+                       nBLow = nBMid + 1;
+       }
+       if(found == true)
+       {
+               for(int i = nLow - nIndexStart; i < nHigh - nIndexStart; i++)
+               {
+                       int nSIndex = ((int)nIndex) & 0x0000FFFF;
+
+                       if (nSIndex == pChain[i].nIndexE)
+                       {
+                               return &pChain[i];
+                       }                               
+                       else if(pChain[i].nIndexE > nSIndex)
+                               break;
+               }
+       }       
+       return NULL;
+}
+
+// not used currently, leaving code for future checkpoints
+//bool CCrackEngine::CheckAlarm(RainbowChain* pChain, int nGuessedPos, unsigned char* pHash, CHashSet& hs)
+//{
+//     CChainWalkContext cwc;
+//     //uint64 nIndexS = pChain->nIndexS >> 16;
+//     uint64 nIndexS = pChain->nIndexS & 0x0000FFFFFFFFFFFFULL; // for first 6 bytes
+//     cwc.SetIndex(nIndexS);
+//     int nPos;
+//     for (nPos = 0; nPos < nGuessedPos; nPos++)
+//     {
+//             cwc.IndexToPlain();
+//             cwc.PlainToHash();
+//             cwc.HashToIndex(nPos);
+//             // Not using checkpoints atm
+//             /*
+//             switch(nPos)
+//             {
+//             case 5000:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000080) >> 7)
+//                             {
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 5000;
+////                                   printf("CheckPoint caught false alarm at position 7600\n");
+//                                     return false;
+//                             }
+//                             break;
+//             case 6000:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000040) >> 6)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 8200\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 6000;
+//                                     return false;
+//                             }
+//                             break;
+//
+//             case 7600:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000020) >> 5)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 8700\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 7600;
+//                                     return false;
+//                             }
+//                             break;
+//
+//             case 8200:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000010) >> 4)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 9000\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 8200;
+//                                     return false;
+//                             }
+//                             break;
+//
+//                     case 8700:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000008) >> 3)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 9300\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 8700;
+//                                     return false;
+//                             }
+//
+//                             break;
+//                     case 9000:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000004) >> 2)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 9600\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 9000;
+//                                     return false;
+//                             }
+//
+//                             break;
+//                     case 9300:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000002) >> 1)
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 9600\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 9300;
+//                                     return false;
+//                             }
+//                             break;
+//                     case 9600:
+//                             if((cwc.GetIndex() & 0x00000001) != (pChain->nCheckPoint & 0x00000001))
+//                             {
+////                                   printf("CheckPoint caught false alarm at position 9600\n");
+//                                     m_nTotalFalseAlarmSkipped += 10000 - 9600;
+//                                     return false;
+//                             }
+//                             break;
+//
+//             }*/
+//     }
+//     cwc.IndexToPlain();
+//     cwc.PlainToHash();
+//     if (cwc.CheckHash(pHash))
+//     {
+//             printf("plaintext of %s is %s\n", cwc.GetHash().c_str(), cwc.GetPlain().c_str());
+//             hs.SetPlain(cwc.GetHash(), cwc.GetPlain(), cwc.GetBinary());
+//             return true;
+//     }
+//
+//     return false;
+//}
+
+//bool CCrackEngine::CheckAlarmOld(RainbowChainO* pChain, int nGuessedPos, unsigned char* pHash, CHashSet& hs)
+//{
+//     CChainWalkContext cwc;
+//     cwc.SetIndex(pChain->nIndexS);
+//     int nPos;
+//     for (nPos = 0; nPos < nGuessedPos; nPos++)
+//     {
+//             cwc.IndexToPlain();
+//             cwc.PlainToHash();
+//             cwc.HashToIndex(nPos);
+//     }
+//     cwc.IndexToPlain();
+//     cwc.PlainToHash();
+//     if (cwc.CheckHash(pHash))
+//     {
+//             printf("plaintext of %s is %s\n", cwc.GetHash().c_str(), cwc.GetPlain().c_str());
+//             hs.SetPlain(cwc.GetHash(), cwc.GetPlain(), cwc.GetBinary());
+//             return true;
+//     }
+//
+//     return false;
+//}
+
+void CCrackEngine::GetChainIndexRangeWithSameEndpoint(RainbowChainO* pChain,
+                                                                                                         int nRainbowChainCount,
+                                                                                                         int nMatchingIndexE,
+                                                                                                         int& nMatchingIndexEFrom,
+                                                                                                         int& nMatchingIndexETo)
+{
+       nMatchingIndexEFrom = nMatchingIndexE;
+       nMatchingIndexETo   = nMatchingIndexE;
+       while (nMatchingIndexEFrom > 0)
+       {
+               if (pChain[nMatchingIndexEFrom - 1].nIndexE == pChain[nMatchingIndexE].nIndexE)
+                       nMatchingIndexEFrom--;
+               else
+                       break;
+       }
+       while (nMatchingIndexETo < nRainbowChainCount - 1)
+       {
+               if (pChain[nMatchingIndexETo + 1].nIndexE == pChain[nMatchingIndexE].nIndexE)
+                       nMatchingIndexETo++;
+               else
+                       break;
+       }
+}
+
+void CCrackEngine::SearchTableChunkOld(RainbowChainO* pChain, int nRainbowChainLen, int nRainbowChainCount, CHashSet& hs)
+{
+       vector<string> vHash;
+       hs.GetLeftHashWithLen(vHash, CChainWalkContext::GetHashLen());
+       printf("searching for %d hash%s...\n", vHash.size(),
+                                                                                  vHash.size() > 1 ? "es" : "");
+
+       int nChainWalkStep = 0;
+       int nFalseAlarm = 0;
+       int nChainWalkStepDueToFalseAlarm = 0;
+
+       vector<rcrackiThread*> threadPool;
+       vector<pthread_t> pThreads;
+
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+       #ifdef _WIN32
+       sched_param param;
+       param.sched_priority = THREAD_PRIORITY_BELOW_NORMAL;
+       pthread_attr_setschedparam (&attr, &param);
+       #endif
+       // else set it to 5 or something (for linux)?
+
+       bool pausing = false;
+
+       int nHashIndex;
+       for (nHashIndex = 0; nHashIndex < vHash.size(); nHashIndex++)
+       {
+               #ifdef _WIN32
+               if (_kbhit())
+               {
+                       int ch = _getch();
+                       ch = toupper(ch);
+                       if (ch == 'P')
+                       {
+                               pausing = true;
+                               printf( "\nPausing, press P again to continue... ");
+                               clock_t t1 = clock();
+                               while (pausing)
+                               {
+                                       if (_kbhit())
+                                       {
+                                               ch = _getch();
+                                               ch = toupper(ch);
+                                               if (ch == 'P')
+                                               {
+                                                       printf( " [Continuing]\n");
+                                                       pausing = false;
+                                                       clock_t t2 = clock();
+                                                       float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                       m_fTotalCryptanalysisTime -= fTime;
+                                               }
+                                       }
+                                       Sleep(500);
+                               }
+                       }
+                       else
+                       {
+                               printf( "\nPress 'P' to pause...\n");
+                       }
+               }
+               #else
+               int c = tty_getchar();
+               if (c >= 0) {
+                       tty_flush();
+                       if (c==112) { // = p
+                               pausing = true;
+                               printf( "\nPausing, press 'p' again to continue... ");
+                               clock_t t1 = clock();
+                               while (pausing)
+                               {
+                                       if ((c = tty_getchar()) >= 0)
+                                       {
+                                               tty_flush();
+                                               if (c == 112)
+                                               {
+                                                       printf( " [Continuing]\n");
+                                                       pausing = false;
+                                                       clock_t t2 = clock();
+                                                       float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                       m_fTotalCryptanalysisTime -= fTime;
+                                               }
+                                       }
+                                       usleep(500*1000);
+                               }
+                       }
+                       else {
+                               printf( "\nPress 'p' to pause...\n");
+                       }
+               }
+               #endif
+               unsigned char TargetHash[MAX_HASH_LEN];
+               int nHashLen;
+               ParseHash(vHash[nHashIndex], TargetHash, nHashLen);
+               if (nHashLen != CChainWalkContext::GetHashLen())
+                       printf("debug: nHashLen mismatch\n");
+
+               // Rqeuest ChainWalk
+               bool fNewlyGenerated;
+               uint64* pStartPosIndexE = m_cws.RequestWalk(TargetHash,
+                                                                                                       nHashLen,
+                                                                                                       CChainWalkContext::GetHashRoutineName(),
+                                                                                                       CChainWalkContext::GetPlainCharsetName(),
+                                                                                                       CChainWalkContext::GetPlainLenMin(),
+                                                                                                       CChainWalkContext::GetPlainLenMax(),
+                                                                                                       CChainWalkContext::GetRainbowTableIndex(),
+                                                                                                       nRainbowChainLen,
+                                                                                                       fNewlyGenerated,
+                                                                                                       debug,
+                                                                                                       sPrecalcPathName);
+               //printf("debug: using %s walk for %s\n", fNewlyGenerated ? "newly generated" : "existing",
+               //                                                                              vHash[nHashIndex].c_str());
+
+               // Walk
+               if (fNewlyGenerated)
+               {
+                       //printf("Pre-calculating hash %d of %d.\t\t\r", nHashIndex+1, vHash.size());
+                       printf("Pre-calculating hash %d of %d.%-20s\r", nHashIndex+1, vHash.size(), "");
+                       threadPool.clear();
+                       pThreads.clear();
+                       
+                       int thread_ID;
+                       for (thread_ID = 0; thread_ID < maxThreads; thread_ID++)
+                       {
+                               rcrackiThread* r_Thread = new rcrackiThread(TargetHash, thread_ID, nRainbowChainLen, maxThreads, pStartPosIndexE);
+                               if (r_Thread)
+                               {
+                                       pthread_t pThread;
+                                       int returnValue = pthread_create( &pThread, &attr, rcrackiThread::rcrackiThreadStaticEntryPointPthread, (void *) r_Thread);
+
+                                       if( returnValue != 0 )
+                                       {
+                                               printf("pThread creation failed, returnValue: %d\n", returnValue);
+                                       }
+                                       else
+                                       {
+                                               pThreads.push_back(pThread);
+                                       }
+
+                                       threadPool.push_back(r_Thread);
+                               }
+                               else 
+                               {
+                                       printf("r_Thread creation failed!\n");
+                               }
+                       }
+                       
+                       //printf("%d r_Threads created\t\t\n", threadPool.size());
+                       
+                       for (thread_ID = 0; thread_ID < threadPool.size(); thread_ID++)
+                       {
+                               pthread_t pThread = pThreads[thread_ID];
+                               int returnValue = pthread_join(pThread, NULL);
+                               if( returnValue != 0 )
+                               {
+                                       printf("pThread join failed, returnValue: %d\n", returnValue);
+                               }
+                                       
+                               rcrackiThread* rThread = threadPool[thread_ID];
+                               nChainWalkStep += rThread->GetChainWalkStep();
+                       }
+
+                       //printf("\t\t\t\t\r");
+                       printf("%-50s\r", "");
+
+
+               }
+
+               //printf("Checking false alarms for hash %d of %d.\t\t\r", nHashIndex+1, vHash.size());
+               printf("Checking false alarms for hash %d of %d.%-20s\r", nHashIndex+1, vHash.size(), "");
+
+               threadPool.clear();
+               pThreads.clear();
+
+               int i;
+               for (i = 0; i < maxThreads; i++)
+               {
+                       rcrackiThread* r_Thread = new rcrackiThread(TargetHash, true);
+                       threadPool.push_back(r_Thread);
+               }
+
+               int thread_ID = 0;
+               int nPos;
+               for (nPos = nRainbowChainLen - 2; nPos >= 0; nPos--)
+               {
+                       uint64 nIndexEOfCurPos = pStartPosIndexE[nPos];
+               
+                       // Search matching nIndexE
+                       int nMatchingIndexE = BinarySearchOld(pChain, nRainbowChainCount, nIndexEOfCurPos);
+                       if (nMatchingIndexE != -1)
+                       {
+                               int nMatchingIndexEFrom, nMatchingIndexETo;
+                               GetChainIndexRangeWithSameEndpoint(pChain, nRainbowChainCount,
+                                                                                                  nMatchingIndexE,
+                                                                                                  nMatchingIndexEFrom, nMatchingIndexETo);
+                               int i;
+                               for (i = nMatchingIndexEFrom; i <= nMatchingIndexETo; i++)
+                               {
+                                       rcrackiThread* rThread = threadPool[thread_ID];
+                                       rThread->AddAlarmCheckO(pChain + i, nPos);
+                                       if (thread_ID < maxThreads - 1 ) {
+                                               thread_ID++;
+                                       } else {
+                                               thread_ID = 0;
+                                       }
+                               }
+                       }
+               }
+
+               for (thread_ID = 0; thread_ID < maxThreads; thread_ID++)
+               {
+                       rcrackiThread* r_Thread = threadPool[thread_ID];
+                       pthread_t pThread;
+
+                       int returnValue = pthread_create( &pThread, &attr, rcrackiThread::rcrackiThreadStaticEntryPointPthread, (void *) r_Thread);
+
+                       if( returnValue != 0 )
+                       {
+                               printf("pThread creation failed, returnValue: %d\n", returnValue);
+                       }
+                       else
+                       {
+                               pThreads.push_back(pThread);
+                       }
+               }
+               
+               //printf("%d r_Threads created\t\t\n", threadPool.size());
+
+               bool foundHashInThread = false;
+               for (thread_ID = 0; thread_ID < threadPool.size(); thread_ID++)
+               {
+                       rcrackiThread* rThread = threadPool[thread_ID];
+                       pthread_t pThread = pThreads[thread_ID];
+
+                       int returnValue = pthread_join(pThread, NULL);
+                       if( returnValue != 0 )
+                       {
+                               printf("pThread join failed, returnValue: %d\n", returnValue);
+                       }
+
+                       nChainWalkStepDueToFalseAlarm += rThread->GetChainWalkStepDueToFalseAlarm();
+                       nFalseAlarm += rThread->GetnFalseAlarm();
+
+                       if (rThread->FoundHash() && !foundHashInThread) {
+                               //printf("\t\t\t\t\t\t\r");
+                               printf("%-50s\r", "");
+
+                               printf("plaintext of %s is %s\n", rThread->GetHash().c_str(), rThread->GetPlain().c_str());
+                               if (writeOutput)
+                               {
+                                       if (!writeResultLineToFile(outputFile, rThread->GetHash(), rThread->GetPlain(), rThread->GetBinary()))
+                                               printf("Couldn't write this result to file!\n");
+                               }
+                               hs.SetPlain(rThread->GetHash(), rThread->GetPlain(), rThread->GetBinary());
+
+                               FILE* file = fopen(sSessionPathName.c_str(), "a");
+                               if (file!=NULL)
+                               {
+                                       string buffer = "sHash=" + rThread->GetHash() + ":" + rThread->GetBinary() + ":" + rThread->GetPlain() + "\n";
+                                       fputs (buffer.c_str(), file);
+                                       fclose (file);
+                               }
+
+                               m_cws.DiscardWalk(pStartPosIndexE);
+                               foundHashInThread = true;
+                       }
+               }
+
+               pThreads.clear();
+               threadPool.clear();
+       }
+
+       //printf("\t\t\t\t\t\t\t\r");
+       printf("%-50s\r", "");
+       pThreads.clear();
+       threadPool.clear();
+       pthread_attr_destroy(&attr);
+
+       //printf("debug: chain walk step: %d\n", nChainWalkStep);
+       //printf("debug: false alarm: %d\n", nFalseAlarm);
+       //printf("debug: chain walk step due to false alarm: %d\n", nChainWalkStepDueToFalseAlarm);
+
+       m_nTotalChainWalkStep += nChainWalkStep;
+       m_nTotalFalseAlarm += nFalseAlarm;
+       m_nTotalChainWalkStepDueToFalseAlarm += nChainWalkStepDueToFalseAlarm;
+}
+
+void CCrackEngine::SearchTableChunk(RainbowChain* pChain, int nRainbowChainLen, int nRainbowChainCount, CHashSet& hs, IndexChain *pIndex, int nIndexSize, int nChainStart)
+{
+       vector<string> vHash;
+       //vector<uint64 *> vIndices;
+       //vector<RainbowChain *> vChains;
+       hs.GetLeftHashWithLen(vHash, CChainWalkContext::GetHashLen());
+       printf("searching for %d hash%s...\n", vHash.size(),
+                                                                                  vHash.size() > 1 ? "es" : "");
+
+       int nChainWalkStep = 0;
+       int nFalseAlarm = 0;
+       int nChainWalkStepDueToFalseAlarm = 0;
+
+       vector<rcrackiThread*> threadPool;
+       vector<pthread_t> pThreads;
+
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+       #ifdef _WIN32
+       sched_param param;
+       param.sched_priority = THREAD_PRIORITY_BELOW_NORMAL;
+       pthread_attr_setschedparam (&attr, &param);
+       #endif
+       // else set it to 5 or something (for linux)?
+
+       bool pausing = false;
+
+       int nHashIndex;
+       for (nHashIndex = 0; nHashIndex < vHash.size(); nHashIndex++)
+       {
+               #ifdef _WIN32
+               if (_kbhit())
+               {
+                       int ch = _getch();
+                       ch = toupper(ch);
+                       if (ch == 'P')
+                       {
+                               pausing = true;
+                               printf( "\nPausing, press P again to continue... ");
+                               clock_t t1 = clock();
+                               while (pausing)
+                               {
+                                       if (_kbhit())
+                                       {
+                                               ch = _getch();
+                                               ch = toupper(ch);
+                                               if (ch == 'P')
+                                               {
+                                                       printf( " [Continuing]\n");
+                                                       pausing = false;
+                                                       clock_t t2 = clock();
+                                                       float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                       m_fTotalCryptanalysisTime -= fTime;
+                                               }
+                                       }
+                                       Sleep(500);
+                               }
+                       }
+                       else
+                       {
+                               printf( "\nPress 'P' to pause...\n");
+                       }
+               }
+               #else
+               int c = tty_getchar();
+               if (c >= 0) {
+                       tty_flush();
+                       if (c==112) { // = p
+                               pausing = true;
+                               printf( "\nPausing, press 'p' again to continue... ");
+                               clock_t t1 = clock();
+                               while (pausing)
+                               {
+                                       if ((c = tty_getchar()) >= 0)
+                                       {
+                                               tty_flush();
+                                               if (c == 112)
+                                               {
+                                                       printf( " [Continuing]\n");
+                                                       pausing = false;
+                                                       clock_t t2 = clock();
+                                                       float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                       m_fTotalCryptanalysisTime -= fTime;
+                                               }
+                                       }
+                                       usleep(500*1000);
+                               }
+                       }
+                       else {
+                               printf( "\nPress 'p' to pause...\n");
+                       }
+               }
+               #endif
+               unsigned char TargetHash[MAX_HASH_LEN];
+               int nHashLen;
+               ParseHash(vHash[nHashIndex], TargetHash, nHashLen);
+               if (nHashLen != CChainWalkContext::GetHashLen())
+                       printf("debug: nHashLen mismatch\n");
+
+               // Request ChainWalk
+               bool fNewlyGenerated;
+//             printf("Requesting walk...");
+                
+
+               uint64* pStartPosIndexE = m_cws.RequestWalk(TargetHash,
+                                                                                                       nHashLen,
+                                                                                                       CChainWalkContext::GetHashRoutineName(),
+                                                                                                       CChainWalkContext::GetPlainCharsetName(),
+                                                                                                       CChainWalkContext::GetPlainLenMin(),
+                                                                                                       CChainWalkContext::GetPlainLenMax(),
+                                                                                                       CChainWalkContext::GetRainbowTableIndex(),
+                                                                                                       nRainbowChainLen,
+                                                                                                       fNewlyGenerated,
+                                                                                                       debug,
+                                                                                                       sPrecalcPathName);
+//             printf("done!\n");
+//             printf("debug: using %s walk for %s\n", fNewlyGenerated ? "newly generated" : "existing",
+//                                                                                             vHash[nHashIndex].c_str());
+
+               if (fNewlyGenerated)
+               {
+                       //printf("Pre-calculating hash %d of %d.\t\t\r", nHashIndex+1, vHash.size());
+                       printf("Pre-calculating hash %d of %d.%-20s\r", nHashIndex+1, vHash.size(), "");
+                       threadPool.clear();
+                       pThreads.clear();
+                       
+                       int thread_ID;
+                       for (thread_ID = 0; thread_ID < maxThreads; thread_ID++)
+                       {
+                               rcrackiThread* r_Thread = new rcrackiThread(TargetHash, thread_ID, nRainbowChainLen, maxThreads, pStartPosIndexE);
+                               if (r_Thread)
+                               {
+                                       pthread_t pThread;
+                                       int returnValue = pthread_create( &pThread, &attr, rcrackiThread::rcrackiThreadStaticEntryPointPthread, (void *) r_Thread);
+
+                                       if( returnValue != 0 )
+                                       {
+                                               printf("pThread creation failed, returnValue: %d\n", returnValue);
+                                       }
+                                       else
+                                       {
+                                               pThreads.push_back(pThread);
+                                       }
+
+                                       threadPool.push_back(r_Thread);
+                               }
+                               else 
+                               {
+                                       printf("r_Thread creation failed!\n");
+                               }
+                       }
+                       
+                       //printf("%d r_Threads created\t\t\n", threadPool.size());
+                       
+                       for (thread_ID = 0; thread_ID < threadPool.size(); thread_ID++)
+                       {
+                               pthread_t pThread = pThreads[thread_ID];
+                               int returnValue = pthread_join(pThread, NULL);
+                               if( returnValue != 0 )
+                               {
+                                       printf("pThread join failed, returnValue: %d\n", returnValue);
+                               }
+                                       
+                               rcrackiThread* rThread = threadPool[thread_ID];
+                               nChainWalkStep += rThread->GetChainWalkStep();
+                       }
+
+                       m_cws.StoreToFile(pStartPosIndexE, TargetHash, nHashLen);
+
+                       //printf("\npStartPosIndexE[0]: %s\n", uint64tostr(pStartPosIndexE[0]).c_str());
+                       //printf("\npStartPosIndexE[nRainbowChainLen-2]: %s\n", uint64tostr(pStartPosIndexE[nRainbowChainLen-2]).c_str());
+
+                       printf("%-50s\r", "");
+
+
+               }
+
+               threadPool.clear();
+               pThreads.clear();
+
+               //printf("Checking false alarms for hash %d of %d.\t\t\r", nHashIndex+1, vHash.size());
+               printf("Checking false alarms for hash %d of %d.%-20s\r", nHashIndex+1, vHash.size(), "");
+
+               int i;
+               for (i = 0; i < maxThreads; i++)
+               {
+                       rcrackiThread* r_Thread = new rcrackiThread(TargetHash);
+                       threadPool.push_back(r_Thread);
+               }
+
+               int thread_ID = 0;
+               int nPos;
+               for (nPos = nRainbowChainLen - 2; nPos >= 0; nPos--)
+               {
+                       uint64 nIndexEOfCurPos = pStartPosIndexE[nPos];
+               
+                       // Search matching nIndexE
+                       RainbowChain *pChainFound = BinarySearch(pChain, nRainbowChainCount, nIndexEOfCurPos, pIndex, nIndexSize, nChainStart);
+                       if (pChainFound != NULL) // For perfected indexed tables we only recieve 1 result (huge speed increase!)
+                       {
+                               rcrackiThread* rThread = threadPool[thread_ID];
+                               rThread->AddAlarmCheck(pChainFound, nPos);
+                               if (thread_ID < maxThreads - 1 ) {
+                                       thread_ID++;
+                               } else {
+                                       thread_ID = 0;
+                               }
+                       }
+               }
+
+               for (thread_ID = 0; thread_ID < maxThreads; thread_ID++)
+               {
+                       rcrackiThread* r_Thread = threadPool[thread_ID];
+                       pthread_t pThread;
+
+                       int returnValue = pthread_create( &pThread, &attr, rcrackiThread::rcrackiThreadStaticEntryPointPthread, (void *) r_Thread);
+
+                       if( returnValue != 0 )
+                       {
+                               printf("pThread creation failed, returnValue: %d\n", returnValue);
+                       }
+                       else
+                       {
+                               pThreads.push_back(pThread);
+                       }
+               }
+               
+               //printf("%d r_Threads created\t\t\n", threadPool.size());
+
+               bool foundHashInThread = false;
+               for (thread_ID = 0; thread_ID < threadPool.size(); thread_ID++)
+               {
+                       rcrackiThread* rThread = threadPool[thread_ID];
+                       pthread_t pThread = pThreads[thread_ID];
+
+                       int returnValue = pthread_join(pThread, NULL);
+                       if( returnValue != 0 )
+                       {
+                               printf("pThread join failed, returnValue: %d\n", returnValue);
+                       }
+
+                       nChainWalkStepDueToFalseAlarm += rThread->GetChainWalkStepDueToFalseAlarm();
+                       nFalseAlarm += rThread->GetnFalseAlarm();
+
+                       if (rThread->FoundHash() && !foundHashInThread) {
+                               //printf("\t\t\t\t\t\t\r");
+                               printf("%-50s\r", "");
+                               printf("plaintext of %s is %s\n", rThread->GetHash().c_str(), rThread->GetPlain().c_str());
+                               if (writeOutput)
+                               {
+                                       if (!writeResultLineToFile(outputFile, rThread->GetHash(), rThread->GetPlain(), rThread->GetBinary()))
+                                               printf("Couldn't write this result to file!\n");
+                               }
+                               hs.SetPlain(rThread->GetHash(), rThread->GetPlain(), rThread->GetBinary());
+                               
+                               FILE* file = fopen(sSessionPathName.c_str(), "a");
+                               if (file!=NULL)
+                               {
+                                       string buffer = "sHash=" + rThread->GetHash() + ":" + rThread->GetBinary() + ":" + rThread->GetPlain() + "\n";
+                                       fputs (buffer.c_str(), file);
+                                       fclose (file);
+                               }
+
+                               m_cws.DiscardWalk(pStartPosIndexE);
+                               foundHashInThread = true;
+                       }
+                       //pthread
+                       delete rThread;
+               }
+
+               pThreads.clear();
+               threadPool.clear();
+
+               //printf("\t\t\t\t\r");
+               //printf("pChainFounds: %d\n", pChainsFound.size());
+//NEXT_HASH:;
+       }
+       //printf("\t\t\t\t\t\t\t\r");
+       printf("%-50s\r", "");
+       pThreads.clear();
+       threadPool.clear();
+       pthread_attr_destroy(&attr);
+
+       //printf("debug: chain walk step: %d\n", nChainWalkStep);
+       //printf("debug: false alarm: %d\n", nFalseAlarm);
+       //printf("debug: chain walk step due to false alarm: %d\n", nChainWalkStepDueToFalseAlarm);
+
+       m_nTotalChainWalkStep += nChainWalkStep;
+       m_nTotalFalseAlarm += nFalseAlarm;
+       m_nTotalChainWalkStepDueToFalseAlarm += nChainWalkStepDueToFalseAlarm;
+}
+
+void CCrackEngine::SearchRainbowTable(string sPathName, CHashSet& hs)
+{
+       // Did we already go through this file in this session?
+       if (resumeSession)
+       {
+               vector<string> sessionFinishedPathNames;
+               if (ReadLinesFromFile(sProgressPathName.c_str(), sessionFinishedPathNames))
+               {
+                       int i;
+                       for (i = 0; i < sessionFinishedPathNames.size(); i++)
+                       {
+                               if (sessionFinishedPathNames[i] == sPathName)
+                               {
+                                       printf("Skipping %s\n", sPathName.c_str());
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       // FileName
+#ifdef _WIN32
+       int nIndex = sPathName.find_last_of('\\');
+#else
+       int nIndex = sPathName.find_last_of('/');
+#endif
+       string sFileName;
+       if (nIndex != -1)
+               sFileName = sPathName.substr(nIndex + 1);
+       else
+               sFileName = sPathName;
+
+       // Info
+       printf("%s:\n", sFileName.c_str());
+
+       // Setup
+       int nRainbowChainLen, nRainbowChainCount;
+       if (!CChainWalkContext::SetupWithPathName(sPathName, nRainbowChainLen, nRainbowChainCount))
+               return;
+       //printf("keyspace: %u\n", CChainWalkContext::GetPlainSpaceTotal());
+       // Already finished?
+       if (!hs.AnyHashLeftWithLen(CChainWalkContext::GetHashLen()))
+       {
+               printf("this table contains hashes with length %d only\n", CChainWalkContext::GetHashLen());
+               return;
+       }
+
+       // Open
+       FILE* file = fopen(sPathName.c_str(), "rb");
+       if (file != NULL)
+       {
+               // File length check
+               bool doOldFormat = CChainWalkContext::isOldFormat();
+               bool doNewFormat = CChainWalkContext::isNewFormat();
+               int sizeOfChain;
+               bool fVerified = false;
+               unsigned int nFileLen = GetFileLen(file);
+
+               if (doOldFormat)
+                       sizeOfChain = 16;
+               else
+                       sizeOfChain = 8;
+
+               //if (nFileLen % 8 != 0 || nRainbowChainCount * 8 != nFileLen)
+               if ((nFileLen % sizeOfChain != 0 || nRainbowChainCount * sizeOfChain != nFileLen) && doNewFormat == false)
+                               printf("file length mismatch\n");
+               else
+               {
+                       fseek(file, 0, SEEK_SET);
+
+                       unsigned int bytesForChainWalkSet = hs.GetStatHashTotal() * (nRainbowChainLen-1) * 8;
+                       if (debug) printf("Debug: Saving %u bytes of memory for chainwalkset.\n", bytesForChainWalkSet);
+
+                       static CMemoryPool mp(bytesForChainWalkSet);
+                       unsigned int nAllocatedSize;
+                       if (doNewFormat || doOldFormat)
+                       {
+                               RTI2Reader *pReader;
+                               if(doNewFormat) {
+                                       pReader = new RTI2Reader(sPathName);
+
+                               }
+                               if (debug) printf("Debug: This is a table in the old .rt format.\n");
+                               RainbowChainO* pChain = (RainbowChainO*)mp.Allocate(nFileLen, nAllocatedSize);
+                               if (debug) printf("Allocated %u bytes, filelen %u\n", nAllocatedSize, nFileLen);
+                               if (pChain != NULL)
+                               {
+                                       nAllocatedSize = nAllocatedSize / sizeOfChain * sizeOfChain;            // Round to sizeOfChain boundary
+
+                                       //fseek(file, 0, SEEK_SET);
+                                       //bool fVerified = false;
+                                       while (true)    // Chunk read loop
+                                       {
+                                               if (ftell(file) == nFileLen)
+                                                       break;
+
+                                               // Load table chunk
+                                               if (debug) printf("reading...\n");
+                                               unsigned int nDataRead = 0;
+                                               clock_t t1 = clock();
+                                               if (doNewFormat)
+                                               {
+                                                       nDataRead = nAllocatedSize / 16;
+                                                       pReader->ReadChains(nDataRead, pChain);
+                                                       nDataRead *= 8; // Convert from chains read to bytes
+                                                       if(nDataRead == 0) // No more data
+                                                               break;
+                                               }
+                                               else {
+                                                       nDataRead = fread(pChain, 1, nAllocatedSize, file);
+                                               }
+                                               clock_t t2 = clock();
+                                               float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                               printf("%u bytes read, disk access time: %.2f s\n", nDataRead, fTime);
+                                               m_fTotalDiskAccessTime += fTime;
+
+                                               int nRainbowChainCountRead = nDataRead / 16;
+
+                                               // Verify table chunk
+                                               if (!fVerified)
+                                               {
+                                                       printf("verifying the file...\n");
+
+                                                       // Chain length test
+                                                       int nIndexToVerify = nRainbowChainCountRead / 2;
+                                                       CChainWalkContext cwc;
+                                                       cwc.SetIndex(pChain[nIndexToVerify].nIndexS);
+                                                       int nPos;
+                                                       for (nPos = 0; nPos < nRainbowChainLen - 1; nPos++)
+                                                       {
+                                                               cwc.IndexToPlain();
+                                                               cwc.PlainToHash();
+                                                               cwc.HashToIndex(nPos);
+                                                       }
+                                                       if (cwc.GetIndex() != pChain[nIndexToVerify].nIndexE)
+                                                       {
+                                                               printf("rainbow chain length verify fail\n");
+                                                               break;
+                                                       }
+
+                                                       // Chain sort test
+                                                       int i;
+                                                       for (i = 0; i < nRainbowChainCountRead - 1; i++)
+                                                       {
+                                                               if (pChain[i].nIndexE > pChain[i + 1].nIndexE)
+                                                                       break;
+                                                       }
+                                                       if (i != nRainbowChainCountRead - 1)
+                                                       {
+                                                               printf("this file is not sorted\n");
+                                                               break;
+                                                       }
+
+                                                       fVerified = true;
+                                               }
+
+                                               // Search table chunk
+                                               t1 = clock();
+                                               SearchTableChunkOld(pChain, nRainbowChainLen, nRainbowChainCountRead, hs);
+                                               t2 = clock();
+                                               fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                               printf("cryptanalysis time: %.2f s\n", fTime);
+                                               m_fTotalCryptanalysisTime += fTime;
+
+                                               // Already finished?
+                                               if (!hs.AnyHashLeftWithLen(CChainWalkContext::GetHashLen()))
+                                                       break;
+                                       }
+                               }
+                               else
+                                       printf("memory allocation fail\n");
+                               
+                               //delete pChain;
+                       }
+                       else
+                       {
+                               static CMemoryPool mpIndex(bytesForChainWalkSet);
+                               unsigned int nAllocatedSizeIndex;
+
+                               //int nIndexSize = 0;
+                               //IndexChain *pIndex = NULL;
+
+                               FILE* fIndex = fopen(((string)(sPathName + string(".index"))).c_str(), "rb");
+                               if(fIndex != NULL)
+                               {
+                                       // File length check
+                                       unsigned int nFileLenIndex = GetFileLen(fIndex);
+                                       unsigned int nRows = nFileLenIndex / 11;
+                                       unsigned int nSize = nRows * sizeof(IndexChain);
+                                       //printf("Debug: 8\n");
+                                       if (nFileLenIndex % 11 != 0)
+                                               printf("index file length mismatch (%u bytes)\n", nFileLenIndex);
+                                       else
+                                       {
+                                               //printf("index nSize: %d\n", nSize);
+                                               //pIndex = (IndexChain*)new unsigned char[nSize];
+                                               IndexChain *pIndex = (IndexChain*)mpIndex.Allocate(nFileLenIndex, nAllocatedSizeIndex);
+                                               if (debug) printf("Debug: Allocated %u bytes for index with filelen %u\n", nAllocatedSizeIndex, nFileLenIndex);
+                                               
+                                               if (pIndex != NULL && nAllocatedSizeIndex > 0)
+                                               {
+                                                       nAllocatedSizeIndex = nAllocatedSizeIndex / sizeof(IndexChain) * sizeof(IndexChain);            // Round to sizeOfIndexChain boundary
+                                               
+                                                       fseek(fIndex, 0, SEEK_SET);
+                                                       int nProcessedIndexChains = 0;
+
+                                                       while (true)    // Index chunk read loop
+                                                       {
+                                                               if (ftell(fIndex) == nFileLenIndex)
+                                                                       break;
+
+                                                               // Load index chunk
+                                                               if (debug) printf("Debug: Setting index to 0x00 in memory, %u bytes\n", nAllocatedSizeIndex);
+                                                               memset(pIndex, 0x00, nAllocatedSizeIndex);
+                                                               printf("reading index... ");
+                                                               clock_t t1 = clock();
+                                                               unsigned int nDataRead = fread(pIndex, 1, nAllocatedSizeIndex, fIndex);
+                                                               clock_t t2 = clock();
+
+                                                               float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                               printf("%u bytes read, disk access time: %.2f s\n", nDataRead, fTime);
+                                                               m_fTotalDiskAccessTime += fTime;
+                                                       
+                                                               //nIndexSize = nFileLenIndex / 11;
+                                                               int nIndexChainCountRead = nDataRead / sizeof(IndexChain);
+                                                               //fclose(fIndex);
+                                                               unsigned int nCoveredRainbowTableChains = 0;
+                                                               for(int i = 0; i < nIndexChainCountRead; i++)
+                                                               {
+                                                                       nCoveredRainbowTableChains += pIndex[i].nChainCount;
+                                                               }
+
+                                                               //RainbowChain* pChain = (RainbowChain*)mp.Allocate(nFileLen, nAllocatedSize);
+                                                               RainbowChain* pChain = (RainbowChain*)mp.Allocate(nCoveredRainbowTableChains * sizeOfChain, nAllocatedSize);
+                                                               if (debug) printf("Debug: Allocated %u bytes for %u chains, filelen %u\n", nAllocatedSize, nCoveredRainbowTableChains, nFileLen);
+
+                                                               if (pChain != NULL && nAllocatedSize > 0)
+                                                               {
+                                                                       nAllocatedSize = nAllocatedSize / sizeOfChain * sizeOfChain;            // Round to sizeOfChain boundary
+
+                                                                       //fseek(file, 0, SEEK_SET);
+                                                                       //bool fVerified = false;
+                                                                       int nProcessedChains = 0;
+                                                                       while (true)    // Chunk read loop
+                                                                       {
+                                                                               if (ftell(file) == nFileLen)
+                                                                                       break;
+
+                                                                               if (nProcessedChains >= nCoveredRainbowTableChains)
+                                                                                       break;
+
+                                                                               // Load table chunk
+                                                                               if (debug) printf("Debug: Setting pChain to 0x00 in memory\n");
+                                                                               memset(pChain, 0x00, nAllocatedSize);
+                                                                               printf("reading table... ");
+                                                                               clock_t t1 = clock();
+                                                                               unsigned int nDataRead = fread(pChain, 1, nAllocatedSize, file);
+                                                                               clock_t t2 = clock();
+
+                                                                               float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                                               printf("%u bytes read, disk access time: %.2f s\n", nDataRead, fTime);
+                                                                               m_fTotalDiskAccessTime += fTime;
+                                                                               int nRainbowChainCountRead = nDataRead / sizeOfChain;
+                                                                               // Verify table chunk (Too lazy to implement this)
+                                                                               
+                                                                               if (!fVerified)
+                                                                               {
+                                                                                       printf("verifying the file...\n");
+
+                                                                                       // Chain length test
+                                                                                       int nIndexToVerify = nRainbowChainCountRead / 2;
+                                                                                       CChainWalkContext cwc;
+                                                                                       uint64 nIndexS;
+                                                                                       nIndexS = pChain[nIndexToVerify].nIndexS & 0x0000FFFFFFFFFFFFULL; // for first 6 bytes
+
+                                                                                       //printf("nIndexS: %s\n", uint64tostr(nIndexS).c_str());
+                                                                                       cwc.SetIndex(nIndexS);
+                                                                                       
+                                                                                       int nPos;
+                                                                                       for (nPos = 0; nPos < nRainbowChainLen - 1; nPos++)
+                                                                                       {
+                                                                                               cwc.IndexToPlain();
+                                                                                               cwc.PlainToHash();
+                                                                                               cwc.HashToIndex(nPos);
+                                                                                       }
+                                                                                       uint64 nEndPoint = 0;
+
+                                                                                       //for(int i = 0; i < nIndexSize; i++)
+                                                                                       for(int i = 0; i < nIndexChainCountRead; i++)
+                                                                                       {
+                                                                                               if(nIndexToVerify >= pIndex[i].nFirstChain && nIndexToVerify < pIndex[i].nFirstChain + pIndex[i].nChainCount) // We found the matching index
+                                                                                               { // Now we need to seek nIndexToVerify into the chains
+                                                                                                       nEndPoint += (pIndex[i].nPrefix & 0x000000FFFFFFFFFFULL) << 16; // & 0x000000FFFFFFFFFFULL for first 5 bytes
+                                                                                                       //printf("nPrefix: %s\n", uint64tostr(pIndex[i].nPrefix & 0x000000FFFFFFFFFF).c_str());
+                                                                                                       //printf("nFirstChain: %d\n", pIndex[i].nFirstChain);
+                                                                                                       //printf("nChainCount: %d\n", pIndex[i].nChainCount);
+                                                                                                       nEndPoint += pChain[nIndexToVerify].nIndexE;
+                                                                                                       break;
+                                                                                               }
+                                                                                       }
+
+                                                                                       if (cwc.GetIndex() != nEndPoint)
+                                                                                       {
+                                                                                               printf("rainbow chain length verify fail\n");
+                                                                                               break;
+                                                                                       }
+
+                                                                                       fVerified = true;
+                                                                               }
+
+                                                                               // Search table chunk
+                                                                               t1 = clock();
+                                                                               float preTime = m_fTotalCryptanalysisTime;
+
+                                                                               SearchTableChunk(pChain, nRainbowChainLen, nRainbowChainCountRead, hs, pIndex, nIndexChainCountRead, nProcessedChains);
+                                                                               float postTime = m_fTotalCryptanalysisTime;
+                                                                               t2 = clock();
+                                                                               fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
+                                                                               printf("cryptanalysis time: %.2f s\n", fTime + postTime - preTime);
+                                                                               m_fTotalCryptanalysisTime += fTime;
+                                                                               nProcessedChains += nRainbowChainCountRead;
+                                                                               // Already finished?
+                                                                               if (!hs.AnyHashLeftWithLen(CChainWalkContext::GetHashLen()))
+                                                                                       break;
+                                                                       }
+                                                               }
+                                                               else printf("memory allocation failed for rainbow table\n");
+
+                                                               //delete pChain;
+                                                       }
+                                               }
+                                               else printf("memory allocation failed for index\n");
+                                       }               
+                               }
+                               else 
+                               {
+                                       printf("Can't load index\n");
+                                       return;
+                               }
+                               fclose(fIndex);
+                               
+                               //delete pIndex;
+                       }
+               }
+               fclose(file);
+
+               if (debug) printf("Debug: writing progress to %s\n", sProgressPathName.c_str());
+               FILE* file = fopen(sProgressPathName.c_str(), "a");
+               if (file!=NULL)
+               {
+                       string buffer = sPathName + "\n";
+                       fputs (buffer.c_str(), file);
+                       fclose (file);
+               }
+       }
+       else
+               printf("can't open file\n");
+}
+
+void CCrackEngine::Run(vector<string> vPathName, CHashSet& hs, int i_maxThreads, bool resume, bool bDebug)
+{
+#ifndef _WIN32
+       tty_init();
+#endif
+       resumeSession = resume;
+       debug = bDebug;
+
+       maxThreads = i_maxThreads;
+       // Reset statistics
+       ResetStatistics();
+
+       // Sort vPathName (CChainWalkSet need it)
+       int i, j;
+       for (i = 0; i < vPathName.size() - 1; i++)
+               for (j = 0; j < vPathName.size() - i - 1; j++)
+               {
+                       if (vPathName[j] > vPathName[j + 1])
+                       {
+                               string sTemp;
+                               sTemp = vPathName[j];
+                               vPathName[j] = vPathName[j + 1];
+                               vPathName[j + 1] = sTemp;
+                       }
+               }
+
+       // Run
+       for (i = 0; i < vPathName.size() && hs.AnyhashLeft(); i++)
+       {
+               SearchRainbowTable(vPathName[i], hs);
+               printf("\n");
+       }
+
+       // delete precalc files
+       if (!keepPrecalcFiles)
+               m_cws.removePrecalcFiles();
+
+#ifndef _WIN32
+       tty_done();
+#endif
+}
+
+void CCrackEngine::setOutputFile(string sPathName)
+{
+       writeOutput = true;
+       outputFile = sPathName;
+}
+
+void CCrackEngine::setSession(string sSession, string sProgress, string sPrecalc, bool keepPrecalc)
+{
+       sSessionPathName = sSession;
+       sProgressPathName = sProgress;
+       sPrecalcPathName = sPrecalc;
+       keepPrecalcFiles = keepPrecalc;
+}
+
+float CCrackEngine::GetStatTotalDiskAccessTime()
+{
+       return m_fTotalDiskAccessTime;
+}
+/*float CCrackEngine::GetWastedTime()
+{
+       return m_fIndexTime;
+}*/
+float CCrackEngine::GetStatTotalCryptanalysisTime()
+{
+       return m_fTotalCryptanalysisTime;
+}
+
+int CCrackEngine::GetStatTotalChainWalkStep()
+{
+       return m_nTotalChainWalkStep;
+}
+
+int CCrackEngine::GetStatTotalFalseAlarm()
+{
+       return m_nTotalFalseAlarm;
+}
+
+int CCrackEngine::GetStatTotalChainWalkStepDueToFalseAlarm()
+{
+       return m_nTotalChainWalkStepDueToFalseAlarm;
+}
diff --git a/Client Applications/rcracki_mt/CrackEngine.h b/Client Applications/rcracki_mt/CrackEngine.h
new file mode 100644 (file)
index 0000000..e69bb0f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _CRACKENGINE_H
+#define _CRACKENGINE_H
+
+#include "Public.h"
+#include "HashSet.h"
+#include "ChainWalkContext.h"
+#include "MemoryPool.h"
+#include "ChainWalkSet.h"
+#include "rcrackiThread.h"
+#ifdef _WIN32
+#include <conio.h>
+#include <windows.h>
+#endif
+#include <pthread.h>
+
+class CCrackEngine
+{
+public:
+       CCrackEngine();
+       virtual ~CCrackEngine();
+
+private:
+       CChainWalkSet m_cws;
+       int maxThreads;
+       bool writeOutput;
+       bool resumeSession;
+       string outputFile;
+       string sSessionPathName;
+       string sProgressPathName;
+       string sPrecalcPathName;
+       //string sPrecalcIndexPathName;
+       bool debug;
+       bool keepPrecalcFiles;
+
+       // Statistics
+       float m_fTotalDiskAccessTime;
+       float m_fTotalCryptanalysisTime;
+       int m_nTotalChainWalkStep;
+       int m_nTotalFalseAlarm;
+       int m_nTotalChainWalkStepDueToFalseAlarm;
+       FILE *m_fChains;
+
+private:
+       void ResetStatistics();
+       RainbowChain *BinarySearch(RainbowChain *pChain, int nChainCountRead, uint64 nIndex, IndexChain *pIndex, int nIndexSize, int nIndexStart);
+       int BinarySearchOld(RainbowChainO* pChain, int nRainbowChainCount, uint64 nIndex);
+       void GetChainIndexRangeWithSameEndpoint(RainbowChainO* pChain,
+                                                                                   int nRainbowChainCount,
+                                                                                   int nChainIndex,
+                                                                                   int& nChainIndexFrom,
+                                                                                   int& nChainIndexTo);
+       void SearchTableChunk(RainbowChain* pChain, int nRainbowChainLen, int nRainbowChainCount, CHashSet& hs, IndexChain *pIndex, int nIndexSize, int nChainStart);
+       void SearchTableChunkOld(RainbowChainO* pChain, int nRainbowChainLen, int nRainbowChainCount, CHashSet& hs);
+       //bool CheckAlarm(RainbowChain* pChain, int nGuessedPos, unsigned char* pHash, CHashSet& hs);
+       //bool CheckAlarmOld(RainbowChainO* pChain, int nGuessedPos, unsigned char* pHash, CHashSet& hs);
+
+public:
+       void SearchRainbowTable(string sPathName, CHashSet& hs);
+       void Run(vector<string> vPathName, CHashSet& hs, int i_maxThreads, bool resume, bool bDebug);
+       float GetStatTotalDiskAccessTime();
+       float GetStatTotalCryptanalysisTime();
+       int   GetStatTotalChainWalkStep();
+       int   GetStatTotalFalseAlarm();
+       int   GetStatTotalChainWalkStepDueToFalseAlarm();
+       void setOutputFile(string sPathName);
+       void setSession(string sSessionPathName, string sProgressPathName, string sPrecalcPathName, bool keepPrecalc);
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/HashAlgorithm.cpp b/Client Applications/rcracki_mt/HashAlgorithm.cpp
new file mode 100644 (file)
index 0000000..66513fc
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+
+   Changes: not using OpenSSL routines the slow way anymore, as suggested by jci.
+*/
+
+#include "HashAlgorithm.h"
+
+#include "Public.h"
+
+#include <openssl/des.h>
+#include <openssl/md2.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <openssl/md5.h>
+#include <openssl/md4.h>
+
+//#include "md5.h"
+#include "fast_md5.h"
+#include "md4.h"
+#include "sha1.h"
+#ifdef _WIN32
+       #pragma comment(lib, "libeay32.lib")
+#endif
+#define MSCACHE_HASH_SIZE 16
+void setup_des_key(unsigned char key_56[], des_key_schedule &ks)
+{
+       des_cblock key;
+
+       key[0] = key_56[0];
+       key[1] = (key_56[0] << 7) | (key_56[1] >> 1);
+       key[2] = (key_56[1] << 6) | (key_56[2] >> 2);
+       key[3] = (key_56[2] << 5) | (key_56[3] >> 3);
+       key[4] = (key_56[3] << 4) | (key_56[4] >> 4);
+       key[5] = (key_56[4] << 3) | (key_56[5] >> 5);
+       key[6] = (key_56[5] << 2) | (key_56[6] >> 6);
+       key[7] = (key_56[6] << 1);
+
+       //des_set_odd_parity(&key);
+       des_set_key(&key, ks);
+}
+
+void HashLM(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       /*
+       unsigned char data[7] = {0};
+       memcpy(data, pPlain, nPlainLen > 7 ? 7 : nPlainLen);
+       */
+
+       int i;
+       for (i = nPlainLen; i < 7; i++)
+               pPlain[i] = 0;
+
+       static unsigned char magic[] = {0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+       des_key_schedule ks;
+       //setup_des_key(data, ks);
+       setup_des_key(pPlain, ks);
+       des_ecb_encrypt((des_cblock*)magic, (des_cblock*)pHash, ks, DES_ENCRYPT);
+}
+
+void HashLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       unsigned char pass[14];
+       unsigned char pre_lmresp[21];
+       static unsigned char magic[] = {0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+       static unsigned char spoofed_challange[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; 
+       des_key_schedule ks;
+
+       memset (pass,0,sizeof(pass));
+       memset (pre_lmresp,0,sizeof(pre_lmresp));
+
+       memcpy (pass,pPlain, nPlainLen);
+
+       setup_des_key(pass, ks);
+       des_ecb_encrypt((des_cblock*)magic, (des_cblock*)pre_lmresp, ks, DES_ENCRYPT);
+
+       setup_des_key(&pass[7], ks);
+       des_ecb_encrypt((des_cblock*)magic, (des_cblock*)&pre_lmresp[8], ks, DES_ENCRYPT);
+
+       setup_des_key(pre_lmresp, ks);
+       des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)pHash, ks, DES_ENCRYPT);
+
+       setup_des_key(&pre_lmresp[7], ks);
+       des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)&pHash[8], ks, DES_ENCRYPT);
+
+       setup_des_key(&pre_lmresp[14], ks);
+       des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)&pHash[16], ks, DES_ENCRYPT);
+
+} 
+
+void HashHALFLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{      
+       unsigned char pre_lmresp[8];
+       static unsigned char magic[] = {0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+       static unsigned char salt[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
+
+       des_key_schedule ks;
+       unsigned char plain[8] = {0};   
+       memcpy(plain, pPlain, nPlainLen);
+       setup_des_key(plain, ks);
+       des_ecb_encrypt((des_cblock*)magic, (des_cblock*)pre_lmresp, ks, DES_ENCRYPT);
+
+       setup_des_key(pre_lmresp, ks);
+       des_ecb_encrypt((des_cblock*)salt, (des_cblock*)pHash, ks, DES_ENCRYPT);
+} 
+
+
+
+void HashNTLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+  unsigned char UnicodePlain[MAX_PLAIN_LEN];
+  static unsigned char spoofed_challange[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; 
+  
+  int len = (nPlainLen < 127) ? nPlainLen : 127;
+  int i;
+  
+  for (i = 0; i < len; i++)
+  {
+    UnicodePlain[i * 2] = pPlain[i];
+    UnicodePlain[i * 2 + 1] = 0x00;
+  }
+
+  des_key_schedule ks;
+  unsigned char lm[21];
+
+  /*MD4_CTX ctx;
+  MD4_Init(&ctx);
+  MD4_Update(&ctx, UnicodePlain, len * 2);
+  MD4_Final(lm, &ctx);  */
+  MD4_NEW(UnicodePlain, len * 2, lm);
+
+  //MD4(UnicodePlain, len * 2, lm);
+  lm[16] = lm[17] = lm[18] = lm[19] = lm[20] = 0;
+
+  setup_des_key(lm, ks);
+  des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)pHash, ks, DES_ENCRYPT);
+
+  setup_des_key(&lm[7], ks);
+  des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)&pHash[8], ks, DES_ENCRYPT);
+
+  setup_des_key(&lm[14], ks);
+  des_ecb_encrypt((des_cblock*)spoofed_challange, (des_cblock*)&pHash[16], ks, DES_ENCRYPT);
+}
+
+
+void HashORACLE(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       char ToEncrypt[256];
+       char temp[256];
+       char username[256];
+
+       DES_cblock iv,iv2;
+       DES_key_schedule ks1,ks2;
+       unsigned char deskey_fixed[]={ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+       int i,j;
+
+       strcpy (username, "SYS");
+       int userlen = 3;
+       
+       strupr ((char*) pPlain);
+       memset (ToEncrypt,0,sizeof(ToEncrypt));
+
+       for (i=1,j=0; j<userlen; i++,j++)
+       {
+               ToEncrypt[i] = username[j];
+               i++;
+       }
+
+       for (j=0; j<nPlainLen; i++,j++)
+       {
+               ToEncrypt[i] = pPlain[j];
+               i++;
+       }
+
+       i=i-1;
+       memset (iv,0,8);
+       memset (iv2,0,8);
+       DES_set_key((DES_cblock*) deskey_fixed, &ks1);
+       DES_ncbc_encrypt((unsigned char*) ToEncrypt, (unsigned char*) temp, i, &ks1, &iv, DES_ENCRYPT);
+       DES_set_key((DES_cblock*) &iv, &ks2);
+       DES_ncbc_encrypt((unsigned char*) ToEncrypt, (unsigned char*) temp, i, &ks2, &iv2, DES_ENCRYPT);
+       memcpy (pHash,iv2,8);
+}
+
+void HashNTLM(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       unsigned char UnicodePlain[MAX_PLAIN_LEN * 2];
+       int i;
+       for (i = 0; i < nPlainLen; i++)
+       {
+               UnicodePlain[i * 2] = pPlain[i];
+               UnicodePlain[i * 2 + 1] = 0x00;
+       }
+
+       /*MD4_CTX ctx;
+       MD4_Init(&ctx);
+       MD4_Update(&ctx, UnicodePlain, nPlainLen * 2);
+       MD4_Final(pHash, &ctx);*/
+
+       //MD4(UnicodePlain, nPlainLen * 2, pHash);
+       MD4_NEW(UnicodePlain, nPlainLen * 2, pHash);
+}
+
+void HashMD2(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       MD2_CTX ctx;
+       MD2_Init(&ctx);
+       MD2_Update(&ctx, pPlain, nPlainLen);
+       MD2_Final(pHash, &ctx);
+
+       //MD2(pPlain, nPlainLen, pHash);
+}
+
+void HashMD4(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       /*MD4_CTX ctx;
+       MD4_Init(&ctx);
+       MD4_Update(&ctx, pPlain, nPlainLen);
+       MD4_Final(pHash, &ctx);*/
+
+       MD4_NEW(pPlain, nPlainLen, pHash);
+       //MD4(pPlain, nPlainLen, pHash);
+}
+
+void HashMD5(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       //MD5_NEW(pPlain, nPlainLen, pHash);
+       fast_MD5(pPlain, nPlainLen, pHash);
+}
+void HashDoubleMD5(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       //MD5_NEW(pPlain, nPlainLen, pHash);
+       fast_MD5(pPlain, nPlainLen, pHash);
+       unsigned char hash[16];
+       memcpy(hash, pHash, 16);
+       //MD5_NEW(hash, 16, pHash);
+       fast_MD5(hash, 16, pHash);
+}
+
+void HashSHA1(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       /*SHA_CTX ctx;
+       SHA1_Init(&ctx);
+       SHA1_Update(&ctx, pPlain, nPlainLen);
+       SHA1_Final(pHash, &ctx);*/
+
+       //SHA1(pPlain, nPlainLen, pHash);
+       SHA1_NEW(pPlain, nPlainLen, pHash);
+}
+
+void HashRIPEMD160(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       RIPEMD160_CTX ctx;
+       RIPEMD160_Init(&ctx);
+       RIPEMD160_Update(&ctx, pPlain, nPlainLen);
+       RIPEMD160_Final(pHash, &ctx);  
+
+       //RIPEMD160(pPlain, nPlainLen, pHash);
+}
+
+void HashMSCACHE(unsigned char *pPlain, int nPlainLen, unsigned char* pHash)
+{
+       char unicode_pwd[256];
+       char unicode_user[256];
+       static unsigned char username[] = "administrator";
+       static int userlen = 13;
+       unsigned char   final1[MD4_DIGEST_LENGTH];
+       MD4_CTX ctx;
+       int i;
+
+//     strcpy (username, "administrator");
+//     userlen = 13;
+
+       for (i=0; i<nPlainLen; i++)
+       {
+               unicode_pwd[i*2] = pPlain[i];
+               unicode_pwd[i*2+1] = 0x00;
+       }
+
+       for (i=0; i<userlen; i++)
+       {
+               unicode_user[i*2] = username[i];
+               unicode_user[i*2+1] = 0x00;
+       }
+
+       MD4_Init(&ctx);
+       MD4_Update(&ctx,unicode_pwd,nPlainLen*2);
+       MD4_Final(final1,&ctx);
+
+       MD4_Init(&ctx);
+       MD4_Update(&ctx,final1,MD4_DIGEST_LENGTH);
+       MD4_Update(&ctx,(unsigned char*) unicode_user,userlen*2);
+       MD4_Final(pHash,&ctx);
+
+       /*
+       unsigned char unicode_pwd[256];
+       for (int i=0; i<nPlainLen; i++)
+       {
+               unicode_pwd[i*2] = pPlain[i];
+               unicode_pwd[i*2+1] = 0x00;
+       }*/     
+       /*
+       unsigned char *buf = (unsigned char*)calloc(MSCACHE_HASH_SIZE + nSaltLength, sizeof(unsigned char));    
+       HashNTLM(pPlain, nPlainLen, buf, NULL);
+       //MD4(unicode_pwd, nPlainLen*2, buf);
+       memcpy(buf + MSCACHE_HASH_SIZE, pSalt, nSaltLength);
+       MD4(buf, MSCACHE_HASH_SIZE + nSaltLength, pHash); 
+       free(buf);
+       */
+}
+
+//*********************************************************************************
+// Code for MySQL password hashing
+//*********************************************************************************
+
+inline void mysql_hash_password_323(unsigned long *result, const char *password) 
+{
+  register unsigned long nr=1345345333L, add=7, nr2=0x12345671L;
+  unsigned long tmp;
+  for (; *password ; password++) 
+  {
+    if (*password == ' ' || *password == '\t') continue;
+       tmp= (unsigned long) (unsigned char) *password;
+       nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+       nr2+=(nr2 << 8) ^ nr;
+       add+=tmp;
+  }
+  result[0]=nr & (((unsigned long) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+  result[1]=nr2 & (((unsigned long) 1L << 31) -1L);
+  return;
+}
+
+void HashMySQL323(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       unsigned long hash_pass[2];     
+       unsigned char* f = (unsigned char*) hash_pass;
+
+       unsigned char* pass = (unsigned char*) calloc (nPlainLen+4,sizeof(unsigned char));
+       memcpy(pass,pPlain,nPlainLen);
+
+       mysql_hash_password_323(hash_pass, (char*) pass);
+       pHash[0]=*(f+3); pHash[1]=*(f+2); pHash[2]=*(f+1); pHash[3]=*(f+0);
+       pHash[4]=*(f+7); pHash[5]=*(f+6); pHash[6]=*(f+5); pHash[7]=*(f+4);
+
+       free (pass);
+}
+
+void HashMySQLSHA1(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       unsigned char hash_stage1[SHA_DIGEST_LENGTH];
+       SHA_CTX ctx;
+
+       SHA1_Init(&ctx);
+       SHA1_Update(&ctx, (unsigned char *) pPlain, nPlainLen);
+       SHA1_Final(hash_stage1, &ctx);
+       SHA1_Init(&ctx);
+       SHA1_Update(&ctx, hash_stage1, SHA_DIGEST_LENGTH);
+       SHA1_Final(pHash, &ctx);
+}
+
+//*********************************************************************************
+// Code for PIX password hashing
+//*********************************************************************************
+static char itoa64[] =          /* 0 ... 63 => ascii - 64 */
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void _crypt_to64(char *s, unsigned long v, int n)
+{
+        while (--n >= 0) {
+                *s++ = itoa64[v&0x3f];
+                v >>= 6;
+        }
+}
+
+void HashPIX(unsigned char* pPlain, int nPlainLen, unsigned char* pHash)
+{
+       char temp[MD5_DIGEST_LENGTH+1];
+       unsigned char final[MD5_DIGEST_LENGTH];
+       char* pass = (char*) calloc (nPlainLen+MD5_DIGEST_LENGTH,sizeof(char));
+
+       memcpy (pass,pPlain,nPlainLen);
+
+       /*MD5_CTX ctx;
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, (unsigned char *) pass, MD5_DIGEST_LENGTH);
+       MD5_Final(final, &ctx);*/
+       fast_MD5((unsigned char *) pass, MD5_DIGEST_LENGTH, final);
+
+       char* p = (char*) temp;
+       _crypt_to64(p,*(unsigned long*) (final+0),4); p += 4;
+       _crypt_to64(p,*(unsigned long*) (final+4),4); p += 4;
+       _crypt_to64(p,*(unsigned long*) (final+8),4); p += 4;
+       _crypt_to64(p,*(unsigned long*) (final+12),4); p += 4;
+       *p=0;
+
+       memcpy(pHash,temp,MD5_DIGEST_LENGTH);
+
+       free (pass);
+}
+
+#ifndef _WIN32
+char *strupr(char *s1)
+{
+       char *p = s1;
+       while(*p)
+       {
+               toupper(*p);
+               p++;
+       }
+       return s1;
+}
+#endif
diff --git a/Client Applications/rcracki_mt/HashAlgorithm.h b/Client Applications/rcracki_mt/HashAlgorithm.h
new file mode 100644 (file)
index 0000000..9958cbc
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _HASHALGORITHM_H
+#define _HASHALGORITHM_H
+
+void HashLM(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashNTLM(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashMD2(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashMD4(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashMD5(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashDoubleMD5(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashSHA1(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashRIPEMD160(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashMSCACHE(unsigned char *pPlain, int nPlainLen, unsigned char* pHash);
+//****************************************************************************
+// MySQL Password Hashing
+//****************************************************************************
+void HashMySQL323(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashMySQLSHA1(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+
+//****************************************************************************
+// Cisco PIX Password Hashing
+//****************************************************************************
+void HashPIX(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+
+//****************************************************************************
+// (HALF) LM CHALL hashing
+void HashLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashHALFLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+
+// From mao
+void HashNTLMCHALL(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+void HashORACLE(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+
+#ifndef _WIN32
+char *strupr(char *s1);
+#endif
+#endif
diff --git a/Client Applications/rcracki_mt/HashRoutine.cpp b/Client Applications/rcracki_mt/HashRoutine.cpp
new file mode 100644 (file)
index 0000000..02fbe71
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "HashRoutine.h"
+#include "HashAlgorithm.h"
+
+//////////////////////////////////////////////////////////////////////
+
+CHashRoutine::CHashRoutine()
+{
+       // Notice: MIN_HASH_LEN <= nHashLen <= MAX_HASH_LEN
+
+
+       AddHashRoutine("lm",   HashLM,   8);
+       AddHashRoutine("ntlm", HashNTLM, 16);
+       AddHashRoutine("md2",  HashMD2,  16);
+       AddHashRoutine("md4",  HashMD4,  16);
+       AddHashRoutine("md5",  HashMD5,  16);
+       AddHashRoutine("doublemd5",  HashDoubleMD5,  16);
+       AddHashRoutine("sha1", HashSHA1, 20);
+       AddHashRoutine("ripemd160", HashRIPEMD160, 20);
+       AddHashRoutine("mysql323", HashMySQL323, 8);
+       AddHashRoutine("mysqlsha1", HashMySQLSHA1, 20);
+       AddHashRoutine("ciscopix", HashPIX, 16);
+       AddHashRoutine("mscache", HashMSCACHE, 16);
+       AddHashRoutine("halflmchall", HashHALFLMCHALL, 8);
+
+       // Added from mao
+       AddHashRoutine("lmchall", HashLMCHALL, 24);
+       AddHashRoutine("ntlmchall", HashNTLMCHALL, 24);
+       AddHashRoutine("oracle", HashORACLE, 8);
+
+}
+
+CHashRoutine::~CHashRoutine()
+{
+}
+
+void CHashRoutine::AddHashRoutine(string sHashRoutineName, HASHROUTINE pHashRoutine, int nHashLen)
+{
+       vHashRoutineName.push_back(sHashRoutineName);
+       vHashRoutine.push_back(pHashRoutine);
+       vHashLen.push_back(nHashLen);
+}
+
+string CHashRoutine::GetAllHashRoutineName()
+{
+       string sRet;
+       int i;
+       for (i = 0; i < vHashRoutineName.size(); i++)
+               sRet += vHashRoutineName[i] + " ";
+
+       return sRet;
+}
+
+void CHashRoutine::GetHashRoutine(string sHashRoutineName, HASHROUTINE& pHashRoutine, int& nHashLen)
+{
+       int i;
+       for (i = 0; i < vHashRoutineName.size(); i++)
+       {
+               if (sHashRoutineName == vHashRoutineName[i])
+               {
+                       pHashRoutine = vHashRoutine[i];
+                       nHashLen = vHashLen[i];
+                       return;
+               }
+       }
+
+       pHashRoutine = NULL;
+       nHashLen = 0;
+}
diff --git a/Client Applications/rcracki_mt/HashRoutine.h b/Client Applications/rcracki_mt/HashRoutine.h
new file mode 100644 (file)
index 0000000..681fa78
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _HASHROUTINE_H
+#define _HASHROUTINE_H
+
+#include <string>
+#include <vector>
+using namespace std;
+
+typedef void (*HASHROUTINE)(unsigned char* pPlain, int nPlainLen, unsigned char* pHash);
+
+class CHashRoutine  
+{
+public:
+       CHashRoutine();
+       virtual ~CHashRoutine();
+
+private:
+       vector<string>          vHashRoutineName;
+       vector<HASHROUTINE>     vHashRoutine;
+       vector<int>                     vHashLen;
+       void AddHashRoutine(string sHashRoutineName, HASHROUTINE pHashRoutine, int nHashLen);
+
+public:
+       string GetAllHashRoutineName();
+       void GetHashRoutine(string sHashRoutineName, HASHROUTINE& pHashRoutine, int& nHashLen);
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/HashSet.cpp b/Client Applications/rcracki_mt/HashSet.cpp
new file mode 100644 (file)
index 0000000..cf8afdb
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "HashSet.h"
+
+CHashSet::CHashSet()
+{
+}
+
+CHashSet::~CHashSet()
+{
+}
+
+void CHashSet::AddHash(string sHash)
+{
+       if (sHash == "aad3b435b51404ee")
+               return;
+
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (m_vHash[i] == sHash)
+                       return;
+       }
+
+       //printf("debug: adding hash %s\n", sHash.c_str());
+
+       m_vHash.push_back(sHash);
+       m_vFound.push_back(false);
+       m_vPlain.push_back("");
+       m_vBinary.push_back("");
+}
+
+string CHashSet::GetHashInfo(int i)
+{
+       string found;
+       if (m_vFound[i])
+               found = "1";
+       else
+               found = "0";
+
+       string buffer = m_vHash[i] + ":" + found + ":" + m_vPlain[i] + ":" + m_vBinary[i];
+
+       return buffer;
+}
+
+bool CHashSet::AnyhashLeft()
+{
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (!m_vFound[i])
+                       return true;
+       }
+
+       return false;
+}
+
+bool CHashSet::AnyHashLeftWithLen(int nLen)
+{
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (!m_vFound[i])
+                       if (m_vHash[i].size() == nLen * 2)
+                               return true;
+       }
+
+       return false;
+}
+
+void CHashSet::GetLeftHashWithLen(vector<string>& vHash, int nLen)
+{
+       vHash.clear();
+
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (!m_vFound[i])
+                       if (m_vHash[i].size() == nLen * 2)
+                               vHash.push_back(m_vHash[i]);
+       }
+}
+
+void CHashSet::AddHashInfo(string sHash, bool found, string sPlain, string sBinary)
+{
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (m_vHash[i] == sHash)
+                       return;
+       }
+
+       m_vHash.push_back(sHash);
+       m_vFound.push_back(found);
+       m_vPlain.push_back(sPlain);
+       m_vBinary.push_back(sBinary);
+}
+
+void CHashSet::SetPlain(string sHash, string sPlain, string sBinary)
+{
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (m_vHash[i] == sHash)
+               {
+                       m_vFound[i]    = true;
+                       m_vPlain[i]    = sPlain;
+                       m_vBinary[i]   = sBinary;
+                       return;
+               }
+       }
+}
+
+bool CHashSet::GetPlain(string sHash, string& sPlain, string& sBinary)
+{
+       if (sHash == "aad3b435b51404ee")
+       {
+               sPlain  = "";
+               sBinary = "";
+               return true;
+       }
+
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (m_vHash[i] == sHash)
+               {
+                       if (m_vFound[i])
+                       {
+                               sPlain  = m_vPlain[i];
+                               sBinary = m_vBinary[i];
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+int CHashSet::GetStatHashFound()
+{
+       int nHashFound = 0;
+       int i;
+       for (i = 0; i < m_vHash.size(); i++)
+       {
+               if (m_vFound[i])
+                       nHashFound++;
+       }
+
+       return nHashFound;
+}
+
+int CHashSet::GetStatHashTotal()
+{
+       return m_vHash.size();
+}
diff --git a/Client Applications/rcracki_mt/HashSet.h b/Client Applications/rcracki_mt/HashSet.h
new file mode 100644 (file)
index 0000000..746bb72
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _HASHSET_H
+#define _HASHSET_H
+
+#include "Public.h"
+
+class CHashSet
+{
+public:
+       CHashSet();
+       virtual ~CHashSet();
+
+private:
+       vector<string> m_vHash;
+       vector<bool>   m_vFound;
+       vector<string> m_vPlain;
+       vector<string> m_vBinary;
+
+public:
+       void AddHash(string sHash);             // lowercase, len % 2 == 0, MIN_HASH_LEN * 2 <= len <= MAX_HASH_LEN * 2
+       bool AnyhashLeft();
+       bool AnyHashLeftWithLen(int nLen);
+       void GetLeftHashWithLen(vector<string>& vHash, int nLen);
+       
+       void SetPlain(string sHash, string sPlain, string sBinary);
+       bool GetPlain(string sHash, string& sPlain, string& sBinary);
+
+       int GetStatHashFound();
+       int GetStatHashTotal();
+
+       string GetHashInfo(int i);
+       void AddHashInfo(string sHash, bool found, string sPlain, string sBinary);
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/Makefile b/Client Applications/rcracki_mt/Makefile
new file mode 100644 (file)
index 0000000..f6329ac
--- /dev/null
@@ -0,0 +1,5 @@
+rcracki_mt:
+       g++ *.cpp -lssl -lpthread -O3 -o rcracki_mt
+
+clean:
+       rm rcracki_mt
diff --git a/Client Applications/rcracki_mt/MemoryPool.cpp b/Client Applications/rcracki_mt/MemoryPool.cpp
new file mode 100644 (file)
index 0000000..2129daa
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#include "MemoryPool.h"
+#include "Public.h"
+
+CMemoryPool::CMemoryPool(unsigned int bytesForChainWalkSet)
+{
+       m_pMem = NULL;
+       m_nMemSize = 0;
+
+       unsigned int nAvailPhys = GetAvailPhysMemorySize();
+       if (nAvailPhys < 32 * 1024 * 1024)
+       {
+               nAvailPhys = 256 * 1024 * 1024; // There is atleast 256 mb available (Some Linux distros returns a really low GetAvailPhysMemorySize())
+       }
+       
+       m_nMemMax = nAvailPhys - bytesForChainWalkSet;  // Leave memory for CChainWalkSet       
+
+       if (m_nMemMax < 16 * 1024 * 1024)
+               m_nMemMax = 16 * 1024 * 1024;
+
+}
+
+CMemoryPool::~CMemoryPool()
+{
+       if (m_pMem != NULL)
+       {
+               delete m_pMem;
+               m_pMem = NULL;
+               m_nMemSize = 0;
+       }
+}
+
+unsigned char* CMemoryPool::Allocate(unsigned int nFileLen, unsigned int& nAllocatedSize)
+{
+       if (nFileLen <= m_nMemSize)
+       {
+               nAllocatedSize = nFileLen;
+               return m_pMem;
+       }
+
+       unsigned int nTargetSize;
+       if (nFileLen < m_nMemMax)
+               nTargetSize = nFileLen;
+       else
+               nTargetSize = m_nMemMax;
+
+       // Free existing memory
+       if (m_pMem != NULL)
+       {
+               delete m_pMem;
+               m_pMem = NULL;
+               m_nMemSize = 0;
+       }
+
+       // Allocate new memory
+       //printf("allocating %u bytes memory\n", nTargetSize);
+       m_pMem = new (nothrow) unsigned char[nTargetSize];
+       while (m_pMem == NULL && nTargetSize >= 32 * 1024 * 1024 )
+       {
+          nTargetSize -= 16 * 1024 * 1024;
+          m_pMem = new (nothrow) unsigned char[nTargetSize];
+       }
+
+       if (m_pMem != NULL)
+       {
+               m_nMemSize = nTargetSize;
+               nAllocatedSize = nTargetSize;
+               return m_pMem;
+       }
+       else
+       {
+               m_nMemSize = 0;
+               nAllocatedSize = 0;
+               return NULL;
+       }
+}
diff --git a/Client Applications/rcracki_mt/MemoryPool.h b/Client Applications/rcracki_mt/MemoryPool.h
new file mode 100644 (file)
index 0000000..91d8214
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _MEMORYPOOL_H
+#define _MEMORYPOOL_H
+
+class CMemoryPool  
+{
+public:
+       CMemoryPool(unsigned int bytesForChainWalkSet);
+       virtual ~CMemoryPool();
+
+private:
+       unsigned char* m_pMem;
+       unsigned int m_nMemSize;
+
+       unsigned int m_nMemMax;
+
+public:
+       unsigned char* Allocate(unsigned int nFileLen, unsigned int& nAllocatedSize);
+};
+
+#endif
diff --git a/Client Applications/rcracki_mt/Public.cpp b/Client Applications/rcracki_mt/Public.cpp
new file mode 100644 (file)
index 0000000..6b98157
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "Public.h"
+
+#ifdef _WIN32
+       #include <windows.h>
+#else
+       #include <sys/sysinfo.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+unsigned int GetFileLen(FILE* file)
+{
+       unsigned int pos = ftell(file);
+       fseek(file, 0, SEEK_END);
+       unsigned int len = ftell(file);
+       fseek(file, pos, SEEK_SET);
+
+       return len;
+}
+
+string TrimString(string s)
+{
+       while (s.size() > 0)
+       {
+               if (s[0] == ' ' || s[0] == '\t')
+                       s = s.substr(1);
+               else
+                       break;
+       }
+
+       while (s.size() > 0)
+       {
+               if (s[s.size() - 1] == ' ' || s[s.size() - 1] == '\t')
+                       s = s.substr(0, s.size() - 1);
+               else
+                       break;
+       }
+
+       return s;
+}
+bool GetHybridCharsets(string sCharset, vector<tCharset>& vCharset)
+{
+       // Example: hybrid(mixalpha-numeric-all-space#1-6,numeric#1-4)
+       if(sCharset.substr(0, 6) != "hybrid") // Not hybrid charset
+               return false;
+       size_t nEnd = sCharset.rfind(')');
+       size_t nStart = sCharset.rfind('(');
+       string sChar = sCharset.substr(nStart + 1, nEnd - nStart - 1);
+       vector<string> vParts;
+       SeperateString(sChar, ",", vParts);
+       for(int i = 0; i < vParts.size(); i++)
+       {
+               tCharset stCharset;
+               vector<string> vParts2;
+               SeperateString(vParts[i], "#", vParts2);
+               stCharset.sName = vParts2[0];
+               vector<string> vParts3;
+               SeperateString(vParts2[1], "-", vParts3);
+               stCharset.nPlainLenMin = atoi(vParts3[0].c_str());
+               stCharset.nPlainLenMax = atoi(vParts3[1].c_str());
+               vCharset.push_back(stCharset);
+       }
+       return true;
+}
+bool ReadLinesFromFile(string sPathName, vector<string>& vLine)
+{
+       vLine.clear();
+
+       FILE* file = fopen(sPathName.c_str(), "rb");
+       if (file != NULL)
+       {
+               unsigned int len = GetFileLen(file);
+               char* data = new char[len + 1];
+               fread(data, 1, len, file);
+               data[len] = '\0';
+               string content = data;
+               content += "\n";
+               delete data;
+
+               unsigned int i;
+               for (i = 0; i < content.size(); i++)
+               {
+                       if (content[i] == '\r')
+                               content[i] = '\n';
+               }
+
+               int n;
+               while ((n = content.find("\n", 0)) != -1)
+               {
+                       string line = content.substr(0, n);
+                       line = TrimString(line);
+                       if (line != "")
+                               vLine.push_back(line);
+                       content = content.substr(n + 1);
+               }
+
+               fclose(file);
+       }
+       else
+               return false;
+
+       return true;
+}
+
+bool writeResultLineToFile(string sOutputFile, string sHash, string sPlain, string sBinary)
+{
+       FILE* file = fopen(sOutputFile.c_str(), "a");
+       if (file!=NULL)
+       {
+               string buffer = sHash + ":" + sPlain + ":" + sBinary + "\n";
+               fputs (buffer.c_str(), file);
+               fclose (file);
+               return true;
+       }
+       else
+               return false;
+}
+
+bool SeperateString(string s, string sSeperator, vector<string>& vPart)
+{
+       vPart.clear();
+
+       unsigned int i;
+       for (i = 0; i < sSeperator.size(); i++)
+       {
+               int n = s.find(sSeperator[i]);
+               if (n != -1)
+               {
+                       vPart.push_back(s.substr(0, n));
+                       s = s.substr(n + 1);
+               }
+               else
+               {
+                       printf("not found: %c\n", sSeperator[i]);
+                       printf("s: %s\n", s.c_str());
+                       return false;
+               }
+       }
+       vPart.push_back(s);
+
+       return true;
+}
+
+string uint64tostr(uint64 n)
+{
+       char str[32];
+
+#ifdef _WIN32
+       sprintf(str, "%I64u", n);
+#else
+       sprintf(str, "%llu", n);
+#endif
+
+       return str;
+}
+
+string uint64tohexstr(uint64 n)
+{
+       char str[32];
+
+#ifdef _WIN32
+       sprintf(str, "%016I64x", n);
+#else
+       sprintf(str, "%016llx", n);
+#endif
+
+       return str;
+}
+
+string HexToStr(const unsigned char* pData, int nLen)
+{
+       string sRet;
+       int i;
+       for (i = 0; i < nLen; i++)
+       {
+               char szByte[3];
+               sprintf(szByte, "%02x", pData[i]);
+               sRet += szByte;
+       }
+
+       return sRet;
+}
+
+unsigned int GetAvailPhysMemorySize()
+{
+#ifdef _WIN32
+               MEMORYSTATUS ms;
+               GlobalMemoryStatus(&ms);
+               return ms.dwAvailPhys;
+#else
+       struct sysinfo info;
+       sysinfo(&info);                 // This function is Linux-specific
+       return info.freeram;
+#endif
+}
+
+string GetApplicationPath()
+{
+       char fullPath[FILENAME_MAX];
+
+#ifdef _WIN32
+       GetModuleFileName(NULL, fullPath, FILENAME_MAX);
+#else
+       char szTmp[32];
+       sprintf(szTmp, "/proc/%d/exe", getpid());
+       int bytes = readlink(szTmp, fullPath, FILENAME_MAX);
+       if(bytes >= 0)
+               fullPath[bytes] = '\0';
+#endif
+
+       string sApplicationPath = fullPath;
+#ifdef _WIN32
+       int nIndex = sApplicationPath.find_last_of('\\');
+#else
+       int nIndex = sApplicationPath.find_last_of('/');
+#endif
+
+       if (nIndex != -1)
+               sApplicationPath = sApplicationPath.substr(0, nIndex+1);
+
+       //printf ("\n\nDebug: The application directory is %s\n", sApplicationPath.c_str());
+       return sApplicationPath;
+}
+
+void ParseHash(string sHash, unsigned char* pHash, int& nHashLen)
+{
+       int i;
+       for (i = 0; i < sHash.size() / 2; i++)
+       {
+               string sSub = sHash.substr(i * 2, 2);
+               int nValue;
+               sscanf(sSub.c_str(), "%02x", &nValue);
+               pHash[i] = (unsigned char)nValue;
+       }
+
+       nHashLen = sHash.size() / 2;
+}
+
+void Logo()
+{
+       printf("RainbowCrack (improved, multi-threaded) - Making a Faster Cryptanalytic Time-Memory Trade-Off\n");
+       printf("by Martin Westergaard <martinwj2005@gmail.com>\n");
+       printf("multi-threaded and enhanced by neinbrucke (version 0.6-svn)\n");
+       printf("http://www.freerainbowtables.com/\n");
+       printf("original code by Zhu Shuanglei <shuanglei@hotmail.com>\n");
+       printf("http://www.antsight.com/zsl/rainbowcrack/\n\n");
+}
+
+// Code comes from nmap, used for the linux implementation of kbhit()
+#ifndef _WIN32
+
+static int tty_fd = 0;
+struct termios saved_ti;
+
+int tty_getchar()
+{
+        int c, numChars;
+
+        if (tty_fd && tcgetpgrp(tty_fd) == getpid()) {
+                c = 0;
+                numChars = read(tty_fd, &c, 1);
+                if (numChars > 0) return c;
+        }
+
+        return -1;
+}
+
+void tty_done()
+{
+        if (!tty_fd) return;
+
+        tcsetattr(tty_fd, TCSANOW, &saved_ti);
+
+        close(tty_fd);
+        tty_fd = 0;
+}
+
+void tty_init()
+{
+        struct termios ti;
+
+        if (tty_fd)
+                return;
+
+        if ((tty_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK)) < 0) return;
+
+        tcgetattr(tty_fd, &ti);
+        saved_ti = ti;
+        ti.c_lflag &= ~(ICANON | ECHO);
+        ti.c_cc[VMIN] = 1;
+        ti.c_cc[VTIME] = 0;
+        tcsetattr(tty_fd, TCSANOW, &ti);
+
+        atexit(tty_done);
+}
+
+void tty_flush(void)
+{
+        tcflush(tty_fd, TCIFLUSH);
+}
+#endif
diff --git a/Client Applications/rcracki_mt/Public.h b/Client Applications/rcracki_mt/Public.h
new file mode 100644 (file)
index 0000000..5e5e8d5
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+*/
+
+#ifndef _PUBLIC_H
+#define _PUBLIC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+#include <list>
+using namespace std;
+
+#ifdef _WIN32
+       #define uint64 unsigned __int64
+#else
+       #ifndef u_int64_t
+               #define uint64 unsigned long long
+       #else
+               #define uint64 u_int64_t
+       #endif
+#endif
+
+struct RainbowChainO
+{
+       uint64 nIndexS;
+       uint64 nIndexE;
+};
+//struct RainbowChain
+//{
+//     //uint64 nChain;
+//     uint64 nIndexS;
+//     int nIndexE;
+//     int nCheckPoint;
+//};
+
+union RainbowChain
+{
+       //uint64 nChain;
+       uint64 nIndexS; 
+       struct
+       {
+               unsigned short foo[3];
+               unsigned short nIndexE;
+       };
+       //int nCheckPoint;
+};
+//struct RainbowChain
+//{
+//     uint64 nIndexS : 48;
+//     unsigned short nIndexE : 16;
+//};
+//struct IndexChain
+//{
+//     uint64 nPrefix;
+//     int nFirstChain;
+//     int nChainCount;
+//     //unsigned short nChainCount; //(maybe union with nPrefix, 1 byte spoiled)
+//};
+#pragma pack(1)
+union IndexChain
+{
+       uint64 nPrefix; //5
+       struct
+       {
+               unsigned char foo[5];
+               int nFirstChain; //4
+               unsigned short nChainCount; //2
+       };
+       //unsigned short nChainCount; (maybe union with nPrefix, 1 byte spoiled, no pack(1) needed)
+};
+#pragma pack()
+typedef struct
+{
+       string sName;
+       int nPlainLenMin;
+       int nPlainLenMax;
+} tCharset;
+
+#define MAX_PLAIN_LEN 256
+#define MIN_HASH_LEN  8
+#define MAX_HASH_LEN  256
+#define MAX_SALT_LEN  256
+
+// Code comes from nmap, used for the linux implementation of kbhit()
+#ifndef _WIN32
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+
+int tty_getchar();
+void tty_done();
+void tty_init();
+void tty_flush(void);
+
+#endif
+
+
+unsigned int GetFileLen(FILE* file);
+string TrimString(string s);
+bool ReadLinesFromFile(string sPathName, vector<string>& vLine);
+bool SeperateString(string s, string sSeperator, vector<string>& vPart);
+string uint64tostr(uint64 n);
+string uint64tohexstr(uint64 n);
+string HexToStr(const unsigned char* pData, int nLen);
+unsigned int GetAvailPhysMemorySize();
+string GetApplicationPath();
+void ParseHash(string sHash, unsigned char* pHash, int& nHashLen);
+bool GetHybridCharsets(string sCharset, vector<tCharset>& vCharset);
+void Logo();
+bool writeResultLineToFile(string sOutputFile, string sHash, string sPlain, string sBinary);
+
+#endif
diff --git a/Client Applications/rcracki_mt/README.txt b/Client Applications/rcracki_mt/README.txt
new file mode 100644 (file)
index 0000000..b4b8cd8
--- /dev/null
@@ -0,0 +1,162 @@
+[rcracki_mt README]
+
+USAGE
+================
+example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 4 -o save.txt C:\md5
+
+Start rcracki_mt without any arguments to view usage information in short. This README describes the various 
+options in more detail. Many options can be set to a default value by editing rcracki_mt.ini. Command line 
+arguments get priority over settings in the ini file.
+
+INPUT
+----------------
+rcracki_mt takes one hash on the command line (using -h) or an input file containing the hashes. rcracki_mt supports 
+three formats for the input file. Use one of the following options to specify the format followed by the filename:
+
+-l:    specify a list of hashes (one hash per line)
+-f:    specify a pwdump file
+-c:    specify a .lst file (format in which Cain stores hashes and results)
+
+SELECTING RAINBOW TABLES
+----------------
+Any command line argument that is not an option will be interpreted as a directory to search for rainbow tables, 
+multiple directories can be specified. rcracki_mt recursively scans all specified directories for *.rti (indexed) 
+and *.rt (old/original) files. You can use .rt & .rti files at once, but this hasn't been tested thoroughly.
+
+You can set default locations to search for rainbow tables in rcracki_mt.ini. You need to use these in combination 
+with the command line argument -a [algorithm]. See the comments in the ini file for examples.
+
+SESSIONS & RESUMING
+----------------
+Rcracki_mt has session support, which means that it stores its progress. This allows you to interrupt the session 
+and resume later on. This also allows sessions that stopped because of a crash (application or even system) to 
+resume. To use this feature, start rcracki_mt with all the options you'd like, then specify a session name with:
+
+-s session_name:       specify a session name
+
+Now during cracking, all your valuable precalculations are stored to disk, as well as progress (which files have 
+been checked) and cracked hashes. If you decide to interrupt the session (using CTRL+C), you can resume it using 
+the -r option. For example:
+
+rcracki_mt -r -s my_personal_hashes
+
+While resuming rcracki_mt you can/have to specify the less important options again, like number of threads and 
+showing debug information. Usually you will have these settings set to a default value in the .ini file anyway. 
+Session are deleted after the run is completed. You can choose to keep the precalculation work on disk, for example 
+if you want to reuse your session later on. Use the '-k' option to enable this feature.
+
+Rcracki_mt has a default session which gets overwritten every time you start a new job without specifying a session 
+name. It might be interesting to always keep precalculation work by enabling this feature in rcracki_mt.ini. But 
+pay attention, these precalculations can become quite large on disk. Currently there is a maximum of around 500 GB 
+of storage for these precalculations. You can always decide to manually remove the .precalc and .precalc.index 
+files from disk. Always remove both at the same time, you will screw up your results if you don't. A possible 
+'todo' for development is to do some verification before using stored precalculations.
+
+OPTIONAL
+----------------
+-t:    Number of threads to use (for precalculation and false alarm checking)
+Note: In Windows the crack threads run with lower priority.
+
+-o:    specify an output file to store found hashes in a colon (:) separated format.
+       Hashes are saved immediately when found. Especially useful if you have a large list of hashes.
+
+-v:    Show more information during cracking, for debugging purposes. Please use this flag if you want to show 
+output and report a bug.
+
+
+EXTRA FEATURES
+----------------
+You can pause a running rcracki_mt by using 'P'. It might not pause right away, it actually pauses after doing 
+precalculation or false alarm checking for one hash. Resume by pressing 'P' again. This pause option is different 
+from the session/resume feature, as this just pauses a running job, you don't stop rcracki_mt this way.
+
+If you are trying to crack a pwdump or Cain (.lst) file, containing both LM and NTLM hashes, rcracki_mt will try 
+and crack the LM hashes. The result will be an uppercase password, which rcracki_mt will then try to correct with 
+the right casing, using the NTLM hashes. If this fails it will try and perform Unicode correction, using a built-in 
+mapping. If you happen to have an LM hash coupled with the wrong NTLM hash, this attempt to perform Unicode 
+correction might take 'forever'. You can press 'S' to skip this step for the current hash.
+
+
+HISTORY AND AUTHORS
+================
+rcracki_mt originally started as a modification of a modification (rcracki) of the original RainbowCrack (rcrack). 
+These programs are all used to perform a rainbow table attack on password hashes, implementing Philippe Oechslin's 
+faster time-memory trade-off technique.
+
+Original rcrack code was written by Zhu Shuanglei <shuanglei@hotmail.com>.
+
+Martin Westergaard Jørgensen <martinwj2005@gmail.com> wrote rcracki (improved) to support the rainbow tables 
+generated by the distributed project www.freerainbowtables.com. These tables are perfected and indexed, making them 
+faster and smaller. Rcracki also supported hybrid tables.
+
+Daniël Niggebrugge <neinbrucke> further enhanced this version and made it multi threaded, creating rcracki_mt. More 
+features were added over time, making it less of an unofficial version with every release.
+
+
+SUPPORTED HASH ALGORITHMS
+================
+Hash types supported by rcracki_mt are: LM, NTLM, MD2, MD4, MD5, DoubleMD5, SHA1, RIPEMD160, MSCACHE, MySQL323, 
+MySQLSHA1, PIX, LMCHALL, HALFLMCHALL, NTLMCHALL, ORACLE
+
+Actual indexed&perfected tables that were generated by the Free Rainbow Tables project: LM, MD5, NTL, FASTLM, 
+HALFLMCHALL, SHA1
+
+
+SUPPORTED PLATFORMS
+================
+Rcracki_mt is released both as win32 binary and as source package. Rcracki_mt should work on any Microsoft Windows system, but is only tested on a 32 bit Windows XP. The source should work on Linux versions, but this has only been tested on 32 bit Ubuntu (8.10).
+
+Some people have reported issues with compiling on 64 bit Linux. If you have trouble, please report details, as workaround try this suggested solution for AMD64 UBUNTU 8.10:
+
+    sudo apt-get install ia32-libs
+
+
+you might need to do:
+    cd /usr/lib32/
+    sudo ln -s libstdc++.so.6 libstdc++.so
+    sudo ln -s libssl.so.0.9.8 libssl.so
+
+
+add -m32 to the compilerline in the Makefile
+    g++ -m32 *.cpp -L/usr/lib32 -lssl -lpthread -O3 -o rcracki_mt
+
+
+'OPTIONAL' TODO
+================
+- verification of an endpoint when restoring a chainwalkset from disk.
+- read multiple chainwalksets from disk at once to try and speed up this process.
+- read next table (part) from disk while doing cryptanalysis
+
+
+LINKS
+================
+rcracki_mt @ SourceForge:              https://sourceforge.net/projects/rcracki/
+Original rcrack:                       http://www.antsight.com/zsl/rainbowcrack/
+Free Rainbow Tables:                   http://www.freerainbowtables.com/
+My personal blog:                      http://blog.distracted.nl/
+Download free rainbow tables:          http://tbhost.eu/
+Download free rainbow tables (mirror): http://freerainbowtables.mirror.garr.it/mirrors/freerainbowtables/
+
+
+THANKS
+================
+the_drag0n                             Writing part of this README
+<james.dickson@comhem.se>              Patch  to support Cain .lst files
+Joao Inacio <jcinacio at gmail.com>    Supplying some faster algorithm implementations
+
+
+FAQ
+================
+Q: Why do I get this message all the time? "this table contains hashes with length 8 only"
+A: You are probably trying to crack LM hashes. You have to split up the hash in 2 parts of 16 hex characters each.
+
+Q: rcracki_mt is so slow when I'm cracking 5000 hashes, why is that?
+A: Rainbow table attacks are only useful for a certain amount of hashes, mainly because of the precalculations that 
+are needed for every hash you are cracking. At a certain point it is faster to brute force the same key space then 
+to try and use rainbow tables. Especially if you use a GPU enabled brute forcer, this limit might be reached very 
+soon. Play around with these to find you limits.
+
+Q: How can I speed up rcracki_mt?
+A: This depends on quite some factors. If your jobs usually comprise of disk access time, you can try and speed up 
+your storage. For example by using RAID and/or by using solid state disks. If you are trying to crack many hashes 
+at the same time, you might be better off with buying a faster CPU.
diff --git a/Client Applications/rcracki_mt/RTI2Reader.cpp b/Client Applications/rcracki_mt/RTI2Reader.cpp
new file mode 100644 (file)
index 0000000..d58e881
--- /dev/null
@@ -0,0 +1,125 @@
+#include "RTI2Reader.h"
+
+#include <math.h>
+RTI2Header *RTI2Reader::m_pHeader = NULL;
+RTI2Reader::RTI2Reader(string Filename)
+{
+       //m_pIndexPos = NULL, m_pChainPos = NULL;;
+       m_pIndex = NULL;
+       m_pFile = fopen(Filename.c_str(), "rb");
+       if(m_pFile == NULL)
+       {
+               printf("Unable to open file %s", Filename.c_str());
+               exit(1);
+       }
+       FILE *pFileIndex = fopen(Filename.append(".index").c_str(), "rb");
+       if(pFileIndex == NULL)
+       {
+               printf("Unable to open file %s", Filename.append(".index").c_str());
+               exit(1);
+       }
+       m_chainPosition = 0;
+
+       unsigned int len = GetFileLen(pFileIndex);
+       fseek(pFileIndex, 0, SEEK_SET);
+
+       m_pIndex = new unsigned char[len];
+       if(fread(m_pIndex, 1, len, pFileIndex) != len)
+       {
+               printf("Error while reading index file");
+               exit(1);
+       }
+       fclose(pFileIndex);
+       m_pHeader = new RTI2Header();   
+       memcpy(m_pHeader, m_pIndex, sizeof(RTI2Header));
+       m_pHeader->m_cppos = (unsigned int*)(m_pIndex + 8);
+       m_pHeader->prefixstart = *(uint64*)(m_pIndex + 8 + (m_pHeader->rti_cplength * 4));
+       m_chainsizebytes = ceil((float)(m_pHeader->rti_startptlength + m_pHeader->rti_endptlength + m_pHeader->rti_cplength) / 8); // Get the size of each chain in bytes
+       m_indexrowsizebytes = ceil((float)m_pHeader->rti_index_numchainslength / 8);
+       // Check the filesize
+       fseek(m_pFile, 0, SEEK_END);
+       len = ftell(m_pFile);
+       fseek(m_pFile, 0, SEEK_SET);
+       if(len % m_chainsizebytes > 0)
+       {
+               printf("Invalid filesize %u\n", len);
+               return;
+       }
+       
+
+}
+
+RTI2Reader::~RTI2Reader(void)
+{
+       if(m_pIndex != NULL) delete m_pIndex;
+       if(m_pFile != NULL) fclose(m_pFile);
+
+}
+
+unsigned int RTI2Reader::GetChainsLeft()
+{
+       int len = GetFileLen(m_pFile);
+       return len / m_chainsizebytes - m_chainPosition;
+}
+
+int RTI2Reader::ReadChains(unsigned int &numChains, RainbowChainO *pData)
+{
+       if(strncmp(m_pHeader->header, "RTI2", 4) != 0)
+       {
+               numChains = 0;
+               return -1;
+       }
+       unsigned char *pNumChains = m_pIndex + (m_pHeader->rti_cplength * 4) + 16; // Pointer into the index containing info about how many numbers are in the first chain prefix
+       unsigned int i = 0;
+       unsigned int indexRow = 0; // Current offset into the index
+       unsigned int curRowPosition = 0;
+       
+       while(true) // Fast forward to current position
+       {
+               // ALERT: Possible problem here if m_indexrowsizebytes > 1 as pNumChains is a unsigned char.
+               unsigned int NumChainsInRow = (unsigned int)*(pNumChains + indexRow * m_indexrowsizebytes);
+               if(m_indexrowsizebytes > 1)     { printf("Have to find a solution to this problem"); exit(2);}
+               if(i + NumChainsInRow > m_chainPosition)
+               {
+                       curRowPosition = m_chainPosition - i;
+                       break; // The current position is somewhere within this prefix
+               }
+               indexRow++;             
+               i += NumChainsInRow;
+       }
+       
+       uint64 chainrow = 0; // Buffer to store a single read chain
+       unsigned int chainsProcessed = 0; // Number of chains processed
+
+       // ALERT: same problem with unsigned char here.
+       unsigned int NumChainsInRow = *(pNumChains + indexRow);
+       while(chainsProcessed < numChains && fread(&chainrow, 1, m_chainsizebytes, m_pFile) == m_chainsizebytes)
+       {
+               if(curRowPosition >= NumChainsInRow)
+               { // Skip to next index row position
+                       indexRow++;
+                       curRowPosition = 0;
+                       NumChainsInRow = *(pNumChains + indexRow);
+               }
+               while(NumChainsInRow == 0) // We skip forward until we hit a index with > 0 chains
+               {
+                       indexRow++;
+                       NumChainsInRow = *(pNumChains + indexRow);
+                       curRowPosition = 0;
+               }
+               // Load the starting point from the data
+               pData[chainsProcessed].nIndexS = chainrow << 64 - m_pHeader->rti_startptlength;
+               pData[chainsProcessed].nIndexS = pData[chainsProcessed].nIndexS >> 64 - m_pHeader->rti_startptlength;
+
+               // Load the ending point prefix 
+               pData[chainsProcessed].nIndexE = m_pHeader->prefixstart + indexRow << m_pHeader->rti_endptlength;
+               // Append the ending point suffix
+               pData[chainsProcessed].nIndexE |= (chainrow & (0xFFFFFFFFFFFFFFFF >> m_pHeader->rti_cplength)) >> m_pHeader->rti_startptlength;
+               //pData[chainsProcessed].nCheckPoint = (chainrow >> m_pHeader->rti_startptlength + m_pHeader->rti_endptlength);
+               curRowPosition++;
+               chainsProcessed++;
+       }
+       numChains = chainsProcessed;
+       m_chainPosition += numChains;
+       return 0;
+}
diff --git a/Client Applications/rcracki_mt/RTI2Reader.h b/Client Applications/rcracki_mt/RTI2Reader.h
new file mode 100644 (file)
index 0000000..6934e6c
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __RTI2READER_H__
+#define __RTI2READER_H__
+
+#include "Public.h"
+#include <string>
+#ifdef WIN32
+#include <io.h>
+#endif
+#include <vector>
+#include "BaseRTReader.h"
+using namespace std;
+
+typedef struct 
+{
+       char header[4];
+       unsigned char rti_startptlength, rti_endptlength, rti_cplength, rti_index_numchainslength;
+       uint64 prefixstart;
+       unsigned int *m_cppos;
+} RTI2Header;
+
+class RTI2Reader : BaseRTReader
+{
+private:
+       FILE *m_pFile;
+       unsigned int m_chainPosition;
+       unsigned char *m_pPos, *m_pChainPos;
+       static RTI2Header *m_pHeader;
+       unsigned char *m_pIndex;
+       unsigned int m_chainsizebytes;
+       unsigned int m_indexrowsizebytes;
+       
+
+public:
+       RTI2Reader(string Filename);
+       ~RTI2Reader(void);
+       int ReadChains(unsigned int &numChains, RainbowChainO *pData);
+       unsigned int GetChainsLeft();
+       static RTI2Header *GetHeader() { return m_pHeader; }
+};
+
+
+#endif
diff --git a/Client Applications/rcracki_mt/RainbowCrack.cpp b/Client Applications/rcracki_mt/RainbowCrack.cpp
new file mode 100644 (file)
index 0000000..185dd1a
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+   RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
+
+   Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
+
+   Modified by Martin Westergaard Jørgensen <martinwj2005@gmail.com> to support indexed and hybrid tables
+
+   Modified by neinbrucke to support multi threading and a bunch of other stuff :)
+
+      2009-01-04 - <james.dickson@comhem.se> - Slightly modified (or "fulhack" as we say in sweden)  
+                               to support cain .lst files.
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "CrackEngine.h"
+#include "lm2ntlm.h"
+#include <algorithm>
+
+
+
+#ifdef _WIN32
+       #include <io.h>
+#else
+       #include <sys/types.h>
+       #include <sys/stat.h>
+       #include <unistd.h>
+       #include <dirent.h>
+#endif
+
+#include <openssl/md4.h>
+#ifdef _WIN32
+       #pragma comment(lib, "libeay32.lib")
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+void GetTableList(string sWildCharPathName, vector<string>& vPathName)
+{
+       //vPathName.clear();
+
+       string sPath;
+       int n = sWildCharPathName.find_last_of('\\');
+
+       if (n == (sWildCharPathName.size() - 1))
+       {
+               sWildCharPathName = sWildCharPathName.substr(0, n);
+               n = sWildCharPathName.find_last_of('\\');
+       }
+
+       if (n != -1)
+               sPath = sWildCharPathName.substr(0, n + 1);
+
+       _finddata_t fd;
+
+       long handle = _findfirst(sWildCharPathName.c_str(), &fd);
+       if (handle != -1)
+       {
+               do
+               {
+                       string sName = fd.name;
+                       if (sName.size()>3) {
+                               if (sName.substr(sName.size()-3, 3) == ".rt" && !(fd.attrib & _A_SUBDIR))
+                               {
+                                       string sPathName = sPath + sName;
+                                       vPathName.push_back(sPathName);
+                               }
+                       }
+                       if (sName.size()>4) {
+                               if (sName.substr(sName.size()-4, 4) == ".rti" && !(fd.attrib & _A_SUBDIR))
+                               {
+                                       string sPathName = sPath + sName;
+                                       vPathName.push_back(sPathName);
+                               }
+                       }
+                       if (sName.size()>5) {
+                               if (sName.substr(sName.size()-5, 5) == ".rti2" && !(fd.attrib & _A_SUBDIR))
+                               {
+                                       string sPathName = sPath + sName;
+                                       vPathName.push_back(sPathName);
+                               }
+                       }
+
+                       if (sName != "." && sName != ".." && (fd.attrib & _A_SUBDIR))
+                       {
+                               string sPath_sub = sPath + sName + '\\';
+                               string sWildCharPathName_sub = sPath_sub + '*';
+                               GetTableList(sWildCharPathName_sub, vPathName);
+                       }
+
+               } while (_findnext(handle, &fd) == 0);
+
+               _findclose(handle);
+       }
+       //printf("Found %d rainbowtables (files) in %d sub directories...\n", vPathName.size(), subDir_count);
+}
+#else
+//void GetTableList(int argc, char* argv[], vector<string>& vPathName)
+void GetTableList(string sWildCharPathName, vector<string>& vPathName)
+{
+       //vPathName.clear();
+
+       struct stat buf;
+       if (lstat(sWildCharPathName.c_str(), &buf) == 0)
+       {
+               if (S_ISDIR(buf.st_mode))
+               {
+                       DIR *dir = opendir(sWildCharPathName.c_str());
+                       if(dir)
+                       {
+                               struct dirent *pDir=NULL;
+                               while((pDir = readdir(dir)) != NULL)
+                               {
+                                       string filename = "";
+                                       filename += (*pDir).d_name;
+                                       if (filename != "." && filename != "..")
+                                       {
+                                               string new_filename = sWildCharPathName + '/' + filename;
+                                               GetTableList(new_filename, vPathName);
+                                       }
+                               }
+                               closedir(dir);
+                       }
+               }
+               else if (S_ISREG(buf.st_mode))
+               {
+                       if (sWildCharPathName.size()>3)
+                       {
+                               if (sWildCharPathName.substr(sWildCharPathName.size()-3, 3) == ".rt")
+                               {
+                                       vPathName.push_back(sWildCharPathName);
+                               }
+                       }
+                       if (sWildCharPathName.size()>4)
+                       {
+                               if (sWildCharPathName.substr(sWildCharPathName.size()-4, 4) == ".rti")
+                               {
+                                       //string sPathName_sub = sPath_sub + sName_sub;
+                                       vPathName.push_back(sWildCharPathName);
+                                       //printf("sPathName_sub: %s\n", sPathName_sub.c_str());
+                               }
+                       }
+               }
+       }
+}
+#endif
+
+bool NormalizeHash(string& sHash)
+{
+       string sNormalizedHash = sHash;
+
+       if (   sNormalizedHash.size() % 2 != 0
+               || sNormalizedHash.size() < MIN_HASH_LEN * 2
+               || sNormalizedHash.size() > MAX_HASH_LEN * 2)
+               return false;
+
+       // Make lower
+       int i;
+       for (i = 0; i < sNormalizedHash.size(); i++)
+       {
+               if (sNormalizedHash[i] >= 'A' && sNormalizedHash[i] <= 'F')
+                       sNormalizedHash[i] = sNormalizedHash[i] - 'A' + 'a';
+       }
+
+       // Character check
+       for (i = 0; i < sNormalizedHash.size(); i++)
+       {
+               if (   (sNormalizedHash[i] < 'a' || sNormalizedHash[i] > 'f')
+                       && (sNormalizedHash[i] < '0' || sNormalizedHash[i] > '9'))
+                       return false;
+       }
+
+       sHash = sNormalizedHash;
+       return true;
+}
+
+void LoadLMHashFromPwdumpFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
+{
+       vector<string> vLine;
+       if (ReadLinesFromFile(sPathName, vLine))
+       {
+               int i;
+               for (i = 0; i < vLine.size(); i++)
+               {
+                       vector<string> vPart;
+                       if (SeperateString(vLine[i], "::::", vPart))
+                       {
+                               string sUserName = vPart[0];
+                               string sLMHash   = vPart[2];
+                               string sNTLMHash = vPart[3];
+
+                               if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
+                               {
+                                       if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
+                                       {
+                                               vUserName.push_back(sUserName);
+                                               vLMHash.push_back(sLMHash);
+                                               vNTLMHash.push_back(sNTLMHash);
+                                       }
+                                       else
+                                               printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
+                               }
+                       }
+               }
+       }
+       else
+               printf("can't open %s\n", sPathName.c_str());
+}
+
+// 2009-01-04 - james - Added this so we can load hashes from cain .LST files.
+void LoadLMHashFromCainLSTFile(string sPathName, vector<string>& vUserName, vector<string>& vLMHash, vector<string>& vNTLMHash)
+{
+       vector<string> vLine;
+       if (ReadLinesFromFile(sPathName, vLine))
+       {
+               int i;
+               for (i = 0; i < vLine.size(); i++)
+               {
+                       vector<string> vPart;
+                       if (SeperateString(vLine[i], "\t\t\t\t\t\t", vPart))
+                       {
+                               string sUserName = vPart[0];
+                               string sLMHash   = vPart[4];
+                               string sNTLMHash = vPart[5];
+
+                               if (sLMHash.size() == 32 && sNTLMHash.size() == 32)
+                               {
+                                       if (NormalizeHash(sLMHash) && NormalizeHash(sNTLMHash))
+                                       {
+                                               vUserName.push_back(sUserName);
+                                               vLMHash.push_back(sLMHash);
+                                               vNTLMHash.push_back(sNTLMHash);
+                                       }
+                                       else
+                                               printf("invalid lm/ntlm hash %s:%s\n", sLMHash.c_str(), sNTLMHash.c_str());
+                               }
+                       }
+               }
+       }
+       else
+               printf("can't open %s\n", sPathName.c_str());
+}
+
+bool NTLMPasswordSeek(unsigned char* pLMPassword, int nLMPasswordLen, int nLMPasswordNext,
+                                         unsigned char* pNTLMHash, string& sNTLMPassword)
+{
+       if (nLMPasswordNext == nLMPasswordLen)
+       {
+               unsigned char md[16];
+               MD4(pLMPassword, nLMPasswordLen * 2, md);
+               if (memcmp(md, pNTLMHash, 16) == 0)
+               {
+                       sNTLMPassword = "";
+                       int i;
+                       for (i = 0; i < nLMPasswordLen; i++)
+                               sNTLMPassword += char(pLMPassword[i * 2]);
+                       return true;
+               }
+               else
+                       return false;
+       }
+
+       if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
+               return true;
+
+       if (   pLMPassword[nLMPasswordNext * 2] >= 'A'
+               && pLMPassword[nLMPasswordNext * 2] <= 'Z')
+       {
+               pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'A' + 'a';
+               if (NTLMPasswordSeek(pLMPassword, nLMPasswordLen, nLMPasswordNext + 1, pNTLMHash, sNTLMPassword))
+                       return true;
+               pLMPassword[nLMPasswordNext * 2] = pLMPassword[nLMPasswordNext * 2] - 'a' + 'A';
+       }
+
+       return false;
+}
+
+bool LMPasswordCorrectCase(string sLMPassword, unsigned char* pNTLMHash, string& sNTLMPassword)
+{
+       if (sLMPassword.size() == 0)
+       {
+               sNTLMPassword = "";
+               return true;
+       }
+
+       unsigned char* pLMPassword = new unsigned char[sLMPassword.size() * 2];
+       int i;
+       for (i = 0; i < sLMPassword.size(); i++)
+       {
+               pLMPassword[i * 2    ] = sLMPassword[i];
+               pLMPassword[i * 2 + 1] = 0x00;
+       }
+       bool fRet = NTLMPasswordSeek(pLMPassword, sLMPassword.size(), 0, pNTLMHash, sNTLMPassword);
+
+       delete pLMPassword;
+
+       return fRet;
+}
+
+void Usage()
+{
+       Logo();
+
+       printf("usage: rcracki_mt -h hash rainbow_table_pathname\n");
+       printf("       rcracki_mt -l hash_list_file rainbow_table_pathname\n");
+       printf("       rcracki_mt -f pwdump_file rainbow_table_pathname\n");
+       printf("       rcracki_mt -c lst_file rainbow_table_pathname\n");
+       printf("\n");
+       printf("-h hash:                use raw hash as input\n");
+       printf("-l hash_list_file:      use hash list file as input, each hash in a line\n");
+       printf("-f pwdump_file:         use pwdump file as input, handles lanmanager hash only\n");
+       printf("-c lst_file:            use .lst (cain format) file as input\n");
+       printf("-r [-s session_name]:   resume from previous session, optional session name\n");
+       printf("rainbow_table_pathname: pathname(s) of the rainbow table(s)\n");
+       printf("\n");
+       printf("Extra options:    -t [nr] use this amount of threads/cores, default is 1\n");
+       printf("                  -o [output_file] write (temporary) results to this file\n");
+       printf("                  -s [session_name] write session data with this name\n");
+       printf("                  -k keep precalculation on disk\n");
+       printf("                  -v show debug information\n");
+       printf("\n");
+#ifdef _WIN32
+       printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]\\MD5\n");
+       printf("         rcracki_mt -l hash.txt [path_to_specific_table]\\*\n");
+#else
+       printf("example: rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 -t 2 [path]/MD5\n");
+       printf("         rcracki_mt -l hash.txt [path_to_specific_table]/*\n");
+#endif
+       printf("         rcracki_mt -f hash.txt -t 4 -o results.txt *.rti\n");
+
+}
+
+int main(int argc, char* argv[])
+{
+       if (argc < 2)
+       {
+               Usage();
+               return 0;
+       }
+
+       vector<string> vPathName;
+       vector<string> vDefaultRainbowTablePath;
+       string sWildCharPathName = "";
+       string sInputType        = "";
+       string sInput            = "";
+       string outputFile                = "";
+       string sApplicationPath  = "";
+       string sIniPathName      = "rcracki_mt.ini";
+       bool writeOutput                 = false;
+       string sSessionPathName  = "rcracki.session";
+       string sProgressPathName = "rcracki.progress";
+       string sPrecalcPathName  = "rcracki.precalc";
+       bool resumeSession       = false;
+       bool useDefaultRainbowTablePath = false;
+       bool debug               = false;
+       bool keepPrecalcFiles    = false;
+       string sAlgorithm                = "";
+       int maxThreads                   = 1;
+       CHashSet hs;
+
+       // Read defaults from ini file;
+       bool readFromIni = false;
+       vector<string> vLine;
+       if (ReadLinesFromFile(sIniPathName, vLine)) {
+               readFromIni = true;
+       }
+       else if (ReadLinesFromFile(GetApplicationPath() + sIniPathName, vLine)) {
+               readFromIni = true;
+       }
+       if (readFromIni)
+       {
+               int i;
+               for (i = 0; i < vLine.size(); i++)
+               {
+                       if (vLine[i].substr(0,1) != "#")
+                       {
+                               vector<string> vPart;
+                               if (SeperateString(vLine[i], "=", vPart))
+                               {
+                                       string sOption = vPart[0];
+                                       string sValue  = vPart[1];
+                                       
+                                       if (sOption == "Threads") {
+                                               maxThreads = atoi(sValue.c_str());
+                                       }
+                                       else if (sOption == "DefaultResultsFile") {
+                                               outputFile = sValue;
+                                       }
+                                       else if (sOption == "AlwaysStoreResultsToFile") {
+                                               if (sValue == "1")
+                                                       writeOutput = true;
+                                       }
+                                       else if (sOption.substr(0,24) == "DefaultRainbowTablePath.") {
+                                               //printf("Default RT path: %s\n", sValue.c_str());
+                                               vDefaultRainbowTablePath.push_back(vLine[i]);
+                                       }
+                                       else if (sOption == "DefaultAlgorithm") {
+                                               useDefaultRainbowTablePath = true;
+                                               sAlgorithm = sValue;
+                                       }
+                                       else if (sOption == "AlwaysDebug") {
+                                               if (sValue == "1")
+                                                       debug = true;
+                                       }
+                                       else if (sOption == "AlwaysKeepPrecalcFiles") {
+                                               if (sValue == "1")
+                                                       keepPrecalcFiles = true;
+                                       }
+                                       else {
+                                               printf("illegal option %s in ini file %s\n", sOption.c_str(), sIniPathName.c_str());
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               if (writeOutput && outputFile == "")
+               {
+                       printf("You need to specify a 'DefaultResultsFile' with 'AlwaysStoreResultsToFile=1'\n");
+                       writeOutput = false;
+               }
+       }
+
+       // Parse command line arguments
+       int i;
+       for (i = 1; i < argc; i++)
+       {
+               string cla = argv[i];
+               if (cla == "-h") {
+                       sInputType = cla;
+                       i++;
+                       if (i < argc)
+                               sInput = argv[i];
+               }
+               else if (cla == "-l") {
+                       sInputType = cla;
+                       i++;
+                       if (i < argc)
+                               sInput = argv[i];
+               }
+               else if (cla == "-f") {
+                       sInputType = cla;
+                       i++;
+                       if (i < argc)
+                               sInput = argv[i];
+               }
+               else if (cla == "-c") {
+                       sInputType = cla;
+                       i++;
+                       if (i < argc)
+                               sInput = argv[i];
+               }
+               else if (cla == "-t") {
+                       i++;
+                       if (i < argc)
+                               maxThreads = atoi(argv[i]);
+               }
+               else if (cla == "-o") {
+                       writeOutput = true;
+                       i++;
+                       if (i < argc)
+                               outputFile = argv[i];
+               }
+               else if (cla == "-r") {
+                       resumeSession = true;
+               }
+               else if (cla == "-s") {
+                       i++;
+                       if (i < argc)
+                       {
+                               sSessionPathName                =  argv[i];
+                               sSessionPathName                += ".session";
+                               sProgressPathName               =  argv[i];
+                               sProgressPathName               += ".progress";
+                               sPrecalcPathName                =  argv[i];
+                               sPrecalcPathName                += ".precalc";
+                       }
+               }
+               else if (cla == "-v") {
+                       debug = true;
+               }
+               else if (cla == "-k") {
+                       keepPrecalcFiles = true;
+               }
+               else if (cla == "-a") {
+                       useDefaultRainbowTablePath = true;
+                       i++;
+                       if (i < argc)
+                               sAlgorithm = argv[i];
+               }
+               else {
+                       GetTableList(cla, vPathName);
+               }
+       }
+
+       if (debug && !readFromIni)
+               printf("Debug: Couldn't read rcracki_mt.ini, continuing anyway.\n");
+
+       // Load session data if we are resuming
+       if (resumeSession)
+       {
+               vPathName.clear();
+               vector<string> sSessionData;
+               if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))
+               {
+                       int i;
+                       for (i = 0; i < sSessionData.size(); i++)
+                       {
+                               vector<string> vPart;
+                               if (SeperateString(sSessionData[i], "=", vPart))
+                               {
+                                       string sOption = vPart[0];
+                                       string sValue  = vPart[1];
+                                       
+                                       if (sOption == "sPathName") {
+                                               vPathName.push_back(sValue);
+                                       }
+                                       else if (sOption == "sInputType") {
+                                               sInputType = sValue;
+                                       }
+                                       else if (sOption == "sInput") {
+                                               sInput = sValue;
+                                       }
+                                       else if (sOption == "outputFile") {
+                                               writeOutput = true;
+                                               outputFile = sValue;
+                                       }
+                                       else if (sOption == "keepPrecalcFiles") {
+                                               if (sValue == "1")
+                                                       keepPrecalcFiles = true;
+                                       }
+                               }
+                       }
+               }
+               else {
+                       printf("Couldn't open session file %s\n", sSessionPathName.c_str());
+                       return 0;
+               }
+       }
+
+       if (maxThreads<1)
+               maxThreads = 1;
+
+       // don't load these if we are resuming a session that already has a list of tables
+       if (useDefaultRainbowTablePath && !resumeSession)
+       {
+               int i;
+               for (i = 0; i < vDefaultRainbowTablePath.size(); i++)
+               {
+                       vector<string> vPart;
+                       if (SeperateString(vDefaultRainbowTablePath[i], ".=", vPart))
+                       {
+                               string lineAlgorithm = vPart[1];
+                               string linePath = vPart[2];
+
+                               if (lineAlgorithm == sAlgorithm)
+                                       GetTableList(linePath, vPathName);
+                       }
+               }
+       }
+
+       printf("Using %d threads for pre-calculation and false alarm checking...\n", maxThreads);
+
+       setvbuf(stdout, NULL, _IONBF,0);
+       if (vPathName.size() == 0)
+       {
+               printf("no rainbow table found\n");
+               return 0;
+       }
+       printf("Found %d rainbowtable files...\n\n", vPathName.size());
+
+       bool fCrackerType;                      // true: hash cracker, false: lm cracker
+       vector<string> vHash;           // hash cracker
+       vector<string> vUserName;       // lm cracker
+       vector<string> vLMHash;         // lm cracker
+       vector<string> vNTLMHash;       // lm cracker
+       if (sInputType == "-h")
+       {
+               fCrackerType = true;
+
+               string sHash = sInput;
+               if (NormalizeHash(sHash))
+                       vHash.push_back(sHash);
+               else
+                       printf("invalid hash: %s\n", sHash.c_str());
+       }
+       else if (sInputType == "-l")
+       {
+               fCrackerType = true;
+
+               string sPathName = sInput;
+               vector<string> vLine;
+               if (ReadLinesFromFile(sPathName, vLine))
+               {
+                       int i;
+                       for (i = 0; i < vLine.size(); i++)
+                       {
+                               string sHash = vLine[i];
+                               if (NormalizeHash(sHash))
+                                       vHash.push_back(sHash);
+                               else
+                                       printf("invalid hash: %s\n", sHash.c_str());
+                       }
+               }
+               else
+                       printf("can't open %s\n", sPathName.c_str());
+       }
+       else if (sInputType == "-f")
+       {
+               fCrackerType = false;
+
+               string sPathName = sInput;
+               LoadLMHashFromPwdumpFile(sPathName, vUserName, vLMHash, vNTLMHash);
+       }
+       else if (sInputType == "-c")
+       {
+               // 2009-01-04 - james - Added this for cain-files.
+               fCrackerType = false;
+               string sPathName = sInput;
+               LoadLMHashFromCainLSTFile(sPathName, vUserName, vLMHash, vNTLMHash);
+       }
+       else
+       {
+               Usage();
+               return 0;
+       }
+
+       if (fCrackerType && vHash.size() == 0)
+       {
+               printf("no hashes found");
+               return 0;
+       }
+       if (!fCrackerType && vLMHash.size() == 0)
+       {
+               return 0;
+               printf("no hashes found");
+       }
+
+       if (fCrackerType)
+       {
+               int i;
+               for (i = 0; i < vHash.size(); i++)
+                       hs.AddHash(vHash[i]);
+       }
+       else
+       {
+               int i;
+               for (i = 0; i < vLMHash.size(); i++)
+               {
+                       hs.AddHash(vLMHash[i].substr(0, 16));
+                       hs.AddHash(vLMHash[i].substr(16, 16));
+               }
+       }
+
+       // Load found hashes from session file
+       if (resumeSession)
+       {
+               vector<string> sSessionData;
+               if (ReadLinesFromFile(sSessionPathName.c_str(), sSessionData))
+               {
+                       int i;
+                       for (i = 0; i < sSessionData.size(); i++)
+                       {
+                               vector<string> vPart;
+                               if (SeperateString(sSessionData[i], "=", vPart))
+                               {
+                                       string sOption = vPart[0];
+                                       string sValue  = vPart[1];
+                                       
+                                       if (sOption == "sHash") {
+                                               vector<string> vPartHash;
+                                               if (SeperateString(sValue, "::", vPartHash))
+                                               {
+                                                       string sHash = vPartHash[0];
+                                                       string sBinary = vPartHash[1];
+                                                       string sPlain = vPartHash[2];
+                                                       
+                                                       hs.SetPlain(sHash, sPlain, sBinary);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // (Over)write session data if we are not resuming
+       if (!resumeSession)
+       {
+               FILE* file = fopen(sSessionPathName.c_str(), "w");
+               string buffer = "";
+
+               if (file!=NULL)
+               {
+                       buffer += "sInputType=" + sInputType + "\n";
+                       buffer += "sInput=" + sInput + "\n";
+
+                       int i;
+                       for (i = 0; i < vPathName.size(); i++)
+                       {
+                               buffer += "sPathName=" + vPathName[i] + "\n";
+                       }
+
+                       if (writeOutput)
+                               buffer += "outputFile=" + outputFile + "\n";
+
+                       if (keepPrecalcFiles)
+                               buffer += "keepPrecalcFiles=1\n";
+
+                       fputs (buffer.c_str(), file);
+                       fclose (file);
+               }
+               file = fopen(sProgressPathName.c_str(), "w");
+               fclose (file);
+       }
+
+       // Run
+       CCrackEngine ce;
+       if (writeOutput)
+               ce.setOutputFile(outputFile);
+       ce.setSession(sSessionPathName, sProgressPathName, sPrecalcPathName, keepPrecalcFiles);
+       ce.Run(vPathName, hs, maxThreads, resumeSession, debug);
+
+       // Remove session files
+       if (debug) printf("Debug: Removing session files.\n");
+       if (remove(sSessionPathName.c_str()) == 0)
+               remove(sProgressPathName.c_str());
+       else
+               if (debug) printf("Debug: Failed removing session files.\n");
+
+       // Statistics
+       printf("statistics\n");
+       printf("-------------------------------------------------------\n");
+       printf("plaintext found:          %d of %d (%.2f%%)\n", hs.GetStatHashFound(),
+                                                                                                                       hs.GetStatHashTotal(),
+                                                                                                                       100.0f * hs.GetStatHashFound() / hs.GetStatHashTotal());
+       printf("total disk access time:   %.2f s\n", ce.GetStatTotalDiskAccessTime());
+       printf("total cryptanalysis time: %.2f s\n", ce.GetStatTotalCryptanalysisTime());
+       printf("total chain walk step:    %d\n",     ce.GetStatTotalChainWalkStep());
+       printf("total false alarm:        %d\n",     ce.GetStatTotalFalseAlarm());
+       printf("total chain walk step due to false alarm: %d\n", ce.GetStatTotalChainWalkStepDueToFalseAlarm());
+//     printf("total chain walk step skipped due to checkpoints: %d\n", ce.GetStatTotalFalseAlarmSkipped()); // Checkpoints not used - yet
+       printf("\n");
+
+       // Result
+       printf("result\n");
+       printf("-------------------------------------------------------\n");
+       if (fCrackerType)
+       {
+               int i;
+               for (i = 0; i < vHash.size(); i++)
+               {
+                       string sPlain, sBinary;
+                       if (!hs.GetPlain(vHash[i], sPlain, sBinary))
+                       {
+                               sPlain  = "<notfound>";
+                               sBinary = "<notfound>";
+                       }
+
+                       printf("%s\t%s\thex:%s\n", vHash[i].c_str(), sPlain.c_str(), sBinary.c_str());
+               }
+       }
+       else
+       {
+               int i;
+               for (i = 0; i < vLMHash.size(); i++)
+               {
+                       string sPlain1, sBinary1;
+                       bool fPart1Found = hs.GetPlain(vLMHash[i].substr(0, 16), sPlain1, sBinary1);
+                       if (!fPart1Found)
+                       {
+                               sPlain1  = "<notfound>";
+                               sBinary1 = "<notfound>";
+                       }
+
+                       string sPlain2, sBinary2;
+                       bool fPart2Found = hs.GetPlain(vLMHash[i].substr(16, 16), sPlain2, sBinary2);
+                       if (!fPart2Found)
+                       {
+                               sPlain2  = "<notfound>";
+                               sBinary2 = "<notfound>";
+                       }
+
+                       string sPlain = sPlain1 + sPlain2;
+                       string sBinary = sBinary1 + sBinary2;
+
+                       // Correct case
+                       if (fPart1Found && fPart2Found)
+                       {
+                               unsigned char NTLMHash[16];
+                               int nHashLen;
+                               ParseHash(vNTLMHash[i], NTLMHash, nHashLen);
+                               if (nHashLen != 16)
+                                       printf("debug: nHashLen mismatch\n");
+                               string sNTLMPassword;
+                               if (LMPasswordCorrectCase(sPlain, NTLMHash, sNTLMPassword))
+                               {
+                                       sPlain = sNTLMPassword;
+                                       sBinary = HexToStr((const unsigned char*)sNTLMPassword.c_str(), sNTLMPassword.size());
+                               }
+                               else
+                               {
+                                       printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(), sPlain.c_str(), sBinary.c_str());
+                                       LM2NTLMcorrector corrector;
+                                       if (corrector.LMPasswordCorrectUnicode(sBinary, NTLMHash, sNTLMPassword))
+                                       {
+                                               sPlain = sNTLMPassword;
+                                               sBinary = corrector.getBinary();
+                                               if (writeOutput)
+                                               {
+                                                       if (!writeResultLineToFile(outputFile, vNTLMHash[i].c_str(), sPlain.c_str(), sBinary.c_str()))
+                                                               printf("Couldn't write final result to file!\n");
+                                               }
+                                       }
+                                       else {
+                                               printf("case correction for password %s failed!\n", sPlain.c_str());
+                                       }
+                               }
+                       }
+
+                       // Display
+                       printf("%-14s\t%s\thex:%s\n", vUserName[i].c_str(),
+                                                                                 sPlain.c_str(),
+                                                                                 sBinary.c_str());
+                       
+               }
+       }
+
+       return 0;
+}
diff --git a/Client Applications/rcracki_mt/charset.txt b/Client Applications/rcracki_mt/charset.txt
new file mode 100644 (file)
index 0000000..6e749fa
--- /dev/null
@@ -0,0 +1,34 @@
+# charset configuration file for DistrRTgen v3.2 by Martin Westergaard (martinwj2005@gmail.com)
+
+byte                        = []
+alpha                       = [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
+alpha-space                 = [ABCDEFGHIJKLMNOPQRSTUVWXYZ ]
+alpha-numeric               = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]
+alpha-numeric-space         = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ]
+alpha-numeric-symbol14      = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=]
+alpha-numeric-symbol14-space= [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+= ]
+all                         = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/]
+all-space                   = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/ ]
+alpha-numeric-symbol32-space = [ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/ ]
+lm-frt-cp437                = [ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~\80\8e\8f\90\92\99\9a\9b\9c\9d\9e\9f¥àáâãäæçèéêëî]
+lm-frt-cp850                = [ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~\80\8e\8f\90\92\99\9a\9c\9d\9f¥µ¶·½¾ÇÏÑÒÓÔÕÖ×ØÞàáâãåæèéêëíï]
+lm-frt-cp437-850            = [ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~\80\8e\8f\90\92\99\9a\9b\9c\9d\9e\9f¥µ¶·½¾ÇÏÑÒÓÔÕÖ×ØÞàáâãäåæçèéêëíîï]
+
+numeric                     = [0123456789]
+numeric-space               = [0123456789 ]
+loweralpha                  = [abcdefghijklmnopqrstuvwxyz]
+loweralpha-space            = [abcdefghijklmnopqrstuvwxyz ]
+loweralpha-numeric          = [abcdefghijklmnopqrstuvwxyz0123456789]
+loweralpha-numeric-space    = [abcdefghijklmnopqrstuvwxyz0123456789 ]
+loweralpha-numeric-symbol14 = [abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_+=]
+loweralpha-numeric-all             = [abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/]
+loweralpha-numeric-symbol32-space= [abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/ ]
+
+mixalpha                    = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]
+mixalpha-space              = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ]
+mixalpha-numeric            = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]
+mixalpha-numeric-space      = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ]
+mixalpha-numeric-symbol14   = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=]
+mixalpha-numeric-all        = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/]
+mixalpha-numeric-symbol32-space  = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/ ]
+mixalpha-numeric-all-space  = [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~`[]{}|\:;"'<>,.?/ ]
diff --git a/Client Applications/rcracki_mt/fast_md5.cpp b/Client Applications/rcracki_mt/fast_md5.cpp
new file mode 100644 (file)
index 0000000..8d60aee
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * Fast implementation of the MD5 message-digest algorithm as per RFC
+ * (see http://tools.ietf.org/html/rfc1321)
+ *
+ * Author: Joao Inacio <jcinacio at gmail.com>
+ * License: Use and share as you wish at your own risk, please keep this header ;)
+ *
+ * Optimizations:
+ *  - For lengths < 16, transformation steps are "unrolled" using macros/defines
+ *  - Constants used whenever possible, it's the compiler's job to sort them out
+ *  - Padding is done on 4-byte words, and memory copied as last resort.
+ */
+
+
+typedef unsigned int UINT4;
+
+
+/* MD5 defines as per RFC reference implementation */
+
+#define AC1                            0xd76aa478
+#define AC2                            0xe8c7b756
+#define AC3                            0x242070db
+#define AC4                            0xc1bdceee
+#define AC5                            0xf57c0faf
+#define AC6                            0x4787c62a
+#define AC7                            0xa8304613
+#define AC8                            0xfd469501
+#define AC9                            0x698098d8
+#define AC10                   0x8b44f7af
+#define AC11                   0xffff5bb1
+#define AC12                   0x895cd7be
+#define AC13                   0x6b901122
+#define AC14                   0xfd987193
+#define AC15                   0xa679438e
+#define AC16                   0x49b40821
+#define AC17                   0xf61e2562
+#define AC18                   0xc040b340
+#define AC19                   0x265e5a51
+#define AC20                   0xe9b6c7aa
+#define AC21                   0xd62f105d
+#define AC22                   0x02441453
+#define AC23                   0xd8a1e681
+#define AC24                   0xe7d3fbc8
+#define AC25                   0x21e1cde6
+#define AC26                   0xc33707d6
+#define AC27                   0xf4d50d87
+#define AC28                   0x455a14ed
+#define AC29                   0xa9e3e905
+#define AC30                   0xfcefa3f8
+#define AC31                   0x676f02d9
+#define AC32                   0x8d2a4c8a
+#define AC33                   0xfffa3942
+#define AC34                   0x8771f681
+#define AC35                   0x6d9d6122
+#define AC36                   0xfde5380c
+#define AC37                   0xa4beea44
+#define AC38                   0x4bdecfa9
+#define AC39                   0xf6bb4b60
+#define AC40                   0xbebfbc70
+#define AC41                   0x289b7ec6
+#define AC42                   0xeaa127fa
+#define AC43                   0xd4ef3085
+#define AC44                   0x04881d05
+#define AC45                   0xd9d4d039
+#define AC46                   0xe6db99e5
+#define AC47                   0x1fa27cf8
+#define AC48                   0xc4ac5665
+#define AC49                   0xf4292244
+#define AC50                   0x432aff97
+#define AC51                   0xab9423a7
+#define AC52                   0xfc93a039
+#define AC53                   0x655b59c3
+#define AC54                   0x8f0ccc92
+#define AC55                   0xffeff47d
+#define AC56                   0x85845dd1
+#define AC57                   0x6fa87e4f
+#define AC58                   0xfe2ce6e0
+#define AC59                   0xa3014314
+#define AC60                   0x4e0811a1
+#define AC61                   0xf7537e82
+#define AC62                   0xbd3af235
+#define AC63                   0x2ad7d2bb
+#define AC64                   0xeb86d391
+
+#define S11                             7
+#define S12                            12
+#define S13                            17
+#define S14                            22
+#define S21                             5
+#define S22                             9
+#define S23                            14
+#define S24                            20
+#define S31                             4
+#define S32                            11
+#define S33                            16
+#define S34                            23
+#define S41                             6
+#define S42                            10
+#define S43                            15
+#define S44                            21
+
+#define Ca                             0x67452301
+#define Cb                             0xefcdab89
+#define Cc                             0x98badcfe
+#define Cd                             0x10325476
+
+
+#define F(x, y, z)                     ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)                     ((y) ^ ((z) & ((x) ^ (y))))
+//#define G(x, y, z)                   F((z), (x), (y))
+#define H(x, y, z)                     ((x) ^ (y) ^ (z))
+#define I(x, y, z)                     ((y) ^ ((x) | ~(z)))
+
+#define ROTATE_LEFT(x, n)      (((x) << (n)) | ((x) >> (32-(n))))
+
+// md5 step
+#define MD5STEP(f, a, b, c, d, AC, x, s) {     \
+    (a) += f ((b), (c), (d));          \
+       (a) += (AC) + (x);                              \
+    (a) = ROTATE_LEFT ((a), (s));      \
+       (a) += (b);                                             \
+}
+
+// full MD5 transformation
+#define MD5_steps(w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15) { \
+       \
+       MD5STEP(F, a, b, c, d,  AC1,  w0, S11);\
+       MD5STEP(F, d, a, b, c,  AC2,  w1, S12);\
+       MD5STEP(F, c, d, a, b,  AC3,  w2, S13);\
+       MD5STEP(F, b, c, d, a,  AC4,  w3, S14);\
+       MD5STEP(F, a, b, c, d,  AC5,  w4, S11);\
+       MD5STEP(F, d, a, b, c,  AC6,  w5, S12);\
+       MD5STEP(F, c, d, a, b,  AC7,  w6, S13);\
+       MD5STEP(F, b, c, d, a,  AC8,  w7, S14);\
+       MD5STEP(F, a, b, c, d,  AC9,  w8, S11);\
+       MD5STEP(F, d, a, b, c, AC10,  w9, S12);\
+       MD5STEP(F, c, d, a, b, AC11, w10, S13);\
+       MD5STEP(F, b, c, d, a, AC12, w11, S14);\
+       MD5STEP(F, a, b, c, d, AC13, w12, S11);\
+       MD5STEP(F, d, a, b, c, AC14, w13, S12);\
+       MD5STEP(F, c, d, a, b, AC15, w14, S13);\
+       MD5STEP(F, b, c, d, a, AC16, w15, S14);\
+       \
+       MD5STEP(G, a, b, c, d, AC17,  w1, S21);\
+       MD5STEP(G, d, a, b, c, AC18,  w6, S22);\
+       MD5STEP(G, c, d, a, b, AC19, w11, S23);\
+       MD5STEP(G, b, c, d, a, AC20,  w0, S24);\
+       MD5STEP(G, a, b, c, d, AC21,  w5, S21);\
+       MD5STEP(G, d, a, b, c, AC22, w10, S22);\
+       MD5STEP(G, c, d, a, b, AC23, w15, S23);\
+       MD5STEP(G, b, c, d, a, AC24,  w4, S24);\
+       MD5STEP(G, a, b, c, d, AC25,  w9, S21);\
+       MD5STEP(G, d, a, b, c, AC26, w14, S22);\
+       MD5STEP(G, c, d, a, b, AC27,  w3, S23);\
+       MD5STEP(G, b, c, d, a, AC28,  w8, S24);\
+       MD5STEP(G, a, b, c, d, AC29, w13, S21);\
+       MD5STEP(G, d, a, b, c, AC30,  w2, S22);\
+       MD5STEP(G, c, d, a, b, AC31,  w7, S23);\
+       MD5STEP(G, b, c, d, a, AC32, w12, S24);\
+       \
+       MD5STEP(H, a, b, c, d, AC33,  w5, S31);\
+       MD5STEP(H, d, a, b, c, AC34,  w8, S32);\
+       MD5STEP(H, c, d, a, b, AC35, w11, S33);\
+       MD5STEP(H, b, c, d, a, AC36, w14, S34);\
+       MD5STEP(H, a, b, c, d, AC37,  w1, S31);\
+       MD5STEP(H, d, a, b, c, AC38,  w4, S32);\
+       MD5STEP(H, c, d, a, b, AC39,  w7, S33);\
+       MD5STEP(H, b, c, d, a, AC40, w10, S34);\
+       MD5STEP(H, a, b, c, d, AC41, w13, S31);\
+       MD5STEP(H, d, a, b, c, AC42,  w0, S32);\
+       MD5STEP(H, c, d, a, b, AC43,  w3, S33);\
+       MD5STEP(H, b, c, d, a, AC44,  w6, S34);\
+       MD5STEP(H, a, b, c, d, AC45,  w9, S31);\
+       MD5STEP(H, d, a, b, c, AC46, w12, S32);\
+       MD5STEP(H, c, d, a, b, AC47, w15, S33);\
+       MD5STEP(H, b, c, d, a, AC48,  w2, S34);\
+       \
+       MD5STEP(I, a, b, c, d, AC49,  w0, S41);\
+       MD5STEP(I, d, a, b, c, AC50,  w7, S42);\
+       MD5STEP(I, c, d, a, b, AC51, w14, S43);\
+       MD5STEP(I, b, c, d, a, AC52,  w5, S44);\
+       MD5STEP(I, a, b, c, d, AC53, w12, S41);\
+       MD5STEP(I, d, a, b, c, AC54,  w3, S42);\
+       MD5STEP(I, c, d, a, b, AC55, w10, S43);\
+       MD5STEP(I, b, c, d, a, AC56,  w1, S44);\
+       MD5STEP(I, a, b, c, d, AC57,  w8, S41);\
+       MD5STEP(I, d, a, b, c, AC58, w15, S42);\
+       MD5STEP(I, c, d, a, b, AC59,  w6, S43);\
+       MD5STEP(I, b, c, d, a, AC60, w13, S44);\
+       MD5STEP(I, a, b, c, d, AC61,  w4, S41);\
+       MD5STEP(I, d, a, b, c, AC62, w11, S42);\
+       MD5STEP(I, c, d, a, b, AC63,  w2, S43);\
+       MD5STEP(I, b, c, d, a, AC64,  w9, S44);\
+}
+
+// len >= 56
+#define MD5_transform_add(w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15) { \
+       \
+       a = wOut[0]; b = wOut[1]; c = wOut[2]; d = wOut[3];\
+       \
+       MD5_steps(w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15);\
+       \
+       wOut[0] += a; wOut[1] += b; wOut[2] += c; wOut[3] += d;\
+}
+
+// len < 56
+#define MD5_transform_single(w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15) { \
+       \
+       a = CC[0]; b=CC[1]; c=CC[2]; d=CC[3];\
+       \
+       MD5_steps(w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15);\
+       \
+       wOut[0] = a+Ca; wOut[1] = b+Cb; wOut[2] = c+Cc; wOut[3] = d+Cd;\
+}
+
+// len < 16
+#define MD5_transform_16(w0, w1, w2, w3, w14) \
+        MD5_transform_single(w0, w1, w2, w3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, w14, 0);
+
+
+// pad word and append 0x80 at appropriate location
+#define MD5_pad_w0()           (0x00000080)
+#define MD5_pad_w1(data)       (((data) & 0x000000FF) | 0x00008000)
+#define MD5_pad_w2(data)       (((data) & 0x0000FFFF) | 0x00800000)
+#define MD5_pad_w3(data)       (((data) & 0x00FFFFFF) | 0x80000000)
+
+
+#ifndef MD5_pad_w1
+static inline UINT4 MD5_pad_w1(UINT4 data)
+{
+       __asm__ (
+               "movb   %%al,   %%cl    \n\t"
+               "xorl   %1,             %1              \n\t"
+               "orb    $128,   %%ah    \n\t"
+               "movb   %%cl,   %%al    \n\t"
+               "movl   %1,     %0              \n\t"
+               : "=r" (data)
+               : "a" (data)
+               : "cl"
+       );
+       return data;
+}
+#endif
+
+#ifndef MD5_pad_w3
+static inline UINT4 MD5_pad_w3(UINT4 data)
+{
+       __asm__ (
+               "roll   $8,             %1              \n\t"
+               "movb   $128,   %%al    \n\t"
+               "rorl   $8,             %1              \n\t"
+               "movl   %1,     %0              \n\t"
+               : "=r" (data)
+               : "a" (data)
+       );
+       return data;
+}
+#endif
+
+
+static inline void MD5_copy_pad_block(UINT4 *dData, UINT4 *wIn, int blocklen, int len)
+{
+       register int cl;
+
+       // copy full words
+       for (cl = 0; cl < blocklen; cl++)
+               dData[cl] = wIn[cl];
+
+       // copy with padding
+       switch (len & 0x03) {
+               case 0:
+                       dData[cl] = MD5_pad_w0();
+                       break;
+               case 1:
+                       dData[cl] = MD5_pad_w1(wIn[cl]);
+                       break;
+               case 2:
+                       dData[cl] = MD5_pad_w2(wIn[cl]);
+                       break;
+               case 3:
+                       dData[cl] = MD5_pad_w3(wIn[cl]);
+                       break;
+       }
+       // append 0's
+       for (cl++; cl < 14; cl++)
+               dData[cl] = 0;
+       // append len
+       dData[cl++] = (len << 3);
+       dData[cl] = (len >> 29);
+}
+
+// fast initializer array
+//__attribute__((aligned(16)))
+//__declspec(align(16))
+static const UINT4 CC[4] = {Ca, Cb, Cc, Cd};
+
+
+
+/*
+ * fast_MD5()
+ *
+ */
+void fast_MD5(unsigned char *pData, int len, unsigned char *pDigest)
+{
+       #define wIn             ((UINT4 *)pData)
+       #define wOut    ((UINT4 *)pDigest)
+
+       register UINT4 a;
+       register UINT4 b;
+       register UINT4 c;
+       register UINT4 d;
+
+       switch (len) {
+               case 0:
+                       MD5_transform_16(MD5_pad_w0(), 0, 0, 0, 8*0);
+                       return;
+               case 1:
+                       MD5_transform_16(MD5_pad_w1(wIn[0]), 0, 0, 0, 8*1);
+                       return;
+               case 2:
+                       MD5_transform_16(MD5_pad_w2(wIn[0]), 0, 0, 0, 8*2);
+                       return;
+               case 3:
+                       MD5_transform_16(MD5_pad_w3(wIn[0]), 0, 0, 0, 8*3);
+                       return;
+               case 4:
+                       MD5_transform_16(wIn[0], MD5_pad_w0(), 0, 0, 8*4);
+                       return;
+               case 5:
+                       MD5_transform_16(wIn[0], MD5_pad_w1(wIn[1]), 0, 0, 8*5);
+                       return;
+               case 6:
+                       MD5_transform_16(wIn[0], MD5_pad_w2(wIn[1]), 0, 0, 8*6);
+                       return;
+               case 7:
+                       MD5_transform_16(wIn[0], MD5_pad_w3(wIn[1]), 0, 0, 8*7);
+                       return;
+               case 8:
+                       MD5_transform_16(wIn[0], wIn[1], MD5_pad_w0(), 0, 8*8);
+                       return;
+               case 9:
+                       MD5_transform_16(wIn[0], wIn[1], MD5_pad_w1(wIn[2]), 0, 8*9);
+                       return;
+               case 10:
+                       MD5_transform_16(wIn[0], wIn[1], MD5_pad_w2(wIn[2]), 0, 8*10);
+                       return;
+               case 11:
+                       MD5_transform_16(wIn[0], wIn[1], MD5_pad_w3(wIn[2]), 0, 8*11);
+                       return;
+               case 12:
+                       MD5_transform_16(wIn[0], wIn[1], wIn[2], MD5_pad_w0(), 8*12);
+                       return;
+               case 13:
+                       MD5_transform_16(wIn[0], wIn[1], wIn[2], MD5_pad_w1(wIn[3]), 8*13);
+                       return;
+               case 14:
+                       MD5_transform_16(wIn[0], wIn[1], wIn[2], MD5_pad_w2(wIn[3]), 8*14)
+                       return;
+               case 15:
+                       MD5_transform_16(wIn[0], wIn[1], wIn[2], MD5_pad_w3(wIn[3]), 8*15)
+                       return;
+       }
+
+       // data block used for padding
+       UINT4 dData[16];
+
+       if (len < 56) {
+               // 16 < length < 56
+
+               MD5_copy_pad_block(dData, wIn, (len >> 2), len);
+
+               // redefine data input, point to padded data
+               #undef  wIn
+               #define wIn             dData
+
+               MD5_transform_single (
+                       wIn[ 0], wIn[ 1], wIn[ 2], wIn[ 3], wIn[ 4], wIn[ 5], wIn[ 6], wIn[ 7],
+                       wIn[ 8], wIn[ 9], wIn[10], wIn[11], wIn[12], wIn[13], wIn[14], wIn[15]
+               );
+
+               #undef  wIn
+               return;
+       } else {
+               // len >= 56
+
+               #define wIn             ((UINT4 *)pData)
+
+               // original len
+               int tlen = len;
+
+               // init digest for long lens
+               wOut[0] = Ca; wOut[1] = Cb; wOut[2] = Cc; wOut[3] = Cd;
+
+               while (tlen >= 64) {
+                       // Process 64-byte chunks
+                       MD5_transform_add(
+                               wIn[ 0], wIn[ 1], wIn[ 2], wIn[ 3], wIn[ 4], wIn[ 5], wIn[ 6], wIn[ 7],
+                               wIn[ 8], wIn[ 9], wIn[10], wIn[11], wIn[12], wIn[13], wIn[14], wIn[15]
+                       );
+
+                       tlen -= 64;
+                       pData += 64;
+               }
+
+               if (tlen >= 56) {
+                       // Process > 56-byte chunk
+
+                       int cl = (tlen >> 2);
+                       // perform padding on last 2 byte
+                       if (cl > 14) {
+                               dData[14] = wIn[14];
+                       } else {
+                               dData[15] = 0;
+                       }
+                       // copy 1 word with padding byte
+                       switch (len & 0x03) {
+                               case 0:
+                                       dData[cl] = MD5_pad_w0();
+                                       break;
+                               case 1:
+                                       dData[cl] = MD5_pad_w1(wIn[cl]);
+                                       break;
+                               case 2:
+                                       dData[cl] = MD5_pad_w2(wIn[cl]);
+                                       break;
+                               case 3:
+                                       dData[cl] = MD5_pad_w3(wIn[cl]);
+                                       break;
+                       }
+
+                       // transform
+                       MD5_transform_add(
+                               wIn[ 0], wIn[ 1], wIn[ 2], wIn[ 3], wIn[ 4], wIn[ 5], wIn[ 6], wIn[ 7],
+                               wIn[ 8], wIn[ 9], wIn[10], wIn[11], wIn[12], wIn[13], dData[14], dData[15]
+                       );
+                       // final transform
+                       #define w14             (len << 3)
+                       #define w15             (len >> 29)
+                       MD5_transform_add(
+                                       0,          0,          0,              0,              0,              0,              0,              0,
+                                       0,              0,              0,              0,              0,              0,    w14,        w15
+                       );
+                       #undef  w14
+                       #undef  w15
+                       return;
+               } else {
+                       // (len mod 64) < 56
+
+                       MD5_copy_pad_block(dData, wIn, (tlen >> 2), len);
+
+                       #undef  wIn
+                       #define wIn             dData
+
+                       // transform
+                       MD5_transform_add(
+                               wIn[ 0], wIn[ 1], wIn[ 2], wIn[ 3], wIn[ 4], wIn[ 5], wIn[ 6], wIn[ 7],
+                               wIn[ 8], wIn[ 9], wIn[10], wIn[11], wIn[12], wIn[13], wIn[14], wIn[15]
+                       );
+
+                       #undef  wIn
+                       #define wIn             ((UINT4 *)pData)
+                       return;
+               }
+       }
+
+       /* end of fast_MD5() */
+}
+
diff --git a/Client Applications/rcracki_mt/fast_md5.h b/Client Applications/rcracki_mt/fast_md5.h
new file mode 100644 (file)
index 0000000..efea781
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Fast implementation of the MD5 message-digest algorithm as per RFC
+ * (see http://tools.ietf.org/html/rfc1321)
+ *
+ * Author: Joao Inacio <jcinacio at gmail.com>
+ * License: Use and share as you wish at your own risk, please keep this header ;)
+ *
+ * Optimizations:
+ *  - For lengths < 16, transformation steps are "unrolled" using macros/defines
+ *  - Constants used whenever possible, it's the compiler's job to sort them out
+ *  - Padding is done on 4-byte words, and memory copied as last resort.
+ */
+
+
+#ifndef FAST_MD5_H
+#define FAST_MD5_H
+
+
+void
+fast_MD5(unsigned char *pData, int len, unsigned char *pDigest);
+
+
+#endif // FAST_MD5_H
diff --git a/Client Applications/rcracki_mt/libeay32.dll b/Client Applications/rcracki_mt/libeay32.dll
new file mode 100644 (file)
index 0000000..36f6d69
Binary files /dev/null and b/Client Applications/rcracki_mt/libeay32.dll differ
diff --git a/Client Applications/rcracki_mt/libeay32.lib b/Client Applications/rcracki_mt/libeay32.lib
new file mode 100644 (file)
index 0000000..93139c6
Binary files /dev/null and b/Client Applications/rcracki_mt/libeay32.lib differ
diff --git a/Client Applications/rcracki_mt/lm2ntlm.cpp b/Client Applications/rcracki_mt/lm2ntlm.cpp
new file mode 100644 (file)
index 0000000..1b80e9c
--- /dev/null
@@ -0,0 +1,2256 @@
+/*
+* Copyright (C) Daniël Niggebrugge <niggebrugge@fox-it.com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, [...] etc :p
+*/
+
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "lm2ntlm.h"
+
+LM2NTLMcorrector::LM2NTLMcorrector()
+{
+       progressCurrentCombination = 0;
+       totalCurrentCombination = 1;
+       counterOverall = 0;
+       countCombinations = 0;
+       countTotalCombinations = 0;
+       counter = 0;
+       fillMapW();
+       aborting = false;
+       sBinary = "";
+
+}
+
+string LM2NTLMcorrector::getBinary()
+{
+       return sBinary;
+}
+
+bool LM2NTLMcorrector::LMPasswordCorrectUnicode(string hexPassword, unsigned char* pNTLMHash, string& sNTLMPassword) //, unsigned char* pLMPassword
+{
+       string sPlain = "";
+
+       int i;
+       for (i = 0; i < hexPassword.size() / 2; i++)
+       {
+               string sSub = hexPassword.substr(i * 2, 2);
+               int nValue;
+               sscanf(sSub.c_str(), "%02x", &nValue);
+               sPlain += (unsigned char)nValue;
+       }
+
+       memcpy(NTLMHash, pNTLMHash, 16);
+
+
+       int tmpLength = sPlain.size() * 2;
+       unsigned char* pLMPassword = new unsigned char[tmpLength];
+
+       //printf("Searching for unicode password.\n");
+       printf("Failed case correction, trying unicode correction for: %s\n", sPlain.c_str());
+       //printf("NTLM hash:          %s\n\n", sNTLMHash.c_str());
+       
+       setvbuf(stdout, NULL, _IONBF,0);
+
+       startClock = clock();
+       previousClock = clock();
+
+#ifndef _WIN32
+       tty_init();
+#endif
+
+       if (startCorrecting(sPlain, NTLMHash, sNTLMPassword, pLMPassword))
+       {
+               sBinary = ByteToStr(pLMPassword, tmpLength).c_str();
+               //printf("\nFound unicode password: %s\n", sNTLMPassword.c_str());
+               //printf("Password in hex: %s\n", sBinary.c_str());
+               writeEndStats();
+#ifndef _WIN32
+               tty_done();
+#endif
+               return true;
+       }
+       else
+       {
+               //printf("\ncase correction for password %s fail!\n", sPlain.c_str());
+               writeEndStats();
+#ifndef _WIN32
+               tty_done();
+#endif
+               return false;
+       }
+}
+
+bool LM2NTLMcorrector::startCorrecting(string sLMPassword, unsigned char* pNTLMHash, string& sNTLMPassword, unsigned char* pLMPassword)
+{
+       if (sLMPassword.size() == 0)
+       {
+               sNTLMPassword = "";
+               return true;
+       }
+
+       string muteMe = sLMPassword;
+       int length = muteMe.size();
+
+       unsigned char* pMuteMe = new unsigned char[length];
+       unsigned char* pTempMute = new unsigned char[length * 2];
+
+       int i;
+       for (i = 0; i < length; i++)
+       {
+               pMuteMe[i] = muteMe[i];
+               pTempMute[i * 2    ] = muteMe[i];
+               pTempMute[i * 2 + 1] = 0x00;
+               unsigned char muteChar = pMuteMe[i];
+               int sizeMapForChar = m_mapChar[muteChar].size();
+               int j;
+               for (j = 0; j < sizeMapForChar; j++)
+               {
+                       currentCharmap[i][j] = m_mapChar[muteChar][j];
+               }
+       }
+       
+       int* jAtPos = new int[length];
+       int* sizeAtPos = new int[length];
+       bool* fullAtPos = new bool[length];
+
+       int setSize;
+       for (setSize = 0; setSize <= length; setSize++)
+       {
+               int cntFull = 0;
+
+               // clear all 'fullatpos' before new setSize
+               int i;
+               for (i=0; i < length; i++)
+               {
+                       fullAtPos[i] = false;
+               }
+
+               //printf("Trying full unicode map for %d/%d characters...\t\t\n", setSize, length);
+               printf("Trying full unicode map for %d/%d characters...%-20s\n", setSize, length, "");
+
+               bool notFirst = true;
+
+               // start at end and set 'full' combination
+               countCombinations = 0;
+               countTotalCombinations = calculateTotalCombinations(length, setSize);
+
+               int sPos = length - 1;
+               while (sPos >= 0 && notFirst) // finding combinations for current 'setSize'
+               {
+                       if (aborting)
+                               return false;
+
+                       if (cntFull < setSize)
+                       {
+                               if (fullAtPos[sPos] == false)
+                               {
+                                       fullAtPos[sPos] = true;
+                                       cntFull++;
+                               }
+                               sPos--;
+                       }
+                       else
+                       {
+                               if (fullAtPos[sPos] == false && setSize > 0)
+                               {
+                                       fullAtPos[sPos] = true;
+                                       cntFull++;
+                                       
+                                       // reset positions after sPos
+                                       int k;
+                                       for (k = sPos+1; k < length; k++)
+                                       {
+                                               if (fullAtPos[k] == true)
+                                               {
+                                                       fullAtPos[k] = false;
+                                                       cntFull--;
+                                               }
+                                       }
+                                       // start at end again
+                                       sPos = length - 1;
+                               }
+                               else
+                               {
+                                       sPos--;
+                               }
+                       }
+                       // we have a combination
+                       if (cntFull == setSize)
+                       {
+                               countCombinations++;
+
+                               setupCombinationAtPositions(length, pMuteMe, pTempMute, jAtPos, fullAtPos, sizeAtPos);
+
+                               if (checkPermutations(length, pMuteMe, pTempMute, jAtPos, sizeAtPos, pLMPassword, sNTLMPassword))
+                               {
+                                       return true;
+                               }
+                       }
+
+                       if (setSize == 0)
+                               notFirst = false;
+               }
+       }
+       return false;
+}
+
+// set up combination at positions
+void LM2NTLMcorrector::setupCombinationAtPositions(int length, unsigned char* pMuteMe, unsigned char* pTempMute, int* jAtPos, bool* fullAtPos, int* sizeAtPos)
+{
+       progressCurrentCombination = 0;
+       totalCurrentCombination = 1;
+
+       int i;
+       for (i=0; i < length; i++)
+       {
+               pTempMute[i*2] = currentCharmap[i][0];
+               pTempMute[i*2+1] = currentCharmap[i][1]; // reset to first char in map
+       
+               jAtPos[i] = 0; // reset charcounter for this char (that is all chars)
+
+               // based on combination, set full map or only upper/lowercase
+               if (fullAtPos[i] == true)
+               {
+                       unsigned char muteChar = pMuteMe[i];
+                       int sizeMapForChar = m_mapChar[muteChar].size()/2; // 2 bytes per char
+                       sizeAtPos[i] = sizeMapForChar;
+               }
+               else
+               {
+                       sizeAtPos[i] = 2;
+               }
+
+               totalCurrentCombination *= sizeAtPos[i];
+       }
+       //printf("Trying %I64u passwords for current combination\t\t\r", totalCurrentCombination);
+}
+
+// go check all permutations for this combination
+bool LM2NTLMcorrector::checkPermutations(int length, unsigned char* pMuteMe, unsigned char* pTempMute, int* jAtPos, int* sizeAtPos, unsigned char* pLMPassword, string& sNTLMPassword)
+{
+       int pos = length - 1;
+
+       while (pos >= 0)
+       {
+               counter++;
+
+               pos = length - 1;
+
+               int jAtCurPos = jAtPos[pos];
+               int sizeMapForCharPos = sizeAtPos[pos];
+               // move to start of string and find character with permutations left
+               while (jAtCurPos >= sizeMapForCharPos-1 && pos >= -1)
+               {
+                       pos--;
+                       if (pos >= 0 )
+                       {
+                               jAtCurPos = jAtPos[pos];
+                               sizeMapForCharPos = sizeAtPos[pos];
+                       }
+               }
+               if (pos < 0)
+                       continue;
+
+               // next permutation for character
+               jAtCurPos++;
+               jAtPos[pos] = jAtCurPos;
+               
+               pTempMute[pos*2] = currentCharmap[pos][jAtCurPos*2];
+               pTempMute[pos*2+1] = currentCharmap[pos][jAtCurPos*2+1];
+               
+               // reset positions after pos
+               int k;
+               for (k = pos+1; k < length; k++)
+               {
+                       jAtPos[k] = 0;
+                       pTempMute[k*2] = currentCharmap[k][0]; // reset to first char in map
+                       pTempMute[k*2+1] = currentCharmap[k][1];
+               }
+
+               if (checkNTLMPassword(pTempMute, length, sNTLMPassword) == true)
+               {
+                       int i;
+                       for (i = 0; i < length*2; i++)
+                               pLMPassword[i] = pTempMute[i];
+                       return true;
+               }
+
+               if (counter > 10000) // don't check clocks too often
+               {
+                       clock_t currentClock = clock();
+                       float fTime = 1.0f * (currentClock - previousClock);
+                       if (fTime > 1.0f * CLOCKS_PER_SEC)
+                       {
+                               float progressPercentageCurrentCombination = progressCurrentCombination * 100.0f / totalCurrentCombination;
+                               float fTime = 1.0f * (currentClock - startClock) / CLOCKS_PER_SEC;
+                               float currentSpeed = (counterOverall + progressCurrentCombination) / fTime / 1000000;
+
+                               //printf("%.2f%% of combination %d/%d (%.2f Mhashes/s)\t\t\t\t\r", progressPercentageCurrentCombination, countCombinations, countTotalCombinations, currentSpeed);
+                               printf("%.2f%% of combination %d/%d (%.2f Mhashes/s)%-30s\r", progressPercentageCurrentCombination, countCombinations, countTotalCombinations, currentSpeed, "");
+
+                               previousClock = clock();
+                               #ifdef _WIN32
+                               if (_kbhit())
+                               {
+                                       int ch = _getch();
+                                       ch = toupper(ch);
+                                       if (ch == 'S')
+                                       {
+                                               aborting = true;
+                                               printf( "\nAborting unicode correction for this hash...\n");
+                                       }
+                                       else
+                                       {
+                                               printf( "\nPress 'S' to skip unicode correction for this hash...\n");
+                                       }
+                               }
+                               #else
+                               int c = tty_getchar();
+                               if (c >= 0) {
+                                       tty_flush();
+                                       if (c==115) { // = s
+                                               aborting = true;
+                                               printf( "\nAborting unicode correction for this hash...\n");
+                                       }
+                                       else {
+                                               printf( "\nPress 's' to skip unicode correction for this hash...\n");
+                                       }
+                               }
+                               #endif
+                               if (aborting)
+                                       return false;
+                       }
+                       counter = 0;
+               }
+               
+               progressCurrentCombination++;
+               counterOverall++;
+       }
+       return false;
+}
+
+// check password, maybe integrate this function in checkPermutations() for performance reasons.
+bool LM2NTLMcorrector::checkNTLMPassword(unsigned char* pLMPassword, int nLMPasswordLen, string& sNTLMPassword)
+{
+       unsigned char md[16];
+
+       //MD4(pLMPassword, nLMPasswordLen * 2, md);
+       MD4_CTX ctx;
+       MD4_Init(&ctx);
+       MD4_Update(&ctx, pLMPassword, nLMPasswordLen * 2);
+       MD4_Final(md, &ctx);  
+
+       if (memcmp(md, NTLMHash, 16) == 0)
+       {
+               sNTLMPassword = "";
+               int i;
+               for (i = 0; i < nLMPasswordLen; i++) {
+                       sNTLMPassword += char(pLMPassword[i * 2]);
+               }
+               return true;
+       }
+       else
+               return false;
+}
+
+void LM2NTLMcorrector::checkAbort()
+{
+#ifdef _WIN32
+       if (_kbhit())
+       {
+               int ch = _getch();
+               ch = toupper(ch);
+               if (ch == 'S')
+               {
+                       aborting = true;
+                       printf( "\nAborting unicode correction for this hash...\n");
+               }
+               else
+               {
+                       printf( "\nPress 'S' to skip unicode correction for this hash...\n");
+               }
+       }
+#endif
+}
+
+void LM2NTLMcorrector::writeEndStats()
+{
+       clock_t endClock = clock();
+       if (endClock - startClock > 0)
+       {
+               float fTime = 1.0f * (endClock - startClock) / CLOCKS_PER_SEC;
+               float speedOverall = counterOverall / fTime / 1000000;
+               printf("\nTried %s passwords in %.2f s (%.2f Mhashes/s)\n", uint64tostr(counterOverall).c_str(), fTime, speedOverall);
+       }
+
+       printf("\n");
+}
+
+int LM2NTLMcorrector::calculateTotalCombinations(int length, int setSize)
+{
+       return factorial(length) / (factorial(setSize) * factorial(length-setSize));
+}
+
+
+int LM2NTLMcorrector::factorial (int num)
+{
+       int result = 1;
+       int i;
+       for (i = 1; i <= num; ++i)
+               result *= i;
+       return result;
+}
+
+// convert some bytes into a string
+string LM2NTLMcorrector::ByteToStr(const unsigned char* pData, int nLen)
+{
+       string sRet = "";
+       int i;
+       for (i = 0; i < nLen/2; i++)
+       {
+               char szByte[3];
+               sprintf(szByte, "%02x", pData[i*2+1]); // swap 2-byte characters again
+               sRet += szByte;
+               sprintf(szByte, "%02x", pData[i*2]);
+               sRet += szByte;
+       }
+
+       return sRet;
+}
+
+void LM2NTLMcorrector::addToMapW(unsigned char key, unsigned char value1, unsigned char value2)
+{
+       int cnt = m_mapChar[key].size();
+       m_mapChar[key][cnt] = value2;
+       m_mapChar[key][cnt+1] = value1; //reverse for endiannes
+}
+
+// construct the mappings, would be nicer in a separate (importable) file
+void LM2NTLMcorrector::fillMapW()
+{
+       addToMapW(0x01, 0x00, 0x01);
+       addToMapW(0x01, 0x26, 0x3A);
+       addToMapW(0x02, 0x00, 0x02);
+       addToMapW(0x02, 0x26, 0x3B);
+       addToMapW(0x03, 0x00, 0x03);
+       addToMapW(0x03, 0x26, 0x65);
+       addToMapW(0x04, 0x00, 0x04);
+       addToMapW(0x04, 0x26, 0x66);
+       addToMapW(0x05, 0x00, 0x05);
+       addToMapW(0x05, 0x26, 0x63);
+       addToMapW(0x06, 0x00, 0x06);
+       addToMapW(0x06, 0x26, 0x60);
+       addToMapW(0x07, 0x00, 0x07);
+       addToMapW(0x07, 0x00, 0xB7);
+       addToMapW(0x07, 0x20, 0x22);
+       addToMapW(0x07, 0x20, 0x24);
+       addToMapW(0x07, 0x20, 0x26);
+       addToMapW(0x07, 0x22, 0x19);
+       addToMapW(0x07, 0x22, 0xC5);
+       addToMapW(0x07, 0x30, 0xFB);
+       addToMapW(0x08, 0x00, 0x08);
+       addToMapW(0x08, 0x25, 0xD8);
+       addToMapW(0x09, 0x00, 0x09);
+       addToMapW(0x09, 0x20, 0xDD);
+       addToMapW(0x09, 0x25, 0xCB);
+       addToMapW(0x09, 0x30, 0x07);
+       addToMapW(0x0a, 0x00, 0x0A);
+       addToMapW(0x0a, 0x25, 0xD9);
+       addToMapW(0x0b, 0x00, 0x0B);
+       addToMapW(0x0b, 0x26, 0x42);
+       addToMapW(0x0c, 0x00, 0x0C);
+       addToMapW(0x0c, 0x26, 0x40);
+       addToMapW(0x0d, 0x00, 0x0D);
+       addToMapW(0x0d, 0x26, 0x6A);
+       addToMapW(0x0e, 0x00, 0x0E);
+       addToMapW(0x0e, 0x26, 0x6B);
+       addToMapW(0x0f, 0x00, 0x0F);
+       addToMapW(0x0f, 0x00, 0xA4);
+       addToMapW(0x0f, 0x26, 0x3C);
+       addToMapW(0x10, 0x00, 0x10);
+       addToMapW(0x10, 0x25, 0xBA);
+       addToMapW(0x11, 0x00, 0x11);
+       addToMapW(0x11, 0x25, 0xC4);
+       addToMapW(0x12, 0x00, 0x12);
+       addToMapW(0x12, 0x21, 0x95);
+       addToMapW(0x13, 0x00, 0x13);
+       addToMapW(0x13, 0x20, 0x3C);
+       addToMapW(0x14, 0x00, 0x14);
+       addToMapW(0x14, 0x00, 0xB6);
+       addToMapW(0x15, 0x00, 0x15);
+       addToMapW(0x15, 0x00, 0xA7);
+       addToMapW(0x16, 0x00, 0x16);
+       addToMapW(0x16, 0x02, 0xC9);
+       addToMapW(0x16, 0x25, 0xAC);
+       addToMapW(0x17, 0x00, 0x17);
+       addToMapW(0x17, 0x21, 0xA8);
+       addToMapW(0x18, 0x00, 0x18);
+       addToMapW(0x18, 0x21, 0x91);
+       addToMapW(0x19, 0x00, 0x19);
+       addToMapW(0x19, 0x21, 0x93);
+       addToMapW(0x1a, 0x00, 0x1A);
+       addToMapW(0x1a, 0x21, 0x92);
+       addToMapW(0x1b, 0x00, 0x1B);
+       addToMapW(0x1b, 0x21, 0x90);
+       addToMapW(0x1c, 0x00, 0x1C);
+       addToMapW(0x1c, 0x22, 0x1F);
+       addToMapW(0x1d, 0x00, 0x1D);
+       addToMapW(0x1d, 0x21, 0x94);
+       addToMapW(0x1e, 0x00, 0x1E);
+       addToMapW(0x1e, 0x25, 0xB2);
+       addToMapW(0x1f, 0x00, 0x1F);
+       addToMapW(0x1f, 0x25, 0xBC);
+       addToMapW(0x20, 0x00, 0x20);
+       addToMapW(0x20, 0x20, 0x00);
+       addToMapW(0x20, 0x20, 0x01);
+       addToMapW(0x20, 0x20, 0x02);
+       addToMapW(0x20, 0x20, 0x03);
+       addToMapW(0x20, 0x20, 0x04);
+       addToMapW(0x20, 0x20, 0x05);
+       addToMapW(0x20, 0x20, 0x06);
+       addToMapW(0x20, 0x30, 0x00);
+       addToMapW(0x21, 0x00, 0x21);
+       addToMapW(0x21, 0x00, 0xA1);
+       addToMapW(0x21, 0x01, 0xC3);
+       addToMapW(0x21, 0xFF, 0x01);
+       addToMapW(0x22, 0x00, 0x22);
+       addToMapW(0x22, 0x00, 0xA8);
+       addToMapW(0x22, 0x02, 0xBA);
+       addToMapW(0x22, 0x03, 0x08);
+       addToMapW(0x22, 0x03, 0x0E);
+       addToMapW(0x22, 0x20, 0x1C);
+       addToMapW(0x22, 0x20, 0x1D);
+       addToMapW(0x22, 0x20, 0x1E);
+       addToMapW(0x22, 0x20, 0x33);
+       addToMapW(0x22, 0x20, 0x35);
+       addToMapW(0x22, 0x27, 0x5D);
+       addToMapW(0x22, 0x27, 0x5E);
+       addToMapW(0x22, 0x30, 0x1D);
+       addToMapW(0x22, 0x30, 0x1E);
+       addToMapW(0x22, 0x30, 0x1F);
+       addToMapW(0x22, 0xFF, 0x02);
+       addToMapW(0x23, 0x00, 0x23);
+       addToMapW(0x23, 0xFF, 0x03);
+       addToMapW(0x24, 0x00, 0x24);
+       addToMapW(0x24, 0xFF, 0x04);
+       addToMapW(0x25, 0x00, 0x25);
+       addToMapW(0x25, 0x06, 0x6A);
+       addToMapW(0x25, 0x20, 0x30);
+       addToMapW(0x25, 0xFF, 0x05);
+       addToMapW(0x26, 0x00, 0x26);
+       addToMapW(0x26, 0xFF, 0x06);
+       addToMapW(0x27, 0x00, 0x27);
+       addToMapW(0x27, 0x00, 0xB4);
+       addToMapW(0x27, 0x02, 0xB9);
+       addToMapW(0x27, 0x02, 0xBB);
+       addToMapW(0x27, 0x02, 0xBC);
+       addToMapW(0x27, 0x02, 0xC8);
+       addToMapW(0x27, 0x02, 0xCA);
+       addToMapW(0x27, 0x02, 0xCB);
+       addToMapW(0x27, 0x03, 0x00);
+       addToMapW(0x27, 0x03, 0x01);
+       addToMapW(0x27, 0x20, 0x18);
+       addToMapW(0x27, 0x20, 0x19);
+       addToMapW(0x27, 0x20, 0x1A);
+       addToMapW(0x27, 0x20, 0x32);
+       addToMapW(0x27, 0x27, 0x5B);
+       addToMapW(0x27, 0x27, 0x5C);
+       addToMapW(0x27, 0xFF, 0x07);
+       addToMapW(0x28, 0x00, 0x28);
+       addToMapW(0x28, 0x23, 0x20);
+       addToMapW(0x28, 0xFF, 0x08);
+       addToMapW(0x29, 0x00, 0x29);
+       addToMapW(0x29, 0x23, 0x21);
+       addToMapW(0x29, 0xFF, 0x09);
+       addToMapW(0x2a, 0x00, 0x2A);
+       addToMapW(0x2a, 0x22, 0x17);
+       addToMapW(0x2a, 0xFF, 0x0A);
+       addToMapW(0x2b, 0x00, 0x2B);
+       addToMapW(0x2b, 0x00, 0xB1);
+       addToMapW(0x2b, 0x20, 0x20);
+       addToMapW(0x2b, 0x20, 0x21);
+       addToMapW(0x2b, 0xFF, 0x0B);
+       addToMapW(0x2c, 0x00, 0x2C);
+       addToMapW(0x2c, 0x00, 0xB8);
+       addToMapW(0x2c, 0x03, 0x27);
+       addToMapW(0x2c, 0x20, 0x1A);
+       addToMapW(0x2c, 0x20, 0x1E);
+       addToMapW(0x2c, 0xFF, 0x0C);
+       addToMapW(0x2d, 0x00, 0x2D);
+       addToMapW(0x2d, 0x00, 0xAC);
+       addToMapW(0x2d, 0x00, 0xAD);
+       addToMapW(0x2d, 0x20, 0x10);
+       addToMapW(0x2d, 0x20, 0x11);
+       addToMapW(0x2d, 0x20, 0x13);
+       addToMapW(0x2d, 0x20, 0x14);
+       addToMapW(0x2d, 0x22, 0x12);
+       addToMapW(0x2d, 0x22, 0x13);
+       addToMapW(0x2d, 0xFF, 0x0D);
+       addToMapW(0x2e, 0x00, 0x2E);
+       addToMapW(0x2e, 0x20, 0x26);
+       addToMapW(0x2e, 0xFF, 0x0E);
+       addToMapW(0x2f, 0x00, 0x2F);
+       addToMapW(0x2f, 0x20, 0x44);
+       addToMapW(0x2f, 0x22, 0x15);
+       addToMapW(0x2f, 0x22, 0x16);
+       addToMapW(0x2f, 0xFF, 0x0F);
+       addToMapW(0x30, 0x00, 0x30);
+       addToMapW(0x30, 0x20, 0x70);
+       addToMapW(0x30, 0x20, 0x80);
+       addToMapW(0x30, 0xFF, 0x10);
+       addToMapW(0x31, 0x00, 0x31);
+       addToMapW(0x31, 0x00, 0xB9);
+       addToMapW(0x31, 0x00, 0xBC);
+       addToMapW(0x31, 0x00, 0xBD);
+       addToMapW(0x31, 0x20, 0x81);
+       addToMapW(0x31, 0xFF, 0x11);
+       addToMapW(0x32, 0x00, 0x32);
+       addToMapW(0x32, 0x00, 0xB2);
+       addToMapW(0x32, 0x20, 0x82);
+       addToMapW(0x32, 0xFF, 0x12);
+       addToMapW(0x33, 0x00, 0x33);
+       addToMapW(0x33, 0x00, 0xB3);
+       addToMapW(0x33, 0x00, 0xBE);
+       addToMapW(0x33, 0x20, 0x83);
+       addToMapW(0x33, 0xFF, 0x13);
+       addToMapW(0x34, 0x00, 0x34);
+       addToMapW(0x34, 0x20, 0x74);
+       addToMapW(0x34, 0x20, 0x84);
+       addToMapW(0x34, 0xFF, 0x14);
+       addToMapW(0x35, 0x00, 0x35);
+       addToMapW(0x35, 0x20, 0x75);
+       addToMapW(0x35, 0x20, 0x85);
+       addToMapW(0x35, 0xFF, 0x15);
+       addToMapW(0x36, 0x00, 0x36);
+       addToMapW(0x36, 0x20, 0x76);
+       addToMapW(0x36, 0x20, 0x86);
+       addToMapW(0x36, 0xFF, 0x16);
+       addToMapW(0x37, 0x00, 0x37);
+       addToMapW(0x37, 0x20, 0x77);
+       addToMapW(0x37, 0x20, 0x87);
+       addToMapW(0x37, 0xFF, 0x17);
+       addToMapW(0x38, 0x00, 0x38);
+       addToMapW(0x38, 0x20, 0x78);
+       addToMapW(0x38, 0x20, 0x88);
+       addToMapW(0x38, 0x22, 0x1E);
+       addToMapW(0x38, 0xFF, 0x18);
+       addToMapW(0x39, 0x00, 0x39);
+       addToMapW(0x39, 0x20, 0x78);
+       addToMapW(0x39, 0x20, 0x89);
+       addToMapW(0x39, 0xFF, 0x19);
+       addToMapW(0x3a, 0x00, 0x3A);
+       addToMapW(0x3a, 0x05, 0x89);
+       addToMapW(0x3a, 0x20, 0x26);
+       addToMapW(0x3a, 0x22, 0x36);
+       addToMapW(0x3a, 0xFF, 0x1A);
+       addToMapW(0x3b, 0x00, 0x3B);
+       addToMapW(0x3b, 0x03, 0x7E);
+       addToMapW(0x3b, 0xFF, 0x1B);
+       addToMapW(0x3c, 0x00, 0x3C);
+       addToMapW(0x3c, 0x00, 0xAB);
+       addToMapW(0x3c, 0x20, 0x39);
+       addToMapW(0x3c, 0x23, 0x29);
+       addToMapW(0x3c, 0x30, 0x08);
+       addToMapW(0x3c, 0xFF, 0x1C);
+       addToMapW(0x3d, 0x00, 0x3D);
+       addToMapW(0x3d, 0x22, 0x61);
+       addToMapW(0x3d, 0x22, 0x64);
+       addToMapW(0x3d, 0x22, 0x65);
+       addToMapW(0x3d, 0xFF, 0x1D);
+       addToMapW(0x3e, 0x00, 0x3E);
+       addToMapW(0x3e, 0x00, 0xBB);
+       addToMapW(0x3e, 0x20, 0x3A);
+       addToMapW(0x3e, 0x23, 0x2A);
+       addToMapW(0x3e, 0x30, 0x09);
+       addToMapW(0x3e, 0xFF, 0x1E);
+       addToMapW(0x3f, 0x00, 0x3F);
+       addToMapW(0x40, 0x00, 0x40);
+       addToMapW(0x40, 0xFF, 0x20);
+       addToMapW(0x41, 0x00, 0x41);
+       addToMapW(0x41, 0x00, 0x61);
+       addToMapW(0x41, 0x00, 0xAA);
+       addToMapW(0x41, 0x00, 0xC0);
+       addToMapW(0x41, 0x00, 0xC1);
+       addToMapW(0x41, 0x00, 0xC2);
+       addToMapW(0x41, 0x00, 0xC3);
+       addToMapW(0x41, 0x00, 0xC4);
+       addToMapW(0x41, 0x00, 0xC5);
+       addToMapW(0x41, 0x00, 0xC6);
+       addToMapW(0x41, 0x00, 0xE0);
+       addToMapW(0x41, 0x00, 0xE1);
+       addToMapW(0x41, 0x00, 0xE2);
+       addToMapW(0x41, 0x00, 0xE3);
+       addToMapW(0x41, 0x00, 0xE4);
+       addToMapW(0x41, 0x00, 0xE5);
+       addToMapW(0x41, 0x00, 0xE6);
+       addToMapW(0x41, 0x01, 0x00);
+       addToMapW(0x41, 0x01, 0x01);
+       addToMapW(0x41, 0x01, 0x02);
+       addToMapW(0x41, 0x01, 0x03);
+       addToMapW(0x41, 0x01, 0x04);
+       addToMapW(0x41, 0x01, 0x05);
+       addToMapW(0x41, 0x01, 0xCD);
+       addToMapW(0x41, 0x01, 0xCE);
+       addToMapW(0x41, 0x01, 0xDE);
+       addToMapW(0x41, 0x01, 0xDF);
+       addToMapW(0x41, 0x03, 0xB1);
+       addToMapW(0x41, 0x21, 0x2B);
+       addToMapW(0x41, 0xFF, 0x21);
+       addToMapW(0x41, 0xFF, 0x41);
+       addToMapW(0x42, 0x00, 0x42);
+       addToMapW(0x42, 0x00, 0x62);
+       addToMapW(0x42, 0x01, 0x80);
+       addToMapW(0x42, 0x21, 0x2C);
+       addToMapW(0x42, 0xFF, 0x22);
+       addToMapW(0x42, 0xFF, 0x42);
+       addToMapW(0x43, 0x00, 0x43);
+       addToMapW(0x43, 0x00, 0x63);
+       addToMapW(0x43, 0x00, 0xA2);
+       addToMapW(0x43, 0x00, 0xA9);
+       addToMapW(0x43, 0x00, 0xC7);
+       addToMapW(0x43, 0x00, 0xE7);
+       addToMapW(0x43, 0x00, 0xE8);
+       addToMapW(0x43, 0x01, 0x06);
+       addToMapW(0x43, 0x01, 0x07);
+       addToMapW(0x43, 0x01, 0x08);
+       addToMapW(0x43, 0x01, 0x09);
+       addToMapW(0x43, 0x01, 0x0A);
+       addToMapW(0x43, 0x01, 0x0B);
+       addToMapW(0x43, 0x01, 0x0C);
+       addToMapW(0x43, 0x01, 0x0D);
+       addToMapW(0x43, 0x21, 0x02);
+       addToMapW(0x43, 0x21, 0x2D);
+       addToMapW(0x43, 0xFF, 0x23);
+       addToMapW(0x43, 0xFF, 0x43);
+       addToMapW(0x44, 0x00, 0x44);
+       addToMapW(0x44, 0x00, 0x64);
+       addToMapW(0x44, 0x00, 0xD0);
+       addToMapW(0x44, 0x00, 0xF0);
+       addToMapW(0x44, 0x01, 0x0E);
+       addToMapW(0x44, 0x01, 0x0F);
+       addToMapW(0x44, 0x01, 0x10);
+       addToMapW(0x44, 0x01, 0x11);
+       addToMapW(0x44, 0x01, 0x89);
+       addToMapW(0x44, 0x03, 0xB4);
+       addToMapW(0x44, 0x26, 0x6A);
+       addToMapW(0x44, 0x26, 0x6B);
+       addToMapW(0x44, 0xFF, 0x24);
+       addToMapW(0x44, 0xFF, 0x44);
+       addToMapW(0x45, 0x00, 0x45);
+       addToMapW(0x45, 0x00, 0x65);
+       addToMapW(0x45, 0x00, 0xC8);
+       addToMapW(0x45, 0x00, 0xC9);
+       addToMapW(0x45, 0x00, 0xCA);
+       addToMapW(0x45, 0x00, 0xCB);
+       addToMapW(0x45, 0x00, 0xE8);
+       addToMapW(0x45, 0x00, 0xE9);
+       addToMapW(0x45, 0x00, 0xEA);
+       addToMapW(0x45, 0x00, 0xEB);
+       addToMapW(0x45, 0x01, 0x12);
+       addToMapW(0x45, 0x01, 0x13);
+       addToMapW(0x45, 0x01, 0x14);
+       addToMapW(0x45, 0x01, 0x15);
+       addToMapW(0x45, 0x01, 0x16);
+       addToMapW(0x45, 0x01, 0x17);
+       addToMapW(0x45, 0x01, 0x18);
+       addToMapW(0x45, 0x01, 0x19);
+       addToMapW(0x45, 0x01, 0x1A);
+       addToMapW(0x45, 0x01, 0x1B);
+       addToMapW(0x45, 0x03, 0xB5);
+       addToMapW(0x45, 0x21, 0x07);
+       addToMapW(0x45, 0x21, 0x2E);
+       addToMapW(0x45, 0x21, 0x2F);
+       addToMapW(0x45, 0x21, 0x30);
+       addToMapW(0x45, 0xFF, 0x25);
+       addToMapW(0x45, 0xFF, 0x45);
+       addToMapW(0x46, 0x00, 0x46);
+       addToMapW(0x46, 0x00, 0x66);
+       addToMapW(0x46, 0x01, 0x91);
+       addToMapW(0x46, 0x01, 0x92);
+       addToMapW(0x46, 0x03, 0xA6);
+       addToMapW(0x46, 0x03, 0xC6);
+       addToMapW(0x46, 0x21, 0x31);
+       addToMapW(0x46, 0xFF, 0x26);
+       addToMapW(0x46, 0xFF, 0x46);
+       addToMapW(0x47, 0x00, 0x47);
+       addToMapW(0x47, 0x00, 0x67);
+       addToMapW(0x47, 0x01, 0x1C);
+       addToMapW(0x47, 0x01, 0x1D);
+       addToMapW(0x47, 0x01, 0x1E);
+       addToMapW(0x47, 0x01, 0x1F);
+       addToMapW(0x47, 0x01, 0x20);
+       addToMapW(0x47, 0x01, 0x21);
+       addToMapW(0x47, 0x01, 0x22);
+       addToMapW(0x47, 0x01, 0x23);
+       addToMapW(0x47, 0x01, 0xE4);
+       addToMapW(0x47, 0x01, 0xE5);
+       addToMapW(0x47, 0x01, 0xE6);
+       addToMapW(0x47, 0x01, 0xE7);
+       addToMapW(0x47, 0x02, 0x61);
+       addToMapW(0x47, 0x03, 0x93);
+       addToMapW(0x47, 0x21, 0x0A);
+       addToMapW(0x47, 0xFF, 0x27);
+       addToMapW(0x47, 0xFF, 0x47);
+       addToMapW(0x48, 0x00, 0x48);
+       addToMapW(0x48, 0x00, 0x68);
+       addToMapW(0x48, 0x01, 0x24);
+       addToMapW(0x48, 0x01, 0x25);
+       addToMapW(0x48, 0x01, 0x26);
+       addToMapW(0x48, 0x01, 0x27);
+       addToMapW(0x48, 0x04, 0xBB);
+       addToMapW(0x48, 0x21, 0x0B);
+       addToMapW(0x48, 0x21, 0x0C);
+       addToMapW(0x48, 0x21, 0x0D);
+       addToMapW(0x48, 0x21, 0x0E);
+       addToMapW(0x48, 0xFF, 0x28);
+       addToMapW(0x48, 0xFF, 0x48);
+       addToMapW(0x49, 0x00, 0x49);
+       addToMapW(0x49, 0x00, 0x69);
+       addToMapW(0x49, 0x00, 0xCC);
+       addToMapW(0x49, 0x00, 0xCD);
+       addToMapW(0x49, 0x00, 0xCE);
+       addToMapW(0x49, 0x00, 0xCF);
+       addToMapW(0x49, 0x00, 0xEC);
+       addToMapW(0x49, 0x00, 0xED);
+       addToMapW(0x49, 0x00, 0xEE);
+       addToMapW(0x49, 0x00, 0xEF);
+       addToMapW(0x49, 0x01, 0x28);
+       addToMapW(0x49, 0x01, 0x29);
+       addToMapW(0x49, 0x01, 0x2A);
+       addToMapW(0x49, 0x01, 0x2B);
+       addToMapW(0x49, 0x01, 0x2C);
+       addToMapW(0x49, 0x01, 0x2D);
+       addToMapW(0x49, 0x01, 0x2E);
+       addToMapW(0x49, 0x01, 0x2F);
+       addToMapW(0x49, 0x01, 0x30);
+       addToMapW(0x49, 0x01, 0x31);
+       addToMapW(0x49, 0x01, 0x97);
+       addToMapW(0x49, 0x01, 0xCF);
+       addToMapW(0x49, 0x01, 0xD0);
+       addToMapW(0x49, 0x21, 0x10);
+       addToMapW(0x49, 0x21, 0x11);
+       addToMapW(0x49, 0xFF, 0x29);
+       addToMapW(0x49, 0xFF, 0x49);
+       addToMapW(0x4a, 0x00, 0x4A);
+       addToMapW(0x4a, 0x00, 0x6A);
+       addToMapW(0x4a, 0x01, 0x34);
+       addToMapW(0x4a, 0x01, 0x35);
+       addToMapW(0x4a, 0x01, 0xF0);
+       addToMapW(0x4a, 0xFF, 0x2A);
+       addToMapW(0x4a, 0xFF, 0x4A);
+       addToMapW(0x4b, 0x00, 0x4B);
+       addToMapW(0x4b, 0x00, 0x6B);
+       addToMapW(0x4b, 0x01, 0x36);
+       addToMapW(0x4b, 0x01, 0x37);
+       addToMapW(0x4b, 0x01, 0xE8);
+       addToMapW(0x4b, 0x01, 0xE9);
+       addToMapW(0x4b, 0x21, 0x2A);
+       addToMapW(0x4b, 0xFF, 0x2B);
+       addToMapW(0x4b, 0xFF, 0x4B);
+       addToMapW(0x4c, 0x00, 0x4C);
+       addToMapW(0x4c, 0x00, 0x6C);
+       addToMapW(0x4c, 0x00, 0xA3);
+       addToMapW(0x4c, 0x01, 0x39);
+       addToMapW(0x4c, 0x01, 0x3A);
+       addToMapW(0x4c, 0x01, 0x3B);
+       addToMapW(0x4c, 0x01, 0x3C);
+       addToMapW(0x4c, 0x01, 0x3D);
+       addToMapW(0x4c, 0x01, 0x3E);
+       addToMapW(0x4c, 0x01, 0x41);
+       addToMapW(0x4c, 0x01, 0x42);
+       addToMapW(0x4c, 0x01, 0x9A);
+       addToMapW(0x4c, 0x20, 0xA4);
+       addToMapW(0x4c, 0x21, 0x12);
+       addToMapW(0x4c, 0x21, 0x13);
+       addToMapW(0x4c, 0xFF, 0x2C);
+       addToMapW(0x4c, 0xFF, 0x4C);
+       addToMapW(0x4d, 0x00, 0x4D);
+       addToMapW(0x4d, 0x00, 0x6D);
+       addToMapW(0x4d, 0x21, 0x33);
+       addToMapW(0x4d, 0xFF, 0x2D);
+       addToMapW(0x4d, 0xFF, 0x4D);
+       addToMapW(0x4e, 0x00, 0x4E);
+       addToMapW(0x4e, 0x00, 0x6E);
+       addToMapW(0x4e, 0x00, 0xD1);
+       addToMapW(0x4e, 0x00, 0xF1);
+       addToMapW(0x4e, 0x01, 0x43);
+       addToMapW(0x4e, 0x01, 0x44);
+       addToMapW(0x4e, 0x01, 0x45);
+       addToMapW(0x4e, 0x01, 0x46);
+       addToMapW(0x4e, 0x01, 0x47);
+       addToMapW(0x4e, 0x01, 0x48);
+       addToMapW(0x4e, 0x20, 0x7F);
+       addToMapW(0x4e, 0x21, 0x15);
+       addToMapW(0x4e, 0x22, 0x29);
+       addToMapW(0x4e, 0xFF, 0x2E);
+       addToMapW(0x4e, 0xFF, 0x4E);
+       addToMapW(0x4f, 0x00, 0x4F);
+       addToMapW(0x4f, 0x00, 0x6F);
+       addToMapW(0x4f, 0x00, 0xB0);
+       addToMapW(0x4f, 0x00, 0xBA);
+       addToMapW(0x4f, 0x00, 0xD2);
+       addToMapW(0x4f, 0x00, 0xD3);
+       addToMapW(0x4f, 0x00, 0xD4);
+       addToMapW(0x4f, 0x00, 0xD5);
+       addToMapW(0x4f, 0x00, 0xD6);
+       addToMapW(0x4f, 0x00, 0xD8);
+       addToMapW(0x4f, 0x00, 0xF2);
+       addToMapW(0x4f, 0x00, 0xF3);
+       addToMapW(0x4f, 0x00, 0xF4);
+       addToMapW(0x4f, 0x00, 0xF5);
+       addToMapW(0x4f, 0x00, 0xF6);
+       addToMapW(0x4f, 0x00, 0xF8);
+       addToMapW(0x4f, 0x01, 0x4C);
+       addToMapW(0x4f, 0x01, 0x4D);
+       addToMapW(0x4f, 0x01, 0x4E);
+       addToMapW(0x4f, 0x01, 0x4F);
+       addToMapW(0x4f, 0x01, 0x50);
+       addToMapW(0x4f, 0x01, 0x51);
+       addToMapW(0x4f, 0x01, 0x52);
+       addToMapW(0x4f, 0x01, 0x53);
+       addToMapW(0x4f, 0x01, 0x9F);
+       addToMapW(0x4f, 0x01, 0xA0);
+       addToMapW(0x4f, 0x01, 0xA1);
+       addToMapW(0x4f, 0x01, 0xD1);
+       addToMapW(0x4f, 0x01, 0xD2);
+       addToMapW(0x4f, 0x01, 0xEA);
+       addToMapW(0x4f, 0x01, 0xEB);
+       addToMapW(0x4f, 0x01, 0xEC);
+       addToMapW(0x4f, 0x01, 0xED);
+       addToMapW(0x4f, 0x03, 0xA9);
+       addToMapW(0x4f, 0x20, 0xDD);
+       addToMapW(0x4f, 0x21, 0x26);
+       addToMapW(0x4f, 0x21, 0x34);
+       addToMapW(0x4f, 0x22, 0x05);
+       addToMapW(0x4f, 0x30, 0x07);
+       addToMapW(0x4f, 0xFF, 0x2F);
+       addToMapW(0x4f, 0xFF, 0x4F);
+       addToMapW(0x50, 0x00, 0x50);
+       addToMapW(0x50, 0x00, 0x70);
+       addToMapW(0x50, 0x03, 0xC0);
+       addToMapW(0x50, 0x20, 0xA7);
+       addToMapW(0x50, 0x21, 0x18);
+       addToMapW(0x50, 0x21, 0x19);
+       addToMapW(0x50, 0xFF, 0x30);
+       addToMapW(0x50, 0xFF, 0x50);
+       addToMapW(0x51, 0x00, 0x51);
+       addToMapW(0x51, 0x00, 0x71);
+       addToMapW(0x51, 0x21, 0x1A);
+       addToMapW(0x51, 0xFF, 0x31);
+       addToMapW(0x51, 0xFF, 0x51);
+       addToMapW(0x52, 0x00, 0x52);
+       addToMapW(0x52, 0x00, 0x72);
+       addToMapW(0x52, 0x00, 0xAE);
+       addToMapW(0x52, 0x01, 0x54);
+       addToMapW(0x52, 0x01, 0x55);
+       addToMapW(0x52, 0x01, 0x56);
+       addToMapW(0x52, 0x01, 0x57);
+       addToMapW(0x52, 0x01, 0x58);
+       addToMapW(0x52, 0x01, 0x59);
+       addToMapW(0x52, 0x21, 0x1B);
+       addToMapW(0x52, 0x21, 0x1C);
+       addToMapW(0x52, 0x21, 0x1D);
+       addToMapW(0x52, 0xFF, 0x32);
+       addToMapW(0x52, 0xFF, 0x52);
+       addToMapW(0x53, 0x00, 0x53);
+       addToMapW(0x53, 0x00, 0x73);
+       addToMapW(0x53, 0x00, 0xDF);
+       addToMapW(0x53, 0x01, 0x5A);
+       addToMapW(0x53, 0x01, 0x5B);
+       addToMapW(0x53, 0x01, 0x5C);
+       addToMapW(0x53, 0x01, 0x5D);
+       addToMapW(0x53, 0x01, 0x5E);
+       addToMapW(0x53, 0x01, 0x5F);
+       addToMapW(0x53, 0x01, 0x60);
+       addToMapW(0x53, 0x01, 0x61);
+       addToMapW(0x53, 0x01, 0xA9);
+       addToMapW(0x53, 0x03, 0xA3);
+       addToMapW(0x53, 0x03, 0xC3);
+       addToMapW(0x53, 0x22, 0x11);
+       addToMapW(0x53, 0xFF, 0x33);
+       addToMapW(0x53, 0xFF, 0x53);
+       addToMapW(0x54, 0x00, 0x54);
+       addToMapW(0x54, 0x00, 0x74);
+       addToMapW(0x54, 0x00, 0xDE);
+       addToMapW(0x54, 0x00, 0xFE);
+       addToMapW(0x54, 0x01, 0x62);
+       addToMapW(0x54, 0x01, 0x63);
+       addToMapW(0x54, 0x01, 0x64);
+       addToMapW(0x54, 0x01, 0x65);
+       addToMapW(0x54, 0x01, 0x66);
+       addToMapW(0x54, 0x01, 0x67);
+       addToMapW(0x54, 0x01, 0xAB);
+       addToMapW(0x54, 0x01, 0xAE);
+       addToMapW(0x54, 0x03, 0xC4);
+       addToMapW(0x54, 0x21, 0x22);
+       addToMapW(0x54, 0xFF, 0x34);
+       addToMapW(0x54, 0xFF, 0x54);
+       addToMapW(0x55, 0x00, 0x55);
+       addToMapW(0x55, 0x00, 0x75);
+       addToMapW(0x55, 0x00, 0xB5);
+       addToMapW(0x55, 0x00, 0xD9);
+       addToMapW(0x55, 0x00, 0xDA);
+       addToMapW(0x55, 0x00, 0xDB);
+       addToMapW(0x55, 0x00, 0xDC);
+       addToMapW(0x55, 0x00, 0xF9);
+       addToMapW(0x55, 0x00, 0xFA);
+       addToMapW(0x55, 0x00, 0xFB);
+       addToMapW(0x55, 0x00, 0xFC);
+       addToMapW(0x55, 0x01, 0x68);
+       addToMapW(0x55, 0x01, 0x69);
+       addToMapW(0x55, 0x01, 0x6A);
+       addToMapW(0x55, 0x01, 0x6B);
+       addToMapW(0x55, 0x01, 0x6C);
+       addToMapW(0x55, 0x01, 0x6D);
+       addToMapW(0x55, 0x01, 0x6E);
+       addToMapW(0x55, 0x01, 0x6F);
+       addToMapW(0x55, 0x01, 0x70);
+       addToMapW(0x55, 0x01, 0x71);
+       addToMapW(0x55, 0x01, 0x72);
+       addToMapW(0x55, 0x01, 0x73);
+       addToMapW(0x55, 0x01, 0xAF);
+       addToMapW(0x55, 0x01, 0xB0);
+       addToMapW(0x55, 0x01, 0xD3);
+       addToMapW(0x55, 0x01, 0xD4);
+       addToMapW(0x55, 0x01, 0xD5);
+       addToMapW(0x55, 0x01, 0xD6);
+       addToMapW(0x55, 0x01, 0xD7);
+       addToMapW(0x55, 0x01, 0xD8);
+       addToMapW(0x55, 0x01, 0xD9);
+       addToMapW(0x55, 0x01, 0xDA);
+       addToMapW(0x55, 0x01, 0xDB);
+       addToMapW(0x55, 0x01, 0xDC);
+       addToMapW(0x55, 0x03, 0xBC);
+       addToMapW(0x55, 0xFF, 0x35);
+       addToMapW(0x55, 0xFF, 0x55);
+       addToMapW(0x56, 0x00, 0x56);
+       addToMapW(0x56, 0x00, 0x76);
+       addToMapW(0x56, 0x22, 0x1A);
+       addToMapW(0x56, 0x27, 0x13);
+       addToMapW(0x56, 0xFF, 0x36);
+       addToMapW(0x56, 0xFF, 0x56);
+       addToMapW(0x57, 0x00, 0x57);
+       addToMapW(0x57, 0x00, 0x77);
+       addToMapW(0x57, 0x01, 0x74);
+       addToMapW(0x57, 0x01, 0x75);
+       addToMapW(0x57, 0xFF, 0x37);
+       addToMapW(0x57, 0xFF, 0x57);
+       addToMapW(0x58, 0x00, 0x58);
+       addToMapW(0x58, 0x00, 0x78);
+       addToMapW(0x58, 0x00, 0xD7);
+       addToMapW(0x58, 0xFF, 0x38);
+       addToMapW(0x58, 0xFF, 0x58);
+       addToMapW(0x59, 0x00, 0x59);
+       addToMapW(0x59, 0x00, 0x79);
+       addToMapW(0x59, 0x00, 0xA5);
+       addToMapW(0x59, 0x00, 0xDD);
+       addToMapW(0x59, 0x00, 0xFD);
+       addToMapW(0x59, 0x00, 0xFF);
+       addToMapW(0x59, 0x01, 0x76);
+       addToMapW(0x59, 0x01, 0x77);
+       addToMapW(0x59, 0x01, 0x78);
+       addToMapW(0x59, 0xFF, 0x39);
+       addToMapW(0x59, 0xFF, 0x59);
+       addToMapW(0x5a, 0x00, 0x5A);
+       addToMapW(0x5a, 0x00, 0x7A);
+       addToMapW(0x5a, 0x01, 0x79);
+       addToMapW(0x5a, 0x01, 0x7A);
+       addToMapW(0x5a, 0x01, 0x7B);
+       addToMapW(0x5a, 0x01, 0x7C);
+       addToMapW(0x5a, 0x01, 0x7D);
+       addToMapW(0x5a, 0x01, 0x7E);
+       addToMapW(0x5a, 0x01, 0xB6);
+       addToMapW(0x5a, 0x21, 0x24);
+       addToMapW(0x5a, 0x21, 0x28);
+       addToMapW(0x5a, 0xFF, 0x3A);
+       addToMapW(0x5a, 0xFF, 0x5A);
+       addToMapW(0x5b, 0x00, 0x5B);
+       addToMapW(0x5b, 0x30, 0x1A);
+       addToMapW(0x5b, 0xFF, 0x3B);
+       addToMapW(0x5c, 0x00, 0x5C);
+       addToMapW(0x5c, 0x00, 0xA5);
+       addToMapW(0x5c, 0x22, 0x16);
+       addToMapW(0x5c, 0xFF, 0x3C);
+       addToMapW(0x5d, 0x00, 0x5D);
+       addToMapW(0x5d, 0x30, 0x1B);
+       addToMapW(0x5d, 0xFF, 0x3D);
+       addToMapW(0x5e, 0x00, 0x5E);
+       addToMapW(0x5e, 0x02, 0xC4);
+       addToMapW(0x5e, 0x02, 0xC6);
+       addToMapW(0x5e, 0x02, 0xC7);
+       addToMapW(0x5e, 0x02, 0xD8);
+       addToMapW(0x5e, 0x03, 0x02);
+       addToMapW(0x5e, 0x03, 0x06);
+       addToMapW(0x5e, 0x03, 0x0C);
+       addToMapW(0x5e, 0x23, 0x03);
+       addToMapW(0x5e, 0xFF, 0x3E);
+       addToMapW(0x5f, 0x00, 0x5F);
+       addToMapW(0x5f, 0x00, 0xAF);
+       addToMapW(0x5f, 0x00, 0xBE);
+       addToMapW(0x5f, 0x00, 0xDE);
+       addToMapW(0x5f, 0x00, 0xFE);
+       addToMapW(0x5f, 0x02, 0xCD);
+       addToMapW(0x5f, 0x03, 0x31);
+       addToMapW(0x5f, 0x03, 0x32);
+       addToMapW(0x5f, 0x20, 0x17);
+       addToMapW(0x5f, 0x30, 0xFC);
+       addToMapW(0x5f, 0xFF, 0x3F);
+       addToMapW(0x60, 0x00, 0x60);
+       addToMapW(0x60, 0x02, 0xCB);
+       addToMapW(0x60, 0x03, 0x00);
+       addToMapW(0x60, 0x20, 0x18);
+       addToMapW(0x60, 0x20, 0x35);
+       addToMapW(0x60, 0xFF, 0x40);
+       addToMapW(0x7b, 0x00, 0x7B);
+       addToMapW(0x7b, 0xFF, 0x5B);
+       addToMapW(0x7c, 0x00, 0x7C);
+       addToMapW(0x7c, 0x00, 0xA6);
+       addToMapW(0x7c, 0x01, 0xC0);
+       addToMapW(0x7c, 0x22, 0x23);
+       addToMapW(0x7c, 0x27, 0x58);
+       addToMapW(0x7c, 0xFF, 0x5C);
+       addToMapW(0x7d, 0x00, 0x7D);
+       addToMapW(0x7d, 0x30, 0x1B);
+       addToMapW(0x7d, 0xFF, 0x5D);
+       addToMapW(0x7e, 0x00, 0x7E);
+       addToMapW(0x7e, 0x02, 0xDC);
+       addToMapW(0x7e, 0x03, 0x03);
+       addToMapW(0x7e, 0x22, 0x3C);
+       addToMapW(0x7e, 0x22, 0x48);
+       addToMapW(0x7e, 0xFF, 0x5E);
+       addToMapW(0x7f, 0x00, 0x7F);
+       addToMapW(0x7f, 0x23, 0x02);
+       addToMapW(0x7f, 0x26, 0x60);
+       addToMapW(0x7f, 0x26, 0x63);
+       addToMapW(0x7f, 0x26, 0x65);
+       addToMapW(0x7f, 0x26, 0x66);
+       addToMapW(0x80, 0x00, 0x80);
+       addToMapW(0x80, 0x00, 0xC7);
+       addToMapW(0x80, 0x00, 0xE7);
+       addToMapW(0x80, 0x01, 0x06);
+       addToMapW(0x80, 0x01, 0x07);
+       addToMapW(0x80, 0x03, 0x91);
+       addToMapW(0x80, 0x03, 0xB1);
+       addToMapW(0x80, 0x04, 0x10);
+       addToMapW(0x80, 0x04, 0x30);
+       addToMapW(0x80, 0x05, 0xD0);
+       addToMapW(0x80, 0x20, 0xAC);
+       addToMapW(0x81, 0x00, 0x81);
+       addToMapW(0x81, 0x03, 0x92);
+       addToMapW(0x81, 0x03, 0xB2);
+       addToMapW(0x81, 0x04, 0x02);
+       addToMapW(0x81, 0x04, 0x11);
+       addToMapW(0x81, 0x04, 0x31);
+       addToMapW(0x81, 0x04, 0x52);
+       addToMapW(0x81, 0x05, 0xD1);
+       addToMapW(0x82, 0x00, 0x82);
+       addToMapW(0x82, 0x03, 0x93);
+       addToMapW(0x82, 0x03, 0xB3);
+       addToMapW(0x82, 0x04, 0x12);
+       addToMapW(0x82, 0x04, 0x32);
+       addToMapW(0x82, 0x05, 0xD2);
+       addToMapW(0x82, 0x20, 0x1A);
+       addToMapW(0x83, 0x00, 0x83);
+       addToMapW(0x83, 0x03, 0x94);
+       addToMapW(0x83, 0x03, 0xB4);
+       addToMapW(0x83, 0x04, 0x03);
+       addToMapW(0x83, 0x04, 0x13);
+       addToMapW(0x83, 0x04, 0x33);
+       addToMapW(0x83, 0x04, 0x53);
+       addToMapW(0x83, 0x05, 0xD3);
+       addToMapW(0x84, 0x00, 0x84);
+       addToMapW(0x84, 0x03, 0x95);
+       addToMapW(0x84, 0x03, 0xB5);
+       addToMapW(0x84, 0x04, 0x14);
+       addToMapW(0x84, 0x04, 0x34);
+       addToMapW(0x84, 0x05, 0xD4);
+       addToMapW(0x84, 0x20, 0x1E);
+       addToMapW(0x85, 0x03, 0x96);
+       addToMapW(0x85, 0x03, 0xB6);
+       addToMapW(0x85, 0x04, 0x01);
+       addToMapW(0x85, 0x04, 0x15);
+       addToMapW(0x85, 0x04, 0x35);
+       addToMapW(0x85, 0x04, 0x51);
+       addToMapW(0x85, 0x05, 0xD5);
+       addToMapW(0x85, 0x20, 0x26);
+       addToMapW(0x86, 0x00, 0x86);
+       addToMapW(0x86, 0x03, 0x97);
+       addToMapW(0x86, 0x03, 0xB7);
+       addToMapW(0x86, 0x04, 0x16);
+       addToMapW(0x86, 0x04, 0x36);
+       addToMapW(0x86, 0x05, 0xD6);
+       addToMapW(0x86, 0x20, 0x20);
+       addToMapW(0x87, 0x00, 0x87);
+       addToMapW(0x87, 0x03, 0x98);
+       addToMapW(0x87, 0x03, 0xB8);
+       addToMapW(0x87, 0x04, 0x04);
+       addToMapW(0x87, 0x04, 0x17);
+       addToMapW(0x87, 0x04, 0x37);
+       addToMapW(0x87, 0x04, 0x54);
+       addToMapW(0x87, 0x05, 0xD7);
+       addToMapW(0x87, 0x20, 0x21);
+       addToMapW(0x88, 0x00, 0x88);
+       addToMapW(0x88, 0x02, 0xC6);
+       addToMapW(0x88, 0x03, 0x99);
+       addToMapW(0x88, 0x03, 0xB9);
+       addToMapW(0x88, 0x04, 0x18);
+       addToMapW(0x88, 0x04, 0x38);
+       addToMapW(0x88, 0x05, 0xD8);
+       addToMapW(0x89, 0x00, 0x89);
+       addToMapW(0x89, 0x03, 0x9A);
+       addToMapW(0x89, 0x03, 0xBA);
+       addToMapW(0x89, 0x04, 0x05);
+       addToMapW(0x89, 0x04, 0x19);
+       addToMapW(0x89, 0x04, 0x39);
+       addToMapW(0x89, 0x04, 0x55);
+       addToMapW(0x89, 0x05, 0xD9);
+       addToMapW(0x89, 0x20, 0x30);
+       addToMapW(0x8a, 0x00, 0x8A);
+       addToMapW(0x8a, 0x01, 0x50);
+       addToMapW(0x8a, 0x01, 0x51);
+       addToMapW(0x8a, 0x01, 0x56);
+       addToMapW(0x8a, 0x01, 0x57);
+       addToMapW(0x8a, 0x03, 0x9B);
+       addToMapW(0x8a, 0x03, 0xBB);
+       addToMapW(0x8a, 0x04, 0x1A);
+       addToMapW(0x8a, 0x04, 0x3A);
+       addToMapW(0x8a, 0x05, 0xDA);
+       addToMapW(0x8b, 0x00, 0x8B);
+       addToMapW(0x8b, 0x03, 0x9C);
+       addToMapW(0x8b, 0x03, 0xBC);
+       addToMapW(0x8b, 0x04, 0x06);
+       addToMapW(0x8b, 0x04, 0x1B);
+       addToMapW(0x8b, 0x04, 0x3B);
+       addToMapW(0x8b, 0x04, 0x56);
+       addToMapW(0x8b, 0x05, 0xDB);
+       addToMapW(0x8b, 0x20, 0x39);
+       addToMapW(0x8c, 0x00, 0x8C);
+       addToMapW(0x8c, 0x01, 0x52);
+       addToMapW(0x8c, 0x01, 0x53);
+       addToMapW(0x8c, 0x03, 0x9D);
+       addToMapW(0x8c, 0x03, 0xBD);
+       addToMapW(0x8c, 0x04, 0x1C);
+       addToMapW(0x8c, 0x04, 0x3C);
+       addToMapW(0x8c, 0x05, 0xDC);
+       addToMapW(0x8d, 0x00, 0x8D);
+       addToMapW(0x8d, 0x01, 0x31);
+       addToMapW(0x8d, 0x01, 0x79);
+       addToMapW(0x8d, 0x01, 0x7A);
+       addToMapW(0x8d, 0x03, 0x9E);
+       addToMapW(0x8d, 0x03, 0xBE);
+       addToMapW(0x8d, 0x04, 0x07);
+       addToMapW(0x8d, 0x04, 0x1D);
+       addToMapW(0x8d, 0x04, 0x3D);
+       addToMapW(0x8d, 0x04, 0x57);
+       addToMapW(0x8d, 0x05, 0xDD);
+       addToMapW(0x8e, 0x00, 0x8E);
+       addToMapW(0x8e, 0x00, 0xC4);
+       addToMapW(0x8e, 0x00, 0xE4);
+       addToMapW(0x8e, 0x03, 0x9F);
+       addToMapW(0x8e, 0x03, 0xBF);
+       addToMapW(0x8e, 0x04, 0x1E);
+       addToMapW(0x8e, 0x04, 0x3E);
+       addToMapW(0x8e, 0x05, 0xDE);
+       addToMapW(0x8f, 0x00, 0x8F);
+       addToMapW(0x8f, 0x00, 0xC5);
+       addToMapW(0x8f, 0x00, 0xE5);
+       addToMapW(0x8f, 0x01, 0x06);
+       addToMapW(0x8f, 0x01, 0x07);
+       addToMapW(0x8f, 0x03, 0xA0);
+       addToMapW(0x8f, 0x03, 0xC0);
+       addToMapW(0x8f, 0x04, 0x08);
+       addToMapW(0x8f, 0x04, 0x1F);
+       addToMapW(0x8f, 0x04, 0x3F);
+       addToMapW(0x8f, 0x04, 0x58);
+       addToMapW(0x8f, 0x05, 0xDF);
+       addToMapW(0x8f, 0x21, 0x2B);
+       addToMapW(0x90, 0x00, 0x90);
+       addToMapW(0x90, 0x00, 0xC9);
+       addToMapW(0x90, 0x00, 0xE9);
+       addToMapW(0x90, 0x03, 0xA1);
+       addToMapW(0x90, 0x03, 0xC1);
+       addToMapW(0x90, 0x04, 0x20);
+       addToMapW(0x90, 0x04, 0x40);
+       addToMapW(0x90, 0x05, 0xE0);
+       addToMapW(0x91, 0x01, 0x39);
+       addToMapW(0x91, 0x01, 0x3A);
+       addToMapW(0x91, 0x03, 0xA3);
+       addToMapW(0x91, 0x03, 0xC2);
+       addToMapW(0x91, 0x03, 0xC3);
+       addToMapW(0x91, 0x04, 0x09);
+       addToMapW(0x91, 0x04, 0x21);
+       addToMapW(0x91, 0x04, 0x41);
+       addToMapW(0x91, 0x04, 0x59);
+       addToMapW(0x91, 0x05, 0xE1);
+       addToMapW(0x91, 0x06, 0x51);
+       addToMapW(0x91, 0x20, 0x18);
+       addToMapW(0x91, 0xFE, 0x7C);
+       addToMapW(0x91, 0xFE, 0x7D);
+       addToMapW(0x92, 0x00, 0xC6);
+       addToMapW(0x92, 0x00, 0xE6);
+       addToMapW(0x92, 0x03, 0xA4);
+       addToMapW(0x92, 0x03, 0xC4);
+       addToMapW(0x92, 0x04, 0x22);
+       addToMapW(0x92, 0x04, 0x42);
+       addToMapW(0x92, 0x05, 0xE2);
+       addToMapW(0x92, 0x06, 0x52);
+       addToMapW(0x92, 0x20, 0x19);
+       addToMapW(0x92, 0xFE, 0x7E);
+       addToMapW(0x92, 0xFE, 0x7F);
+       addToMapW(0x93, 0x03, 0xA5);
+       addToMapW(0x93, 0x03, 0xC5);
+       addToMapW(0x93, 0x04, 0x0A);
+       addToMapW(0x93, 0x04, 0x23);
+       addToMapW(0x93, 0x04, 0x43);
+       addToMapW(0x93, 0x04, 0x5A);
+       addToMapW(0x93, 0x05, 0xE3);
+       addToMapW(0x93, 0x20, 0x1C);
+       addToMapW(0x94, 0x00, 0xA4);
+       addToMapW(0x94, 0x03, 0xA6);
+       addToMapW(0x94, 0x03, 0xC6);
+       addToMapW(0x94, 0x04, 0x24);
+       addToMapW(0x94, 0x04, 0x44);
+       addToMapW(0x94, 0x05, 0xE4);
+       addToMapW(0x94, 0x20, 0x1D);
+       addToMapW(0x95, 0x01, 0x22);
+       addToMapW(0x95, 0x01, 0x23);
+       addToMapW(0x95, 0x01, 0x3D);
+       addToMapW(0x95, 0x01, 0x3E);
+       addToMapW(0x95, 0x03, 0xA7);
+       addToMapW(0x95, 0x03, 0xC7);
+       addToMapW(0x95, 0x04, 0x0B);
+       addToMapW(0x95, 0x04, 0x25);
+       addToMapW(0x95, 0x04, 0x45);
+       addToMapW(0x95, 0x04, 0x5B);
+       addToMapW(0x95, 0x05, 0xE5);
+       addToMapW(0x95, 0x06, 0x40);
+       addToMapW(0x95, 0x20, 0x22);
+       addToMapW(0x96, 0x00, 0xA2);
+       addToMapW(0x96, 0x03, 0xA8);
+       addToMapW(0x96, 0x03, 0xC8);
+       addToMapW(0x96, 0x04, 0x26);
+       addToMapW(0x96, 0x04, 0x46);
+       addToMapW(0x96, 0x05, 0xE6);
+       addToMapW(0x96, 0x20, 0x13);
+       addToMapW(0x97, 0x00, 0xB5);
+       addToMapW(0x97, 0x01, 0x5A);
+       addToMapW(0x97, 0x01, 0x5B);
+       addToMapW(0x97, 0x03, 0xA9);
+       addToMapW(0x97, 0x03, 0xC9);
+       addToMapW(0x97, 0x04, 0x0C);
+       addToMapW(0x97, 0x04, 0x27);
+       addToMapW(0x97, 0x04, 0x47);
+       addToMapW(0x97, 0x04, 0x5C);
+       addToMapW(0x97, 0x05, 0xE7);
+       addToMapW(0x97, 0x20, 0x14);
+       addToMapW(0x98, 0x00, 0x98);
+       addToMapW(0x98, 0x01, 0x30);
+       addToMapW(0x98, 0x02, 0xDC);
+       addToMapW(0x98, 0x04, 0x28);
+       addToMapW(0x98, 0x04, 0x48);
+       addToMapW(0x98, 0x05, 0xE8);
+       addToMapW(0x98, 0x06, 0x21);
+       addToMapW(0x98, 0xFE, 0x80);
+       addToMapW(0x99, 0x00, 0x99);
+       addToMapW(0x99, 0x00, 0xD6);
+       addToMapW(0x99, 0x00, 0xF6);
+       addToMapW(0x99, 0x04, 0x0E);
+       addToMapW(0x99, 0x04, 0x29);
+       addToMapW(0x99, 0x04, 0x49);
+       addToMapW(0x99, 0x04, 0x5E);
+       addToMapW(0x99, 0x05, 0xE9);
+       addToMapW(0x99, 0x06, 0x22);
+       addToMapW(0x99, 0x21, 0x22);
+       addToMapW(0x99, 0xFE, 0x81);
+       addToMapW(0x99, 0xFE, 0x82);
+       addToMapW(0x9a, 0x00, 0x9A);
+       addToMapW(0x9a, 0x00, 0xDC);
+       addToMapW(0x9a, 0x00, 0xFC);
+       addToMapW(0x9a, 0x04, 0x2A);
+       addToMapW(0x9a, 0x04, 0x4A);
+       addToMapW(0x9a, 0x05, 0xEA);
+       addToMapW(0x9a, 0x06, 0x23);
+       addToMapW(0x9a, 0xFE, 0x83);
+       addToMapW(0x9a, 0xFE, 0x84);
+       addToMapW(0x9b, 0x00, 0x9B);
+       addToMapW(0x9b, 0x00, 0xA2);
+       addToMapW(0x9b, 0x01, 0x64);
+       addToMapW(0x9b, 0x01, 0x65);
+       addToMapW(0x9b, 0x04, 0x0F);
+       addToMapW(0x9b, 0x04, 0x2B);
+       addToMapW(0x9b, 0x04, 0x4B);
+       addToMapW(0x9b, 0x04, 0x5F);
+       addToMapW(0x9b, 0x06, 0x24);
+       addToMapW(0x9b, 0x20, 0x3A);
+       addToMapW(0x9b, 0xFE, 0x85);
+       addToMapW(0x9b, 0xFE, 0x86);
+       addToMapW(0x9c, 0x00, 0x9C);
+       addToMapW(0x9c, 0x00, 0xA3);
+       addToMapW(0x9c, 0x04, 0x2C);
+       addToMapW(0x9c, 0x04, 0x4C);
+       addToMapW(0x9c, 0x20, 0xA4);
+       addToMapW(0x9d, 0x00, 0x9D);
+       addToMapW(0x9d, 0x00, 0xA5);
+       addToMapW(0x9d, 0x00, 0xD8);
+       addToMapW(0x9d, 0x00, 0xF8);
+       addToMapW(0x9d, 0x01, 0x41);
+       addToMapW(0x9d, 0x01, 0x42);
+       addToMapW(0x9d, 0x02, 0x78);
+       addToMapW(0x9d, 0x03, 0x98);
+       addToMapW(0x9d, 0x04, 0x2D);
+       addToMapW(0x9d, 0x04, 0x2E);
+       addToMapW(0x9d, 0x04, 0x4D);
+       addToMapW(0x9d, 0x04, 0x4E);
+       addToMapW(0x9d, 0x06, 0x25);
+       addToMapW(0x9d, 0x22, 0x05);
+       addToMapW(0x9d, 0xFE, 0x87);
+       addToMapW(0x9d, 0xFE, 0x88);
+       addToMapW(0x9e, 0x00, 0x9E);
+       addToMapW(0x9e, 0x00, 0xD7);
+       addToMapW(0x9e, 0x01, 0x5E);
+       addToMapW(0x9e, 0x01, 0x5F);
+       addToMapW(0x9e, 0x04, 0x2E);
+       addToMapW(0x9e, 0x04, 0x4E);
+       addToMapW(0x9e, 0x06, 0x26);
+       addToMapW(0x9e, 0x20, 0xA7);
+       addToMapW(0x9e, 0xFE, 0x89);
+       addToMapW(0x9e, 0xFE, 0x8A);
+       addToMapW(0x9e, 0xFE, 0x8B);
+       addToMapW(0x9e, 0xFE, 0x8C);
+       addToMapW(0x9f, 0x00, 0x9F);
+       addToMapW(0x9f, 0x00, 0xA4);
+       addToMapW(0x9f, 0x00, 0xFF);
+       addToMapW(0x9f, 0x01, 0x78);
+       addToMapW(0x9f, 0x01, 0x91);
+       addToMapW(0x9f, 0x01, 0x92);
+       addToMapW(0x9f, 0x04, 0x2A);
+       addToMapW(0x9f, 0x04, 0x2F);
+       addToMapW(0x9f, 0x04, 0x4A);
+       addToMapW(0x9f, 0x04, 0x4F);
+       addToMapW(0x9f, 0x06, 0x27);
+       addToMapW(0x9f, 0xFE, 0x8D);
+       addToMapW(0x9f, 0xFE, 0x8E);
+       addToMapW(0xa0, 0x00, 0xA0);
+       addToMapW(0xa0, 0x01, 0x00);
+       addToMapW(0xa0, 0x01, 0x01);
+       addToMapW(0xa0, 0x06, 0x28);
+       addToMapW(0xa0, 0xF8, 0xF0);
+       addToMapW(0xa0, 0xFE, 0x8F);
+       addToMapW(0xa0, 0xFE, 0x90);
+       addToMapW(0xa0, 0xFE, 0x91);
+       addToMapW(0xa0, 0xFE, 0x92);
+       addToMapW(0xa1, 0x00, 0xA1);
+       addToMapW(0xa1, 0x01, 0x2A);
+       addToMapW(0xa1, 0x01, 0x2B);
+       addToMapW(0xa1, 0x04, 0x10);
+       addToMapW(0xa1, 0x04, 0x30);
+       addToMapW(0xa1, 0x06, 0x29);
+       addToMapW(0xa1, 0x0E, 0x01);
+       addToMapW(0xa1, 0xFE, 0x93);
+       addToMapW(0xa1, 0xFE, 0x94);
+       addToMapW(0xa1, 0xFF, 0x61);
+       addToMapW(0xa2, 0x00, 0xA2);
+       addToMapW(0xa2, 0x06, 0x2A);
+       addToMapW(0xa2, 0x0E, 0x02);
+       addToMapW(0xa2, 0xFE, 0x95);
+       addToMapW(0xa2, 0xFE, 0x96);
+       addToMapW(0xa2, 0xFE, 0x97);
+       addToMapW(0xa2, 0xFE, 0x98);
+       addToMapW(0xa2, 0xFF, 0x62);
+       addToMapW(0xa3, 0x00, 0xA3);
+       addToMapW(0xa3, 0x01, 0x7B);
+       addToMapW(0xa3, 0x01, 0x7C);
+       addToMapW(0xa3, 0x04, 0x11);
+       addToMapW(0xa3, 0x04, 0x31);
+       addToMapW(0xa3, 0x06, 0x2B);
+       addToMapW(0xa3, 0x0E, 0x03);
+       addToMapW(0xa3, 0xFE, 0x99);
+       addToMapW(0xa3, 0xFE, 0x9A);
+       addToMapW(0xa3, 0xFE, 0x9B);
+       addToMapW(0xa3, 0xFE, 0x9C);
+       addToMapW(0xa3, 0xFF, 0x63);
+       addToMapW(0xa4, 0x00, 0xA4);
+       addToMapW(0xa4, 0x01, 0x04);
+       addToMapW(0xa4, 0x01, 0x05);
+       addToMapW(0xa4, 0x06, 0x2C);
+       addToMapW(0xa4, 0x0E, 0x04);
+       addToMapW(0xa4, 0xFE, 0x9D);
+       addToMapW(0xa4, 0xFE, 0x9E);
+       addToMapW(0xa4, 0xFE, 0x9F);
+       addToMapW(0xa4, 0xFE, 0xA0);
+       addToMapW(0xa4, 0xFF, 0x64);
+       addToMapW(0xa5, 0x00, 0xA5);
+       addToMapW(0xa5, 0x00, 0xD1);
+       addToMapW(0xa5, 0x00, 0xF1);
+       addToMapW(0xa5, 0x04, 0x26);
+       addToMapW(0xa5, 0x04, 0x46);
+       addToMapW(0xa5, 0x06, 0x2D);
+       addToMapW(0xa5, 0x0E, 0x05);
+       addToMapW(0xa5, 0xFE, 0xA1);
+       addToMapW(0xa5, 0xFE, 0xA2);
+       addToMapW(0xa5, 0xFE, 0xA3);
+       addToMapW(0xa5, 0xFE, 0xA4);
+       addToMapW(0xa5, 0xFF, 0x65);
+       addToMapW(0xa6, 0x00, 0xA6);
+       addToMapW(0xa6, 0x00, 0xAA);
+       addToMapW(0xa6, 0x01, 0x1E);
+       addToMapW(0xa6, 0x01, 0x1F);
+       addToMapW(0xa6, 0x01, 0x7D);
+       addToMapW(0xa6, 0x01, 0x7E);
+       addToMapW(0xa6, 0x06, 0x2E);
+       addToMapW(0xa6, 0x0E, 0x06);
+       addToMapW(0xa6, 0x20, 0x1D);
+       addToMapW(0xa6, 0xFE, 0xA5);
+       addToMapW(0xa6, 0xFE, 0xA6);
+       addToMapW(0xa6, 0xFE, 0xA7);
+       addToMapW(0xa6, 0xFE, 0xA8);
+       addToMapW(0xa6, 0xFF, 0x66);
+       addToMapW(0xa7, 0x00, 0xA6);
+       addToMapW(0xa7, 0x00, 0xA7);
+       addToMapW(0xa7, 0x00, 0xBA);
+       addToMapW(0xa7, 0x04, 0x14);
+       addToMapW(0xa7, 0x04, 0x34);
+       addToMapW(0xa7, 0x06, 0x2F);
+       addToMapW(0xa7, 0x0E, 0x07);
+       addToMapW(0xa7, 0xFE, 0xA9);
+       addToMapW(0xa7, 0xFE, 0xAA);
+       addToMapW(0xa7, 0xFF, 0x67);
+       addToMapW(0xa8, 0x00, 0xA8);
+       addToMapW(0xa8, 0x00, 0xA9);
+       addToMapW(0xa8, 0x00, 0xBF);
+       addToMapW(0xa8, 0x01, 0x18);
+       addToMapW(0xa8, 0x01, 0x19);
+       addToMapW(0xa8, 0x06, 0x30);
+       addToMapW(0xa8, 0x0E, 0x08);
+       addToMapW(0xa8, 0xFE, 0xAB);
+       addToMapW(0xa8, 0xFE, 0xAC);
+       addToMapW(0xa8, 0xFF, 0x68);
+       addToMapW(0xa9, 0x00, 0xA9);
+       addToMapW(0xa9, 0x00, 0xAE);
+       addToMapW(0xa9, 0x04, 0x15);
+       addToMapW(0xa9, 0x04, 0x35);
+       addToMapW(0xa9, 0x06, 0x31);
+       addToMapW(0xa9, 0x0E, 0x09);
+       addToMapW(0xa9, 0x23, 0x10);
+       addToMapW(0xa9, 0xFE, 0xAD);
+       addToMapW(0xa9, 0xFE, 0xAE);
+       addToMapW(0xa9, 0xFF, 0x69);
+       addToMapW(0xaa, 0x00, 0xAA);
+       addToMapW(0xaa, 0x00, 0xAC);
+       addToMapW(0xaa, 0x06, 0x32);
+       addToMapW(0xaa, 0x0E, 0x0A);
+       addToMapW(0xaa, 0x23, 0x10);
+       addToMapW(0xaa, 0xFE, 0xAF);
+       addToMapW(0xaa, 0xFE, 0xB0);
+       addToMapW(0xaa, 0xFF, 0x6A);
+       addToMapW(0xab, 0x00, 0xAB);
+       addToMapW(0xab, 0x00, 0xBD);
+       addToMapW(0xab, 0x04, 0x24);
+       addToMapW(0xab, 0x04, 0x44);
+       addToMapW(0xab, 0x06, 0x33);
+       addToMapW(0xab, 0x0E, 0x0B);
+       addToMapW(0xab, 0xFE, 0xB1);
+       addToMapW(0xab, 0xFE, 0xB2);
+       addToMapW(0xab, 0xFE, 0xB3);
+       addToMapW(0xab, 0xFE, 0xB4);
+       addToMapW(0xab, 0xFF, 0x6B);
+       addToMapW(0xac, 0x00, 0xAC);
+       addToMapW(0xac, 0x00, 0xBC);
+       addToMapW(0xac, 0x01, 0x0C);
+       addToMapW(0xac, 0x01, 0x0D);
+       addToMapW(0xac, 0x06, 0x34);
+       addToMapW(0xac, 0x0E, 0x0C);
+       addToMapW(0xac, 0xFE, 0xB5);
+       addToMapW(0xac, 0xFE, 0xB6);
+       addToMapW(0xac, 0xFE, 0xB7);
+       addToMapW(0xac, 0xFE, 0xB8);
+       addToMapW(0xac, 0xFF, 0x6C);
+       addToMapW(0xad, 0x00, 0xA1);
+       addToMapW(0xad, 0x00, 0xAD);
+       addToMapW(0xad, 0x01, 0x41);
+       addToMapW(0xad, 0x01, 0x42);
+       addToMapW(0xad, 0x04, 0x13);
+       addToMapW(0xad, 0x04, 0x33);
+       addToMapW(0xad, 0x06, 0x35);
+       addToMapW(0xad, 0x0E, 0x0D);
+       addToMapW(0xad, 0xFE, 0xB9);
+       addToMapW(0xad, 0xFE, 0xBA);
+       addToMapW(0xad, 0xFE, 0xBB);
+       addToMapW(0xad, 0xFE, 0xBC);
+       addToMapW(0xad, 0xFF, 0x6D);
+       addToMapW(0xae, 0x00, 0xAB);
+       addToMapW(0xae, 0x00, 0xAE);
+       addToMapW(0xae, 0x0E, 0x0E);
+       addToMapW(0xae, 0x22, 0x6A);
+       addToMapW(0xae, 0x30, 0x0A);
+       addToMapW(0xae, 0xFF, 0x6E);
+       addToMapW(0xaf, 0x00, 0xAF);
+       addToMapW(0xaf, 0x00, 0xBB);
+       addToMapW(0xaf, 0x0E, 0x0F);
+       addToMapW(0xaf, 0x22, 0x6B);
+       addToMapW(0xaf, 0x30, 0x0B);
+       addToMapW(0xaf, 0xFF, 0x6F);
+       addToMapW(0xb0, 0x00, 0xB0);
+       addToMapW(0xb0, 0x0E, 0x10);
+       addToMapW(0xb0, 0x25, 0x91);
+       addToMapW(0xb0, 0xFF, 0x70);
+       addToMapW(0xb1, 0x00, 0xB1);
+       addToMapW(0xb1, 0x0E, 0x11);
+       addToMapW(0xb1, 0x25, 0x92);
+       addToMapW(0xb1, 0xFF, 0x71);
+       addToMapW(0xb2, 0x00, 0xB2);
+       addToMapW(0xb2, 0x0E, 0x12);
+       addToMapW(0xb2, 0x25, 0x93);
+       addToMapW(0xb2, 0xFF, 0x72);
+       addToMapW(0xb3, 0x00, 0xA6);
+       addToMapW(0xb3, 0x00, 0xB3);
+       addToMapW(0xb3, 0x01, 0xC0);
+       addToMapW(0xb3, 0x0E, 0x13);
+       addToMapW(0xb3, 0x22, 0x23);
+       addToMapW(0xb3, 0x25, 0x02);
+       addToMapW(0xb3, 0x27, 0x58);
+       addToMapW(0xb3, 0xFF, 0x73);
+       addToMapW(0xb4, 0x00, 0xB4);
+       addToMapW(0xb4, 0x0E, 0x14);
+       addToMapW(0xb4, 0x25, 0x24);
+       addToMapW(0xb4, 0xFF, 0x74);
+       addToMapW(0xb5, 0x00, 0xB5);
+       addToMapW(0xb5, 0x00, 0xC1);
+       addToMapW(0xb5, 0x00, 0xE1);
+       addToMapW(0xb5, 0x01, 0x04);
+       addToMapW(0xb5, 0x01, 0x05);
+       addToMapW(0xb5, 0x0E, 0x15);
+       addToMapW(0xb5, 0x25, 0x61);
+       addToMapW(0xb5, 0xFF, 0x75);
+       addToMapW(0xb6, 0x00, 0xB6);
+       addToMapW(0xb6, 0x00, 0xC2);
+       addToMapW(0xb6, 0x00, 0xE2);
+       addToMapW(0xb6, 0x01, 0x0C);
+       addToMapW(0xb6, 0x01, 0x0D);
+       addToMapW(0xb6, 0x04, 0x25);
+       addToMapW(0xb6, 0x04, 0x45);
+       addToMapW(0xb6, 0x0E, 0x16);
+       addToMapW(0xb6, 0x25, 0x62);
+       addToMapW(0xb6, 0xFF, 0x76);
+       addToMapW(0xb7, 0x00, 0xB7);
+       addToMapW(0xb7, 0x00, 0xC0);
+       addToMapW(0xb7, 0x00, 0xE0);
+       addToMapW(0xb7, 0x01, 0x18);
+       addToMapW(0xb7, 0x01, 0x19);
+       addToMapW(0xb7, 0x01, 0x1A);
+       addToMapW(0xb7, 0x01, 0x1B);
+       addToMapW(0xb7, 0x0E, 0x17);
+       addToMapW(0xb7, 0x25, 0x56);
+       addToMapW(0xb7, 0xFF, 0x77);
+       addToMapW(0xb8, 0x00, 0xA9);
+       addToMapW(0xb8, 0x00, 0xB8);
+       addToMapW(0xb8, 0x01, 0x16);
+       addToMapW(0xb8, 0x01, 0x17);
+       addToMapW(0xb8, 0x01, 0x5E);
+       addToMapW(0xb8, 0x01, 0x5F);
+       addToMapW(0xb8, 0x04, 0x18);
+       addToMapW(0xb8, 0x04, 0x38);
+       addToMapW(0xb8, 0x0E, 0x18);
+       addToMapW(0xb8, 0x25, 0x55);
+       addToMapW(0xb8, 0xFF, 0x78);
+       addToMapW(0xb9, 0x00, 0xB9);
+       addToMapW(0xb9, 0x0E, 0x19);
+       addToMapW(0xb9, 0x25, 0x61);
+       addToMapW(0xb9, 0x25, 0x62);
+       addToMapW(0xb9, 0x25, 0x63);
+       addToMapW(0xb9, 0xFF, 0x79);
+       addToMapW(0xba, 0x00, 0xBA);
+       addToMapW(0xba, 0x0E, 0x1A);
+       addToMapW(0xba, 0x25, 0x51);
+       addToMapW(0xba, 0xFF, 0x7A);
+       addToMapW(0xbb, 0x00, 0xBB);
+       addToMapW(0xbb, 0x0E, 0x1B);
+       addToMapW(0xbb, 0x25, 0x55);
+       addToMapW(0xbb, 0x25, 0x56);
+       addToMapW(0xbb, 0x25, 0x57);
+       addToMapW(0xbb, 0xFF, 0x7B);
+       addToMapW(0xbc, 0x00, 0xBC);
+       addToMapW(0xbc, 0x0E, 0x1C);
+       addToMapW(0xbc, 0x25, 0x5B);
+       addToMapW(0xbc, 0x25, 0x5C);
+       addToMapW(0xbc, 0x25, 0x5D);
+       addToMapW(0xbc, 0xFF, 0x7C);
+       addToMapW(0xbd, 0x00, 0xA2);
+       addToMapW(0xbd, 0x00, 0xBD);
+       addToMapW(0xbd, 0x01, 0x2E);
+       addToMapW(0xbd, 0x01, 0x2F);
+       addToMapW(0xbd, 0x01, 0x7B);
+       addToMapW(0xbd, 0x01, 0x7C);
+       addToMapW(0xbd, 0x0E, 0x1D);
+       addToMapW(0xbd, 0x25, 0x5C);
+       addToMapW(0xbd, 0xFF, 0x7D);
+       addToMapW(0xbe, 0x00, 0xA5);
+       addToMapW(0xbe, 0x00, 0xBE);
+       addToMapW(0xbe, 0x01, 0x60);
+       addToMapW(0xbe, 0x01, 0x61);
+       addToMapW(0xbe, 0x04, 0x19);
+       addToMapW(0xbe, 0x04, 0x39);
+       addToMapW(0xbe, 0x0E, 0x1E);
+       addToMapW(0xbe, 0x25, 0x5B);
+       addToMapW(0xbe, 0xFF, 0x7E);
+       addToMapW(0xbf, 0x00, 0xAC);
+       addToMapW(0xbf, 0x00, 0xBF);
+       addToMapW(0xbf, 0x0E, 0x1F);
+       addToMapW(0xbf, 0x25, 0x10);
+       addToMapW(0xbf, 0xFF, 0x7F);
+       addToMapW(0xc0, 0x00, 0xC0);
+       addToMapW(0xc0, 0x00, 0xE0);
+       addToMapW(0xc0, 0x0E, 0x20);
+       addToMapW(0xc0, 0x25, 0x14);
+       addToMapW(0xc0, 0xFF, 0x80);
+       addToMapW(0xc1, 0x00, 0xC1);
+       addToMapW(0xc1, 0x00, 0xE1);
+       addToMapW(0xc1, 0x0E, 0x21);
+       addToMapW(0xc1, 0x25, 0x34);
+       addToMapW(0xc1, 0xFF, 0x81);
+       addToMapW(0xc2, 0x00, 0xC2);
+       addToMapW(0xc2, 0x00, 0xE2);
+       addToMapW(0xc2, 0x0E, 0x22);
+       addToMapW(0xc2, 0x25, 0x2C);
+       addToMapW(0xc2, 0xFF, 0x82);
+       addToMapW(0xc3, 0x01, 0x02);
+       addToMapW(0xc3, 0x01, 0x03);
+       addToMapW(0xc3, 0x0E, 0x23);
+       addToMapW(0xc3, 0x25, 0x1C);
+       addToMapW(0xc3, 0xFF, 0x83);
+       addToMapW(0xc4, 0x00, 0xAF);
+       addToMapW(0xc4, 0x00, 0xC4);
+       addToMapW(0xc4, 0x00, 0xE4);
+       addToMapW(0xc4, 0x02, 0xC9);
+       addToMapW(0xc4, 0x03, 0x04);
+       addToMapW(0xc4, 0x03, 0x05);
+       addToMapW(0xc4, 0x0E, 0x24);
+       addToMapW(0xc4, 0x25, 0x00);
+       addToMapW(0xc4, 0xFF, 0x84);
+       addToMapW(0xc5, 0x00, 0xC5);
+       addToMapW(0xc5, 0x00, 0xE5);
+       addToMapW(0xc5, 0x0E, 0x25);
+       addToMapW(0xc5, 0x20, 0x20);
+       addToMapW(0xc5, 0x20, 0x21);
+       addToMapW(0xc5, 0x25, 0x3C);
+       addToMapW(0xc5, 0xFF, 0x85);
+       addToMapW(0xc6, 0x00, 0xC6);
+       addToMapW(0xc6, 0x00, 0xE6);
+       addToMapW(0xc6, 0x01, 0x02);
+       addToMapW(0xc6, 0x01, 0x03);
+       addToMapW(0xc6, 0x01, 0x72);
+       addToMapW(0xc6, 0x01, 0x73);
+       addToMapW(0xc6, 0x0E, 0x26);
+       addToMapW(0xc6, 0x25, 0x5E);
+       addToMapW(0xc6, 0xFF, 0x86);
+       addToMapW(0xc7, 0x00, 0xC3);
+       addToMapW(0xc7, 0x00, 0xC7);
+       addToMapW(0xc7, 0x00, 0xE3);
+       addToMapW(0xc7, 0x00, 0xE7);
+       addToMapW(0xc7, 0x01, 0x6A);
+       addToMapW(0xc7, 0x01, 0x6B);
+       addToMapW(0xc7, 0x04, 0x1A);
+       addToMapW(0xc7, 0x04, 0x3A);
+       addToMapW(0xc7, 0x0E, 0x27);
+       addToMapW(0xc7, 0x25, 0x5F);
+       addToMapW(0xc7, 0xFF, 0x87);
+       addToMapW(0xc8, 0x00, 0xC8);
+       addToMapW(0xc8, 0x00, 0xE8);
+       addToMapW(0xc8, 0x0E, 0x28);
+       addToMapW(0xc8, 0x25, 0x58);
+       addToMapW(0xc8, 0x25, 0x59);
+       addToMapW(0xc8, 0x25, 0x5A);
+       addToMapW(0xc8, 0xFF, 0x88);
+       addToMapW(0xc9, 0x00, 0xC9);
+       addToMapW(0xc9, 0x00, 0xE9);
+       addToMapW(0xc9, 0x0E, 0x29);
+       addToMapW(0xc9, 0x25, 0x52);
+       addToMapW(0xc9, 0x25, 0x53);
+       addToMapW(0xc9, 0x25, 0x54);
+       addToMapW(0xc9, 0xFF, 0x89);
+       addToMapW(0xca, 0x00, 0xCA);
+       addToMapW(0xca, 0x00, 0xEA);
+       addToMapW(0xca, 0x0E, 0x2A);
+       addToMapW(0xca, 0x25, 0x67);
+       addToMapW(0xca, 0x25, 0x68);
+       addToMapW(0xca, 0x25, 0x69);
+       addToMapW(0xca, 0xFF, 0x8A);
+       addToMapW(0xcb, 0x00, 0xCB);
+       addToMapW(0xcb, 0x00, 0xEB);
+       addToMapW(0xcb, 0x0E, 0x2B);
+       addToMapW(0xcb, 0x25, 0x64);
+       addToMapW(0xcb, 0x25, 0x65);
+       addToMapW(0xcb, 0x25, 0x66);
+       addToMapW(0xcb, 0xFF, 0x8B);
+       addToMapW(0xcc, 0x03, 0x00);
+       addToMapW(0xcc, 0x0E, 0x2C);
+       addToMapW(0xcc, 0x25, 0x5E);
+       addToMapW(0xcc, 0x25, 0x5F);
+       addToMapW(0xcc, 0x25, 0x60);
+       addToMapW(0xcc, 0xFF, 0x8C);
+       addToMapW(0xcd, 0x00, 0xCD);
+       addToMapW(0xcd, 0x00, 0xED);
+       addToMapW(0xcd, 0x0E, 0x2D);
+       addToMapW(0xcd, 0x25, 0x50);
+       addToMapW(0xcd, 0xFF, 0x8D);
+       addToMapW(0xce, 0x00, 0xCE);
+       addToMapW(0xce, 0x00, 0xEE);
+       addToMapW(0xce, 0x0E, 0x2E);
+       addToMapW(0xce, 0x20, 0x21);
+       addToMapW(0xce, 0x25, 0x6A);
+       addToMapW(0xce, 0x25, 0x6B);
+       addToMapW(0xce, 0x25, 0x6C);
+       addToMapW(0xce, 0xFF, 0x8E);
+       addToMapW(0xcf, 0x00, 0xA4);
+       addToMapW(0xcf, 0x00, 0xCF);
+       addToMapW(0xcf, 0x00, 0xEF);
+       addToMapW(0xcf, 0x01, 0x7D);
+       addToMapW(0xcf, 0x01, 0x7E);
+       addToMapW(0xcf, 0x0E, 0x2F);
+       addToMapW(0xcf, 0x25, 0x67);
+       addToMapW(0xcf, 0xFF, 0x8F);
+       addToMapW(0xd0, 0x00, 0xBA);
+       addToMapW(0xd0, 0x01, 0x10);
+       addToMapW(0xd0, 0x01, 0x11);
+       addToMapW(0xd0, 0x0E, 0x30);
+       addToMapW(0xd0, 0x25, 0x68);
+       addToMapW(0xd0, 0xFF, 0x90);
+       addToMapW(0xd1, 0x00, 0xAA);
+       addToMapW(0xd1, 0x00, 0xD0);
+       addToMapW(0xd1, 0x00, 0xD1);
+       addToMapW(0xd1, 0x00, 0xF0);
+       addToMapW(0xd1, 0x00, 0xF1);
+       addToMapW(0xd1, 0x01, 0x10);
+       addToMapW(0xd1, 0x01, 0x11);
+       addToMapW(0xd1, 0x01, 0x89);
+       addToMapW(0xd1, 0x04, 0x1B);
+       addToMapW(0xd1, 0x04, 0x3B);
+       addToMapW(0xd1, 0x0E, 0x31);
+       addToMapW(0xd1, 0x25, 0x64);
+       addToMapW(0xd1, 0xFF, 0x91);
+       addToMapW(0xd2, 0x00, 0xCA);
+       addToMapW(0xd2, 0x00, 0xEA);
+       addToMapW(0xd2, 0x01, 0x0E);
+       addToMapW(0xd2, 0x01, 0x0F);
+       addToMapW(0xd2, 0x03, 0x09);
+       addToMapW(0xd2, 0x0E, 0x32);
+       addToMapW(0xd2, 0x25, 0x65);
+       addToMapW(0xd2, 0xFF, 0x92);
+       addToMapW(0xd3, 0x00, 0xCB);
+       addToMapW(0xd3, 0x00, 0xD3);
+       addToMapW(0xd3, 0x00, 0xEB);
+       addToMapW(0xd3, 0x00, 0xF3);
+       addToMapW(0xd3, 0x04, 0x1C);
+       addToMapW(0xd3, 0x04, 0x3C);
+       addToMapW(0xd3, 0x0E, 0x33);
+       addToMapW(0xd3, 0x25, 0x59);
+       addToMapW(0xd3, 0xFF, 0x93);
+       addToMapW(0xd4, 0x00, 0xC8);
+       addToMapW(0xd4, 0x00, 0xD4);
+       addToMapW(0xd4, 0x00, 0xE8);
+       addToMapW(0xd4, 0x00, 0xF4);
+       addToMapW(0xd4, 0x0E, 0x34);
+       addToMapW(0xd4, 0x25, 0x58);
+       addToMapW(0xd4, 0xFF, 0x94);
+       addToMapW(0xd5, 0x01, 0x31);
+       addToMapW(0xd5, 0x01, 0x47);
+       addToMapW(0xd5, 0x01, 0x48);
+       addToMapW(0xd5, 0x01, 0xA0);
+       addToMapW(0xd5, 0x01, 0xA1);
+       addToMapW(0xd5, 0x04, 0x1D);
+       addToMapW(0xd5, 0x04, 0x3D);
+       addToMapW(0xd5, 0x0E, 0x35);
+       addToMapW(0xd5, 0x25, 0x52);
+       addToMapW(0xd5, 0xF8, 0xBB);
+       addToMapW(0xd5, 0xFF, 0x95);
+       addToMapW(0xd6, 0x00, 0xCD);
+       addToMapW(0xd6, 0x00, 0xD6);
+       addToMapW(0xd6, 0x00, 0xED);
+       addToMapW(0xd6, 0x00, 0xF6);
+       addToMapW(0xd6, 0x0E, 0x36);
+       addToMapW(0xd6, 0x25, 0x53);
+       addToMapW(0xd6, 0xFF, 0x96);
+       addToMapW(0xd7, 0x00, 0xCE);
+       addToMapW(0xd7, 0x00, 0xD7);
+       addToMapW(0xd7, 0x00, 0xEE);
+       addToMapW(0xd7, 0x04, 0x1E);
+       addToMapW(0xd7, 0x04, 0x3E);
+       addToMapW(0xd7, 0x0E, 0x37);
+       addToMapW(0xd7, 0x25, 0x6B);
+       addToMapW(0xd7, 0xFF, 0x97);
+       addToMapW(0xd8, 0x00, 0xCF);
+       addToMapW(0xd8, 0x00, 0xD8);
+       addToMapW(0xd8, 0x00, 0xEF);
+       addToMapW(0xd8, 0x00, 0xF8);
+       addToMapW(0xd8, 0x0E, 0x38);
+       addToMapW(0xd8, 0x20, 0x21);
+       addToMapW(0xd8, 0x25, 0x6A);
+       addToMapW(0xd8, 0xFF, 0x98);
+       addToMapW(0xd9, 0x00, 0xD9);
+       addToMapW(0xd9, 0x00, 0xF9);
+       addToMapW(0xd9, 0x0E, 0x39);
+       addToMapW(0xd9, 0x25, 0x18);
+       addToMapW(0xd9, 0xFF, 0x99);
+       addToMapW(0xda, 0x00, 0xDA);
+       addToMapW(0xda, 0x00, 0xFA);
+       addToMapW(0xda, 0x0E, 0x3A);
+       addToMapW(0xda, 0x25, 0x0C);
+       addToMapW(0xda, 0xFF, 0x9A);
+       addToMapW(0xdb, 0x00, 0xDB);
+       addToMapW(0xdb, 0x00, 0xFB);
+       addToMapW(0xdb, 0x25, 0x88);
+       addToMapW(0xdb, 0x25, 0x8C);
+       addToMapW(0xdb, 0x25, 0x90);
+       addToMapW(0xdb, 0xF8, 0xC1);
+       addToMapW(0xdb, 0xFF, 0x9B);
+       addToMapW(0xdc, 0x00, 0xDC);
+       addToMapW(0xdc, 0x00, 0xFC);
+       addToMapW(0xdc, 0x25, 0x84);
+       addToMapW(0xdc, 0xF8, 0xC2);
+       addToMapW(0xdc, 0xFF, 0x9C);
+       addToMapW(0xdd, 0x00, 0xA6);
+       addToMapW(0xdd, 0x01, 0x62);
+       addToMapW(0xdd, 0x01, 0x63);
+       addToMapW(0xdd, 0x01, 0xAF);
+       addToMapW(0xdd, 0x01, 0xB0);
+       addToMapW(0xdd, 0x04, 0x1F);
+       addToMapW(0xdd, 0x04, 0x3F);
+       addToMapW(0xdd, 0x25, 0x8C);
+       addToMapW(0xdd, 0xF8, 0xC3);
+       addToMapW(0xdd, 0xFF, 0x9D);
+       addToMapW(0xde, 0x00, 0xCC);
+       addToMapW(0xde, 0x00, 0xEC);
+       addToMapW(0xde, 0x01, 0x6E);
+       addToMapW(0xde, 0x01, 0x6F);
+       addToMapW(0xde, 0x03, 0x03);
+       addToMapW(0xde, 0x25, 0x90);
+       addToMapW(0xde, 0xF8, 0xC4);
+       addToMapW(0xde, 0xFF, 0x9E);
+       addToMapW(0xdf, 0x00, 0xDF);
+       addToMapW(0xdf, 0x0E, 0x3F);
+       addToMapW(0xdf, 0x25, 0x80);
+       addToMapW(0xdf, 0xFF, 0x9F);
+       addToMapW(0xe0, 0x00, 0xD3);
+       addToMapW(0xe0, 0x00, 0xF3);
+       addToMapW(0xe0, 0x03, 0x91);
+       addToMapW(0xe0, 0x03, 0xB1);
+       addToMapW(0xe0, 0x04, 0x2F);
+       addToMapW(0xe0, 0x04, 0x4F);
+       addToMapW(0xe0, 0x06, 0x36);
+       addToMapW(0xe0, 0x0E, 0x40);
+       addToMapW(0xe0, 0xFE, 0xBD);
+       addToMapW(0xe0, 0xFE, 0xBE);
+       addToMapW(0xe0, 0xFE, 0xBF);
+       addToMapW(0xe0, 0xFE, 0xC0);
+       addToMapW(0xe1, 0x00, 0xDF);
+       addToMapW(0xe1, 0x03, 0xB2);
+       addToMapW(0xe1, 0x06, 0x37);
+       addToMapW(0xe1, 0x0E, 0x41);
+       addToMapW(0xe1, 0xFE, 0xC1);
+       addToMapW(0xe1, 0xFE, 0xC2);
+       addToMapW(0xe1, 0xFE, 0xC3);
+       addToMapW(0xe1, 0xFE, 0xC4);
+       addToMapW(0xe2, 0x00, 0xD4);
+       addToMapW(0xe2, 0x00, 0xF4);
+       addToMapW(0xe2, 0x01, 0x4C);
+       addToMapW(0xe2, 0x01, 0x4D);
+       addToMapW(0xe2, 0x03, 0x93);
+       addToMapW(0xe2, 0x04, 0x20);
+       addToMapW(0xe2, 0x04, 0x40);
+       addToMapW(0xe2, 0x06, 0x38);
+       addToMapW(0xe2, 0x0E, 0x42);
+       addToMapW(0xe2, 0xFE, 0xC5);
+       addToMapW(0xe2, 0xFE, 0xC6);
+       addToMapW(0xe2, 0xFE, 0xC7);
+       addToMapW(0xe2, 0xFE, 0xC8);
+       addToMapW(0xe3, 0x00, 0xD2);
+       addToMapW(0xe3, 0x00, 0xF2);
+       addToMapW(0xe3, 0x01, 0x43);
+       addToMapW(0xe3, 0x01, 0x44);
+       addToMapW(0xe3, 0x03, 0xA0);
+       addToMapW(0xe3, 0x03, 0xC0);
+       addToMapW(0xe3, 0x06, 0x39);
+       addToMapW(0xe3, 0x0E, 0x43);
+       addToMapW(0xe3, 0xFE, 0xC9);
+       addToMapW(0xe3, 0xFE, 0xCA);
+       addToMapW(0xe3, 0xFE, 0xCB);
+       addToMapW(0xe3, 0xFE, 0xCC);
+       addToMapW(0xe4, 0x01, 0xA9);
+       addToMapW(0xe4, 0x03, 0xA3);
+       addToMapW(0xe4, 0x03, 0xC3);
+       addToMapW(0xe4, 0x04, 0x21);
+       addToMapW(0xe4, 0x04, 0x41);
+       addToMapW(0xe4, 0x06, 0x3A);
+       addToMapW(0xe4, 0x0E, 0x44);
+       addToMapW(0xe4, 0x22, 0x11);
+       addToMapW(0xe4, 0xFE, 0xCD);
+       addToMapW(0xe4, 0xFE, 0xCE);
+       addToMapW(0xe4, 0xFE, 0xCF);
+       addToMapW(0xe4, 0xFE, 0xD0);
+       addToMapW(0xe5, 0x00, 0xD5);
+       addToMapW(0xe5, 0x00, 0xF5);
+       addToMapW(0xe5, 0x06, 0x41);
+       addToMapW(0xe5, 0x0E, 0x45);
+       addToMapW(0xe5, 0xFE, 0xD1);
+       addToMapW(0xe5, 0xFE, 0xD2);
+       addToMapW(0xe5, 0xFE, 0xD3);
+       addToMapW(0xe5, 0xFE, 0xD4);
+       addToMapW(0xe6, 0x00, 0xB5);
+       addToMapW(0xe6, 0x01, 0x60);
+       addToMapW(0xe6, 0x01, 0x61);
+       addToMapW(0xe6, 0x03, 0xBC);
+       addToMapW(0xe6, 0x04, 0x22);
+       addToMapW(0xe6, 0x04, 0x42);
+       addToMapW(0xe6, 0x0E, 0x46);
+       addToMapW(0xe7, 0x03, 0xA4);
+       addToMapW(0xe7, 0x03, 0xC4);
+       addToMapW(0xe7, 0x06, 0x42);
+       addToMapW(0xe7, 0x0E, 0x47);
+       addToMapW(0xe7, 0xF8, 0xBC);
+       addToMapW(0xe7, 0xFE, 0xD5);
+       addToMapW(0xe7, 0xFE, 0xD6);
+       addToMapW(0xe7, 0xFE, 0xD7);
+       addToMapW(0xe7, 0xFE, 0xD8);
+       addToMapW(0xe8, 0x00, 0xD7);
+       addToMapW(0xe8, 0x00, 0xDE);
+       addToMapW(0xe8, 0x00, 0xFE);
+       addToMapW(0xe8, 0x01, 0x36);
+       addToMapW(0xe8, 0x01, 0x37);
+       addToMapW(0xe8, 0x01, 0x54);
+       addToMapW(0xe8, 0x01, 0x55);
+       addToMapW(0xe8, 0x02, 0x78);
+       addToMapW(0xe8, 0x03, 0xA6);
+       addToMapW(0xe8, 0x03, 0xC6);
+       addToMapW(0xe8, 0x04, 0x23);
+       addToMapW(0xe8, 0x04, 0x43);
+       addToMapW(0xe8, 0x06, 0x43);
+       addToMapW(0xe8, 0x0E, 0x48);
+       addToMapW(0xe8, 0x22, 0x05);
+       addToMapW(0xe8, 0xFE, 0xD9);
+       addToMapW(0xe8, 0xFE, 0xDA);
+       addToMapW(0xe8, 0xFE, 0xDB);
+       addToMapW(0xe8, 0xFE, 0xDC);
+       addToMapW(0xe9, 0x00, 0xDA);
+       addToMapW(0xe9, 0x00, 0xFA);
+       addToMapW(0xe9, 0x03, 0x98);
+       addToMapW(0xe9, 0x06, 0x44);
+       addToMapW(0xe9, 0x0E, 0x49);
+       addToMapW(0xe9, 0xFE, 0xDD);
+       addToMapW(0xe9, 0xFE, 0xDE);
+       addToMapW(0xe9, 0xFE, 0xDF);
+       addToMapW(0xe9, 0xFE, 0xE0);
+       addToMapW(0xea, 0x00, 0xDB);
+       addToMapW(0xea, 0x00, 0xFB);
+       addToMapW(0xea, 0x01, 0x3B);
+       addToMapW(0xea, 0x01, 0x3C);
+       addToMapW(0xea, 0x03, 0x86);
+       addToMapW(0xea, 0x03, 0xA9);
+       addToMapW(0xea, 0x03, 0xAC);
+       addToMapW(0xea, 0x04, 0x16);
+       addToMapW(0xea, 0x04, 0x36);
+       addToMapW(0xea, 0x06, 0x45);
+       addToMapW(0xea, 0x0E, 0x4A);
+       addToMapW(0xea, 0x21, 0x26);
+       addToMapW(0xea, 0xFE, 0xE1);
+       addToMapW(0xea, 0xFE, 0xE2);
+       addToMapW(0xea, 0xFE, 0xE3);
+       addToMapW(0xea, 0xFE, 0xE4);
+       addToMapW(0xeb, 0x00, 0xD9);
+       addToMapW(0xeb, 0x00, 0xF9);
+       addToMapW(0xeb, 0x01, 0x70);
+       addToMapW(0xeb, 0x01, 0x71);
+       addToMapW(0xeb, 0x03, 0x88);
+       addToMapW(0xeb, 0x03, 0x94);
+       addToMapW(0xeb, 0x03, 0xAD);
+       addToMapW(0xeb, 0x03, 0xB4);
+       addToMapW(0xeb, 0x06, 0x46);
+       addToMapW(0xeb, 0x0E, 0x4B);
+       addToMapW(0xeb, 0xFE, 0xE5);
+       addToMapW(0xeb, 0xFE, 0xE6);
+       addToMapW(0xeb, 0xFE, 0xE7);
+       addToMapW(0xeb, 0xFE, 0xE8);
+       addToMapW(0xec, 0x03, 0x01);
+       addToMapW(0xec, 0x03, 0x89);
+       addToMapW(0xec, 0x03, 0xAE);
+       addToMapW(0xec, 0x04, 0x12);
+       addToMapW(0xec, 0x04, 0x32);
+       addToMapW(0xec, 0x06, 0x47);
+       addToMapW(0xec, 0x0E, 0x4C);
+       addToMapW(0xec, 0x22, 0x1E);
+       addToMapW(0xec, 0xFE, 0xE9);
+       addToMapW(0xec, 0xFE, 0xEA);
+       addToMapW(0xec, 0xFE, 0xEB);
+       addToMapW(0xec, 0xFE, 0xEC);
+       addToMapW(0xed, 0x00, 0xDD);
+       addToMapW(0xed, 0x00, 0xFD);
+       addToMapW(0xed, 0x01, 0x12);
+       addToMapW(0xed, 0x01, 0x13);
+       addToMapW(0xed, 0x03, 0x8A);
+       addToMapW(0xed, 0x03, 0xAF);
+       addToMapW(0xed, 0x06, 0x48);
+       addToMapW(0xed, 0x0E, 0x4D);
+       addToMapW(0xed, 0xFE, 0xED);
+       addToMapW(0xed, 0xFE, 0xEE);
+       addToMapW(0xee, 0x00, 0xAF);
+       addToMapW(0xee, 0x01, 0x45);
+       addToMapW(0xee, 0x01, 0x46);
+       addToMapW(0xee, 0x03, 0x04);
+       addToMapW(0xee, 0x03, 0x05);
+       addToMapW(0xee, 0x03, 0x8C);
+       addToMapW(0xee, 0x03, 0x95);
+       addToMapW(0xee, 0x03, 0xB5);
+       addToMapW(0xee, 0x03, 0xCC);
+       addToMapW(0xee, 0x04, 0x2C);
+       addToMapW(0xee, 0x04, 0x4C);
+       addToMapW(0xee, 0x06, 0x49);
+       addToMapW(0xee, 0x0E, 0x4E);
+       addToMapW(0xee, 0xFE, 0xEF);
+       addToMapW(0xee, 0xFE, 0xF0);
+       addToMapW(0xef, 0x00, 0xB4);
+       addToMapW(0xef, 0x02, 0xB9);
+       addToMapW(0xef, 0x02, 0xCA);
+       addToMapW(0xef, 0x03, 0x01);
+       addToMapW(0xef, 0x03, 0x8E);
+       addToMapW(0xef, 0x03, 0xCD);
+       addToMapW(0xef, 0x06, 0x4A);
+       addToMapW(0xef, 0x0E, 0x4F);
+       addToMapW(0xef, 0x20, 0x19);
+       addToMapW(0xef, 0x20, 0x32);
+       addToMapW(0xef, 0x20, 0x35);
+       addToMapW(0xef, 0x21, 0x16);
+       addToMapW(0xef, 0x22, 0x29);
+       addToMapW(0xef, 0xFE, 0xF1);
+       addToMapW(0xef, 0xFE, 0xF2);
+       addToMapW(0xef, 0xFE, 0xF3);
+       addToMapW(0xef, 0xFE, 0xF4);
+       addToMapW(0xf0, 0x00, 0xAD);
+       addToMapW(0xf0, 0x03, 0x8F);
+       addToMapW(0xf0, 0x03, 0xCE);
+       addToMapW(0xf0, 0x04, 0x01);
+       addToMapW(0xf0, 0x04, 0x51);
+       addToMapW(0xf0, 0x0E, 0x50);
+       addToMapW(0xf0, 0x22, 0x61);
+       addToMapW(0xf1, 0x00, 0xB1);
+       addToMapW(0xf1, 0x02, 0xDD);
+       addToMapW(0xf1, 0x06, 0x4B);
+       addToMapW(0xf1, 0x0E, 0x51);
+       addToMapW(0xf1, 0x22, 0x13);
+       addToMapW(0xf1, 0xFE, 0x70);
+       addToMapW(0xf1, 0xFE, 0x71);
+       addToMapW(0xf2, 0x02, 0xDB);
+       addToMapW(0xf2, 0x03, 0x23);
+       addToMapW(0xf2, 0x04, 0x04);
+       addToMapW(0xf2, 0x04, 0x2B);
+       addToMapW(0xf2, 0x04, 0x4B);
+       addToMapW(0xf2, 0x04, 0x54);
+       addToMapW(0xf2, 0x06, 0x4C);
+       addToMapW(0xf2, 0x0E, 0x52);
+       addToMapW(0xf2, 0x20, 0x17);
+       addToMapW(0xf2, 0x20, 0x1C);
+       addToMapW(0xf2, 0x22, 0x65);
+       addToMapW(0xf2, 0xF8, 0xBD);
+       addToMapW(0xf2, 0xFE, 0x72);
+       addToMapW(0xf3, 0x00, 0xBE);
+       addToMapW(0xf3, 0x02, 0xC7);
+       addToMapW(0xf3, 0x03, 0x0C);
+       addToMapW(0xf3, 0x06, 0x4D);
+       addToMapW(0xf3, 0x0E, 0x53);
+       addToMapW(0xf3, 0x22, 0x64);
+       addToMapW(0xf3, 0xFE, 0x74);
+       addToMapW(0xf4, 0x00, 0xB6);
+       addToMapW(0xf4, 0x02, 0xD8);
+       addToMapW(0xf4, 0x03, 0x06);
+       addToMapW(0xf4, 0x03, 0xAA);
+       addToMapW(0xf4, 0x03, 0xCA);
+       addToMapW(0xf4, 0x04, 0x07);
+       addToMapW(0xf4, 0x04, 0x17);
+       addToMapW(0xf4, 0x04, 0x37);
+       addToMapW(0xf4, 0x04, 0x57);
+       addToMapW(0xf4, 0x06, 0x4E);
+       addToMapW(0xf4, 0x0E, 0x54);
+       addToMapW(0xf4, 0x23, 0x20);
+       addToMapW(0xf4, 0xFE, 0x76);
+       addToMapW(0xf4, 0xFE, 0x77);
+       addToMapW(0xf5, 0x00, 0xA7);
+       addToMapW(0xf5, 0x03, 0xAB);
+       addToMapW(0xf5, 0x03, 0xCB);
+       addToMapW(0xf5, 0x06, 0x4F);
+       addToMapW(0xf5, 0x0E, 0x55);
+       addToMapW(0xf5, 0x23, 0x21);
+       addToMapW(0xf5, 0xFE, 0x78);
+       addToMapW(0xf5, 0xFE, 0x79);
+       addToMapW(0xf6, 0x00, 0xF7);
+       addToMapW(0xf6, 0x04, 0x0E);
+       addToMapW(0xf6, 0x04, 0x28);
+       addToMapW(0xf6, 0x04, 0x48);
+       addToMapW(0xf6, 0x04, 0x5E);
+       addToMapW(0xf6, 0x06, 0x50);
+       addToMapW(0xf6, 0x0E, 0x56);
+       addToMapW(0xf6, 0xFE, 0x7A);
+       addToMapW(0xf6, 0xFE, 0x7B);
+       addToMapW(0xf7, 0x00, 0xB8);
+       addToMapW(0xf7, 0x00, 0xF7);
+       addToMapW(0xf7, 0x02, 0xDB);
+       addToMapW(0xf7, 0x03, 0x27);
+       addToMapW(0xf7, 0x0E, 0x57);
+       addToMapW(0xf7, 0x20, 0x1E);
+       addToMapW(0xf7, 0x22, 0x48);
+       addToMapW(0xf8, 0x00, 0xB0);
+       addToMapW(0xf8, 0x02, 0xDA);
+       addToMapW(0xf8, 0x03, 0x0A);
+       addToMapW(0xf8, 0x04, 0x2D);
+       addToMapW(0xf8, 0x04, 0x4D);
+       addToMapW(0xf8, 0x0E, 0x58);
+       addToMapW(0xf8, 0x20, 0x70);
+       addToMapW(0xf8, 0x22, 0x18);
+       addToMapW(0xf9, 0x00, 0xA8);
+       addToMapW(0xf9, 0x02, 0xDD);
+       addToMapW(0xf9, 0x03, 0x08);
+       addToMapW(0xf9, 0x0E, 0x59);
+       addToMapW(0xf9, 0x22, 0x19);
+       addToMapW(0xfa, 0x00, 0xB7);
+       addToMapW(0xfa, 0x02, 0xD9);
+       addToMapW(0xfa, 0x03, 0x07);
+       addToMapW(0xfa, 0x04, 0x29);
+       addToMapW(0xfa, 0x04, 0x49);
+       addToMapW(0xfa, 0x0E, 0x5A);
+       addToMapW(0xfa, 0x20, 0x24);
+       addToMapW(0xfa, 0x22, 0xC5);
+       addToMapW(0xfa, 0x30, 0xFB);
+       addToMapW(0xfb, 0x00, 0xB9);
+       addToMapW(0xfb, 0x0E, 0x5B);
+       addToMapW(0xfb, 0x20, 0x81);
+       addToMapW(0xfb, 0x22, 0x1A);
+       addToMapW(0xfb, 0x27, 0x13);
+       addToMapW(0xfc, 0x00, 0xB3);
+       addToMapW(0xfc, 0x01, 0x58);
+       addToMapW(0xfc, 0x01, 0x59);
+       addToMapW(0xfc, 0x04, 0x27);
+       addToMapW(0xfc, 0x04, 0x47);
+       addToMapW(0xfc, 0x20, 0x7F);
+       addToMapW(0xfc, 0x20, 0x83);
+       addToMapW(0xfc, 0x21, 0x16);
+       addToMapW(0xfc, 0xF8, 0xC5);
+       addToMapW(0xfd, 0x00, 0xA4);
+       addToMapW(0xfd, 0x00, 0xA7);
+       addToMapW(0xfd, 0x00, 0xB2);
+       addToMapW(0xfd, 0x20, 0x82);
+       addToMapW(0xfd, 0xF8, 0xC6);
+       addToMapW(0xfd, 0xF8, 0xF1);
+       addToMapW(0xfe, 0x20, 0xAB);
+       addToMapW(0xfe, 0x25, 0xA0);
+       addToMapW(0xfe, 0xF8, 0xC7);
+       addToMapW(0xfe, 0xF8, 0xF2);
+       addToMapW(0xff, 0x00, 0xA0);
+       addToMapW(0xff, 0xF8, 0xC8);
+       addToMapW(0xff, 0xF8, 0xF3);
+}
diff --git a/Client Applications/rcracki_mt/lm2ntlm.h b/Client Applications/rcracki_mt/lm2ntlm.h
new file mode 100644 (file)
index 0000000..ff2e42d
--- /dev/null
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string>
+#include <map>
+#ifdef _WIN32
+#include <conio.h>
+#endif
+#include "openssl/md4.h"
+#include "time.h"
+#include "signal.h"
+#include "Public.h"
+using namespace std;
+
+class LM2NTLMcorrector
+{
+public:
+       LM2NTLMcorrector();
+
+private:
+       map<unsigned char, map<int, unsigned char> > m_mapChar;
+       uint64 progressCurrentCombination;
+       uint64 totalCurrentCombination;
+       uint64 counterOverall;
+       unsigned char NTLMHash[16];
+       clock_t startClock;
+       int countCombinations;
+       int countTotalCombinations;
+       int counter;
+       clock_t previousClock;
+       unsigned char currentCharmap[16][128];
+       bool aborting;
+       string sBinary;
+
+private:
+       bool checkNTLMPassword(unsigned char* pLMPassword, int nLMPasswordLen, string& sNTLMPassword);
+       bool startCorrecting(string sLMPassword, unsigned char* pNTLMHash, string& sNTLMPassword, unsigned char* pLMPassword);
+       void printString(unsigned char* muteThis, int length);
+       void setupCombinationAtPositions(int length, unsigned char* pMuteMe, unsigned char* pTempMute, int* jAtPos, bool* fullAtPos, int* sizeAtPos);
+       bool checkPermutations(int length, unsigned char* pMuteMe, unsigned char* pTempMute, int* jAtPos, int* sizeAtPos, unsigned char* pLMPassword, string& sNTLMPassword);
+
+       int calculateTotalCombinations(int length, int setSize);
+       int factorial (int num);
+
+       bool parseHexPassword(string hexPassword, string& sPlain);
+       bool NormalizeHexString(string& sHash);
+       void ParseHash(string sHash, unsigned char* pHash, int& nHashLen);
+       string ByteToStr(const unsigned char* pData, int nLen);
+       void addToMapW(unsigned char key, unsigned char value1, unsigned char value2);
+       void fillMapW();
+       void checkAbort();
+       void writeEndStats();
+public:
+       bool LMPasswordCorrectUnicode(string hexPassword, unsigned char* NTLMHash, string& sNTLMPassword);
+       string getBinary();
+};
+
diff --git a/Client Applications/rcracki_mt/md4.cpp b/Client Applications/rcracki_mt/md4.cpp
new file mode 100644 (file)
index 0000000..4e402fd
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * "Just the reference implementation, single stage. Hardly "optimized." Though a good bit faster than libssl's MD4, as it isn't doing nearly the same amount of work." - Bitweasil
+ * 
+ * little bit optimized (or at least attempted) for NTLM (unicode) by neinbrucke
+ */
+
+
+//#include <cstdlib>
+#include <cstring>
+#include "md4.h"
+
+/* MD4 Defines as per RFC reference implementation */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+#define FF(a, b, c, d, x, s) { \
+    (a) += F ((b), (c), (d)) + (x); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define GG(a, b, c, d, x, s) { \
+    (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define HH(a, b, c, d, x, s) { \
+    (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+/* End MD4 Defines */
+
+void MD4_NEW( unsigned char * pData, int length, unsigned char * pDigest)
+{
+       // access data as 4-byte word
+       #define uData                           ((UINT4 *)pData)
+       #define uDigest                         ((UINT4 *)pDigest)
+
+       // pad word and append bit at appropriate location
+       #define MD4_pad_w0()            (0x00000080)
+       #define MD4_pad_w1(data)        (((data) & 0x000000FF) | 0x00008000)
+       #define MD4_pad_w2(data)        (((data) & 0x0000FFFF) | 0x00800000)
+       #define MD4_pad_w3(data)        (((data) & 0x00FFFFFF) | 0x80000000)
+
+       // For the hash working space
+       //__attribute__((aligned(16))) UINT4 data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       //__declspec(align(16)) UINT4 data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       UINT4 data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+       // For the output result
+       UINT4 a,b,c,d;
+
+       switch (length)
+       {
+               case 0:
+               {
+                       data[ 0] = MD4_pad_w0();
+
+                       data[14] = 0;
+               }
+               break;
+               case 1:
+               {
+                       data[ 0] = MD4_pad_w1(uData[0]);
+
+                       data[14] = 1 << 3;
+               }
+               break;
+               case 2:
+               {
+                       data[ 0] = MD4_pad_w2(uData[0]);
+
+                       data[14] = 2 << 3;
+               }
+               break;
+               case 3:
+               {
+                       data[ 0] = MD4_pad_w3(uData[0]);
+
+                       data[14] = 3 << 3;
+               }
+               break;
+               case 4:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = MD4_pad_w0();
+
+                       data[14] = 4 << 3;
+               }
+               break;
+               case 5:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = MD4_pad_w1(uData[1]);
+
+                       data[14] = 5 << 3;
+               }
+               break;
+               case 6:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = MD4_pad_w2(uData[1]);
+
+                       data[14] = 6 << 3;
+               }
+               break;
+               case 7:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = MD4_pad_w3(uData[1]);
+
+                       data[14] = 7 << 3;
+               }
+               break;
+               case 8:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = MD4_pad_w0();
+
+                       data[14] = 8 << 3;
+               }
+               break;
+               case 9:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = MD4_pad_w1(uData[2]);
+
+                       data[14] = 9 << 3;
+               }
+               break;
+               case 10:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = MD4_pad_w2(uData[2]);
+
+                       data[14] = 10 << 3;
+               }
+               break;
+               case 11:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = MD4_pad_w3(uData[2]);
+
+                       data[14] = 11 << 3;
+               }
+               break;
+               case 12:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = uData[2];
+                       data[ 3] = MD4_pad_w0();
+
+                       data[14] = 12 << 3;
+               }
+               break;
+               case 13:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = uData[2];
+                       data[ 3] = MD4_pad_w1(uData[3]);
+
+                       data[14] = 13 << 3;
+               }
+               break;
+               case 14:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = uData[2];
+                       data[ 3] = MD4_pad_w2(uData[3]);
+
+                       data[14] = 14 << 3;
+               }
+               break;
+               case 15:
+               {
+                       data[ 0] = uData[0];
+                       data[ 1] = uData[1];
+                       data[ 2] = uData[2];
+                       data[ 3] = MD4_pad_w3(uData[3]);
+
+                       data[14] = 15 << 3;
+               }
+               break;
+
+               default:
+               {
+                       length = length % 32; // lenght >= 32 not suported
+
+                       int word = length >> 2;
+
+                       int i = 0;
+                       while (i < word) {
+                               data[i] = uData[i];
+                               i++;
+                       }
+
+                       switch (length & 0x3) {
+                               case 0:
+                               {
+                                       data[word] = MD4_pad_w0();
+                               }
+                               break;
+                               case 1:
+                               {
+                                       data[word] = MD4_pad_w1(uData[word]);
+                               }
+                               break;
+                               case 2:
+                               {
+                                       data[word] = MD4_pad_w2(uData[word]);
+                               }
+                               break;
+                               case 3:
+                               {
+                                       data[word] = MD4_pad_w3(uData[word]);
+                               }
+                               break;
+                       }
+
+                       data[14] = length << 3;
+               }
+               break;
+       }
+
+       a = 0x67452301;
+       b = 0xefcdab89;
+       c = 0x98badcfe;
+       d = 0x10325476;
+
+       /* Round 1 */
+       FF (a, b, c, d, data[ 0], S11); /* 1 */
+       FF (d, a, b, c, data[ 1], S12); /* 2 */
+       FF (c, d, a, b, data[ 2], S13); /* 3 */
+       FF (b, c, d, a, data[ 3], S14); /* 4 */
+       FF (a, b, c, d, data[ 4], S11); /* 5 */
+       FF (d, a, b, c, data[ 5], S12); /* 6 */
+       FF (c, d, a, b, data[ 6], S13); /* 7 */
+       FF (b, c, d, a, data[ 7], S14); /* 8 */
+       FF (a, b, c, d,        0, S11); /* 9 */
+       FF (d, a, b, c,        0, S12); /* 10 */
+       FF (c, d, a, b,        0, S13); /* 11 */
+       FF (b, c, d, a,        0, S14); /* 12 */
+       FF (a, b, c, d,        0, S11); /* 13 */
+       FF (d, a, b, c,        0, S12); /* 14 */
+       FF (c, d, a, b, data[14], S13); /* 15 */
+       FF (b, c, d, a,        0, S14); /* 16 */
+
+       /* Round 2 */
+       GG (a, b, c, d, data[ 0], S21); /* 17 */
+       GG (d, a, b, c, data[ 4], S22); /* 18 */
+       GG (c, d, a, b,        0, S23); /* 19 */
+       GG (b, c, d, a,        0, S24); /* 20 */
+       GG (a, b, c, d, data[ 1], S21); /* 21 */
+       GG (d, a, b, c, data[ 5], S22); /* 22 */
+       GG (c, d, a, b,        0, S23); /* 23 */
+       GG (b, c, d, a,        0, S24); /* 24 */
+       GG (a, b, c, d, data[ 2], S21); /* 25 */
+       GG (d, a, b, c, data[ 6], S22); /* 26 */
+       GG (c, d, a, b,        0, S23); /* 27 */
+       GG (b, c, d, a, data[14], S24); /* 28 */
+       GG (a, b, c, d, data[ 3], S21); /* 29 */
+       GG (d, a, b, c, data[ 7], S22); /* 30 */
+       GG (c, d, a, b,        0, S23); /* 31 */
+       GG (b, c, d, a,        0, S24); /* 32 */
+
+       /* Round 3 */
+       HH (a, b, c, d, data[ 0], S31); /* 33 */
+       HH (d, a, b, c,        0, S32); /* 34 */
+       HH (c, d, a, b, data[ 4], S33); /* 35 */
+       HH (b, c, d, a,        0, S34); /* 36 */
+       HH (a, b, c, d, data[ 2], S31); /* 37 */
+       HH (d, a, b, c,        0, S32); /* 38 */
+       HH (c, d, a, b, data[ 6], S33); /* 39 */
+       HH (b, c, d, a, data[14], S34); /* 40 */
+       HH (a, b, c, d, data[ 1], S31); /* 41 */
+       HH (d, a, b, c,        0, S32); /* 42 */
+       HH (c, d, a, b, data[ 5], S33); /* 43 */
+       HH (b, c, d, a,        0, S34); /* 44 */
+       HH (a, b, c, d, data[ 3], S31); /* 45 */
+       HH (d, a, b, c,        0, S32); /* 46 */
+       HH (c, d, a, b, data[ 7], S33); /* 47 */
+       HH (b, c, d, a,        0, S34); /* 48 */
+
+       // Finally, add initial values, as this is the only pass we make.
+       a += 0x67452301;
+       b += 0xefcdab89;
+       c += 0x98badcfe;
+       d += 0x10325476;
+
+       uDigest[0] = a;
+       uDigest[1] = b;
+       uDigest[2] = c;
+       uDigest[3] = d;
+}
+
+//void MD4_NEW( unsigned char * pData, int length, unsigned char * pDigest)
+//{
+//     // For the hash working space
+//     UINT4 b0,b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15;
+//
+//     // For the output result
+//     UINT4 a,b,c,d;
+//
+//     b0 = 0x00000000;
+//     b1 = 0x00000000;
+//     b2 = 0x00000000;
+//     b3 = 0x00000000;
+//     b4 = 0x00000000;
+//     b5 = 0x00000000;
+//     b6 = 0x00000000;
+//     b7 = 0x00000000;
+//     b8 = 0x00000000;
+//     b9 = 0x00000000;
+//     b10 = 0x00000000;
+//     b11 = 0x00000000;
+//     b12 = 0x00000000;
+//     b13 = 0x00000000;
+//     b14 = 0x00000000;
+//     b15 = 0x00000000; 
+//
+//     // LOAD DATA INTO b0 ... whatever here.   
+//     switch (length)
+//     {
+//             case 2:
+//             {
+//                     unsigned char in[4];
+//                     memcpy(in, pData, length);
+//                     in[2] = 0x80;
+//                     in[3] = 0x00;
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//             }
+//             break;
+//             case 4:
+//             {
+//                     unsigned char in[4];
+//                     memcpy(in, pData, length);
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//                     b1 = 0x00000080;
+//             }
+//             break;
+//             case 6:
+//             {
+//                     unsigned char in[8];
+//                     memcpy(in, pData, length);
+//                     in[6] = 0x80;
+//                     in[7] = 0x00;
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//                     b1 = pUiIn[1];
+//             }
+//             break;
+//             case 8:
+//             {
+//                     unsigned char in[8];
+//                     memcpy(in, pData, length);
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//                     b1 = pUiIn[1];
+//                     b2 = 0x00000080;
+//             }
+//             break;
+//             case 10:
+//             {
+//                     unsigned char in[12];
+//                     memcpy(in, pData, length);
+//                     in[10] = 0x80;
+//                     in[11] = 0x00;
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//                     b1 = pUiIn[1];
+//                     b2 = pUiIn[2];
+//             }
+//             break;
+//             default:
+//             {
+//                     unsigned char in[32];
+//                     memcpy(in, pData, length);
+//                     in[length] = 0x80;
+//                     memset(in + length + 1, 0, 32 - length - 1);
+//                     UINT4 * pUiIn = (UINT4 *) in;
+//                     b0 = pUiIn[0];
+//                     b1 = pUiIn[1];
+//                     b2 = pUiIn[2];
+//                     b3 = pUiIn[3];
+//                     b4 = pUiIn[4];
+//                     b5 = pUiIn[5];
+//                     b6 = pUiIn[6];
+//                     b7 = pUiIn[7]; // max 14 2byte chars (ntlm)
+//                     b8 = pUiIn[8];
+//             }
+//             break;
+//     }
+//
+//     b14 = length << 3;
+//
+//     a = 0x67452301;
+//     b = 0xefcdab89;
+//     c = 0x98badcfe;
+//     d = 0x10325476;
+//
+//     /* Round 1 */
+//     FF (a, b, c, d, b0, S11); /* 1 */
+//     FF (d, a, b, c, b1, S12); /* 2 */
+//     FF (c, d, a, b, b2, S13); /* 3 */
+//     FF (b, c, d, a, b3, S14); /* 4 */
+//     FF (a, b, c, d, b4, S11); /* 5 */
+//     FF (d, a, b, c, b5, S12); /* 6 */
+//     FF (c, d, a, b, b6, S13); /* 7 */
+//     FF (b, c, d, a, b7, S14); /* 8 */
+//     FF (a, b, c, d, 0, S11); /* 9 */
+//     FF (d, a, b, c, 0, S12); /* 10 */
+//     FF (c, d, a, b, 0, S13); /* 11 */
+//     FF (b, c, d, a, 0, S14); /* 12 */
+//     FF (a, b, c, d, 0, S11); /* 13 */
+//     FF (d, a, b, c, 0, S12); /* 14 */
+//     FF (c, d, a, b, b14, S13); /* 15 */
+//     FF (b, c, d, a, 0, S14); /* 16 */
+//
+//     /* Round 2 */
+//     GG (a, b, c, d, b0, S21); /* 17 */
+//     GG (d, a, b, c, b4, S22); /* 18 */
+//     GG (c, d, a, b, 0, S23); /* 19 */
+//     GG (b, c, d, a, 0, S24); /* 20 */
+//     GG (a, b, c, d, b1, S21); /* 21 */
+//     GG (d, a, b, c, b5, S22); /* 22 */
+//     GG (c, d, a, b, 0, S23); /* 23 */
+//     GG (b, c, d, a, 0, S24); /* 24 */
+//     GG (a, b, c, d, b2, S21); /* 25 */
+//     GG (d, a, b, c, b6, S22); /* 26 */
+//     GG (c, d, a, b, 0, S23); /* 27 */
+//     GG (b, c, d, a, b14, S24); /* 28 */
+//     GG (a, b, c, d, b3, S21); /* 29 */
+//     GG (d, a, b, c, b7, S22); /* 30 */
+//     GG (c, d, a, b, 0, S23); /* 31 */
+//     GG (b, c, d, a, 0, S24); /* 32 */
+//
+//     /* Round 3 */
+//     HH (a, b, c, d, b0, S31); /* 33 */
+//     HH (d, a, b, c, 0, S32); /* 34 */
+//     HH (c, d, a, b, b4, S33); /* 35 */
+//     HH (b, c, d, a, 0, S34); /* 36 */
+//     HH (a, b, c, d, b2, S31); /* 37 */
+//     HH (d, a, b, c, 0, S32); /* 38 */
+//     HH (c, d, a, b, b6, S33); /* 39 */
+//     HH (b, c, d, a, b14, S34); /* 40 */
+//     HH (a, b, c, d, b1, S31); /* 41 */
+//     HH (d, a, b, c, 0, S32); /* 42 */
+//     HH (c, d, a, b, b5, S33); /* 43 */
+//     HH (b, c, d, a, 0, S34); /* 44 */
+//     HH (a, b, c, d, b3, S31); /* 45 */
+//     HH (d, a, b, c, 0, S32); /* 46 */
+//     HH (c, d, a, b, b7, S33); /* 47 */
+//     HH (b, c, d, a, 0, S34); /* 48 */
+//
+//     // Finally, add initial values, as this is the only pass we make.
+//     a += 0x67452301;
+//     b += 0xefcdab89;
+//     c += 0x98badcfe;
+//     d += 0x10325476;
+//
+//     UINT4 buf[4] = { a, b, c, d};
+//     memcpy(pDigest, buf, 16);
+//
+//     return;
+//}
diff --git a/Client Applications/rcracki_mt/md4.h b/Client Applications/rcracki_mt/md4.h
new file mode 100644 (file)
index 0000000..8a5c428
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef MD4_H
+#define MD4_H
+
+//typedef unsigned long uint32;
+typedef unsigned long UINT4;
+
+//Main function
+void MD4_NEW( unsigned char * buf, int len, unsigned char * pDigest);
+
+#endif /* !MD4_H */
diff --git a/Client Applications/rcracki_mt/pthreadVC2.dll b/Client Applications/rcracki_mt/pthreadVC2.dll
new file mode 100644 (file)
index 0000000..93f562b
Binary files /dev/null and b/Client Applications/rcracki_mt/pthreadVC2.dll differ
diff --git a/Client Applications/rcracki_mt/pthreadVC2.lib b/Client Applications/rcracki_mt/pthreadVC2.lib
new file mode 100644 (file)
index 0000000..13f47f4
Binary files /dev/null and b/Client Applications/rcracki_mt/pthreadVC2.lib differ
diff --git a/Client Applications/rcracki_mt/rcrackiThread.cpp b/Client Applications/rcracki_mt/rcrackiThread.cpp
new file mode 100644 (file)
index 0000000..9dc1f14
--- /dev/null
@@ -0,0 +1,239 @@
+#ifdef _WIN32
+       #pragma warning(disable : 4786 4267 4018)
+#endif
+
+#include "rcrackiThread.h"
+
+// create job for pre-calculation
+rcrackiThread::rcrackiThread(unsigned char* TargetHash, int thread_id, int nRainbowChainLen, int thread_count, uint64* pStartPosIndexE)
+{
+       t_TargetHash = TargetHash;
+       t_nRainbowChainLen = nRainbowChainLen;
+       t_ID = thread_id;
+       t_count = thread_count;
+       t_pStartPosIndexE = pStartPosIndexE;
+       t_nChainWalkStep = 0;
+       falseAlarmChecker = false;
+       falseAlarmCheckerO = false;
+}
+
+// create job for false alarm checking
+rcrackiThread::rcrackiThread(unsigned char* pHash)
+{
+       falseAlarmChecker = true;
+       falseAlarmCheckerO = false;
+       t_pChainsFound.clear();
+       t_nGuessedPoss.clear();
+       t_pHash = pHash;
+       t_nChainWalkStepDueToFalseAlarm = 0;
+       t_nFalseAlarm = 0;
+       foundHash = false;
+}
+
+// create job for false alarm checking OLD format
+rcrackiThread::rcrackiThread(unsigned char* pHash, bool oldFormat)
+{
+       falseAlarmChecker = true;
+       falseAlarmCheckerO = true;
+       t_pChainsFoundO.clear();
+       t_nGuessedPoss.clear();
+       t_pHash = pHash;
+       t_nChainWalkStepDueToFalseAlarm = 0;
+       t_nFalseAlarm = 0;
+       foundHash = false;
+}
+
+
+void rcrackiThread::AddAlarmCheck(RainbowChain* pChain, int nGuessedPos)
+{
+       t_pChainsFound.push_back(pChain);
+       t_nGuessedPoss.push_back(nGuessedPos);
+}
+
+void rcrackiThread::AddAlarmCheckO(RainbowChainO* pChain, int nGuessedPos)
+{
+       t_pChainsFoundO.push_back(pChain);
+       t_nGuessedPoss.push_back(nGuessedPos);
+}
+
+// Windows (beginthreadex) way of threads
+//unsigned __stdcall rcrackiThread::rcrackiThreadStaticEntryPoint(void * pThis)
+//{
+//     rcrackiThread* pTT = (rcrackiThread*)pThis;
+//     pTT->rcrackiThreadEntryPoint();
+//     _endthreadex( 2 );
+//     return 2;
+//}
+
+// entry point for the posix thread
+void * rcrackiThread::rcrackiThreadStaticEntryPointPthread(void * pThis)
+{
+       rcrackiThread* pTT = (rcrackiThread*)pThis;
+       pTT->rcrackiThreadEntryPoint();
+       pthread_exit(NULL);
+       return NULL;
+}
+
+// start processing of jobs
+void rcrackiThread::rcrackiThreadEntryPoint()
+{
+       if (falseAlarmChecker) {
+               if (falseAlarmCheckerO) {
+                       CheckAlarmO();
+               }
+               else {
+                       CheckAlarm();
+               }
+       }
+       else {
+               PreCalculate();
+       }
+}
+
+uint64 rcrackiThread::GetIndex(int nPos)
+{
+       uint64 t_index = t_vStartPosIndexE[nPos - t_ID];
+       return t_index;
+}
+
+int rcrackiThread::GetChainWalkStep()
+{
+       return t_nChainWalkStep;
+}
+
+int rcrackiThread::GetIndexCount()
+{
+       return t_vStartPosIndexE.size();
+}
+
+rcrackiThread::~rcrackiThread(void)
+{
+}
+
+void rcrackiThread::PreCalculate()
+{
+       for (t_nPos = t_nRainbowChainLen - 2 - t_ID; t_nPos >= 0; t_nPos -= t_count)
+       {
+               t_cwc.SetHash(t_TargetHash);
+               t_cwc.HashToIndex(t_nPos);
+               int i;
+               for (i = t_nPos + 1; i <= t_nRainbowChainLen - 2; i++)
+               //for (i = t_nPos + 1; i <= 10; i++)
+               {
+                       t_cwc.IndexToPlain();
+                       t_cwc.PlainToHash();
+                       t_cwc.HashToIndex(i);
+               }
+               t_pStartPosIndexE[t_nPos] = t_cwc.GetIndex();
+               t_nChainWalkStep += t_nRainbowChainLen - 2 - t_nPos;
+       }
+}
+
+void rcrackiThread::CheckAlarm()
+{
+       int i;
+       for (i = 0; i < t_pChainsFound.size(); i++)
+       {
+               RainbowChain* t_pChain = t_pChainsFound[i];
+               int t_nGuessedPos = t_nGuessedPoss[i];          
+               
+               CChainWalkContext cwc;
+               //uint64 nIndexS = t_pChain->nIndexS & 0x0000FFFFFFFFFFFF; // for first 6 bytes
+               //uint64 nIndexS = t_pChain->nIndexS >> 16;
+               uint64 nIndexS = t_pChain->nIndexS & 0x0000FFFFFFFFFFFFULL; // for first 6 bytes
+               cwc.SetIndex(nIndexS);
+               //cwc.SetIndex(t_pChain->nIndexS);      
+               int nPos;
+               for (nPos = 0; nPos < t_nGuessedPos; nPos++)
+               {
+                       cwc.IndexToPlain();
+                       cwc.PlainToHash();
+                       cwc.HashToIndex(nPos);
+               }
+               cwc.IndexToPlain();
+               cwc.PlainToHash();
+               if (cwc.CheckHash(t_pHash))
+               {
+                       t_Hash = cwc.GetHash();
+                       t_Plain = cwc.GetPlain();
+                       t_Binary = cwc.GetBinary();
+
+                       foundHash = true;
+                       break;
+               }
+               else {
+                       foundHash = false;
+                       t_nChainWalkStepDueToFalseAlarm += t_nGuessedPos + 1;
+                       t_nFalseAlarm++;
+               }
+       }
+}
+
+void rcrackiThread::CheckAlarmO()
+{
+       int i;
+       for (i = 0; i < t_pChainsFoundO.size(); i++)
+       {
+               RainbowChainO* t_pChain = t_pChainsFoundO[i];
+               int t_nGuessedPos = t_nGuessedPoss[i];          
+               
+               CChainWalkContext cwc;
+
+               uint64 nIndexS = t_pChain->nIndexS;
+               cwc.SetIndex(nIndexS);
+
+               int nPos;
+               for (nPos = 0; nPos < t_nGuessedPos; nPos++)
+               {
+                       cwc.IndexToPlain();
+                       cwc.PlainToHash();
+                       cwc.HashToIndex(nPos);
+               }
+               cwc.IndexToPlain();
+               cwc.PlainToHash();
+               if (cwc.CheckHash(t_pHash))
+               {
+                       t_Hash = cwc.GetHash();
+                       t_Plain = cwc.GetPlain();
+                       t_Binary = cwc.GetBinary();
+
+                       foundHash = true;
+                       break;
+               }
+               else {
+                       foundHash = false;
+                       t_nChainWalkStepDueToFalseAlarm += t_nGuessedPos + 1;
+                       t_nFalseAlarm++;
+               }
+       }
+}
+
+bool rcrackiThread::FoundHash()
+{
+       return foundHash;
+}
+
+int rcrackiThread::GetChainWalkStepDueToFalseAlarm()
+{
+       return t_nChainWalkStepDueToFalseAlarm;
+}
+
+int rcrackiThread::GetnFalseAlarm()
+{
+       return t_nFalseAlarm;
+}
+
+string rcrackiThread::GetHash()
+{
+       return t_Hash;
+}
+
+string rcrackiThread::GetPlain()
+{
+       return t_Plain;
+}
+
+string rcrackiThread::GetBinary()
+{
+       return t_Binary;
+}
diff --git a/Client Applications/rcracki_mt/rcrackiThread.h b/Client Applications/rcracki_mt/rcrackiThread.h
new file mode 100644 (file)
index 0000000..74b96dc
--- /dev/null
@@ -0,0 +1,60 @@
+#pragma once
+#include "ChainWalkContext.h"
+#include "Public.h"
+#include "HashSet.h"
+//#include <process.h>
+#include <pthread.h>
+
+class rcrackiThread
+{
+private:
+       unsigned char* t_TargetHash;
+       int t_nPos;
+       int t_nRainbowChainLen;
+       CChainWalkContext t_cwc;
+       vector<uint64> t_vStartPosIndexE;
+       int t_ID;
+       int t_count;
+       uint64* t_pStartPosIndexE;
+       int t_nChainWalkStep;
+       bool falseAlarmChecker;
+       bool falseAlarmCheckerO;
+       vector<RainbowChain *> t_pChainsFound;
+       vector<RainbowChainO *> t_pChainsFoundO;
+       vector<int> t_nGuessedPoss;
+       unsigned char* t_pHash;
+       bool foundHash;
+       int t_nChainWalkStepDueToFalseAlarm;
+       int t_nFalseAlarm;
+       string t_Hash;
+       string t_Plain;
+       string t_Binary;
+
+public:
+       rcrackiThread(unsigned char* TargetHash, int thread_id, int nRainbowChainLen, int thread_count, uint64* pStartPosIndexE);
+       rcrackiThread(unsigned char* pHash);
+       rcrackiThread(unsigned char* pHash, bool oldFormat);
+       rcrackiThread(void);
+       ~rcrackiThread(void);
+
+       //void SetWork(unsigned char* TargetHash, int nPos, int nRainbowChainLen);
+       //static unsigned __stdcall rcrackiThread::rcrackiThreadStaticEntryPoint(void * pThis);
+       static void * rcrackiThreadStaticEntryPointPthread(void * pThis);
+       int GetIndexCount();
+       int GetChainWalkStep();
+       uint64 GetIndex(int nPos);
+       bool FoundHash();
+       void AddAlarmCheck(RainbowChain* pChain, int nGuessedPos);
+       void AddAlarmCheckO(RainbowChainO* pChain, int nGuessedPos);
+       int GetChainWalkStepDueToFalseAlarm();
+       int GetnFalseAlarm();
+       string GetHash();
+       string GetPlain();
+       string GetBinary();
+
+private:
+       void rcrackiThreadEntryPoint();
+       void PreCalculate();
+       void CheckAlarm();
+       void CheckAlarmO();
+};
diff --git a/Client Applications/rcracki_mt/rcracki_mt.exe b/Client Applications/rcracki_mt/rcracki_mt.exe
new file mode 100644 (file)
index 0000000..2de1ad6
Binary files /dev/null and b/Client Applications/rcracki_mt/rcracki_mt.exe differ
diff --git a/Client Applications/rcracki_mt/rcracki_mt.ini b/Client Applications/rcracki_mt/rcracki_mt.ini
new file mode 100644 (file)
index 0000000..17edb0a
--- /dev/null
@@ -0,0 +1,33 @@
+# Default settings for rcracki_mt
+# Command line arguments override these defaults
+
+# Specify default amount of threads
+Threads=1
+
+# Set a default file to store temporary results.
+# Set AlwaysStoreResultsToFile=1 or use -o to actually store results.
+DefaultResultsFile=e:\default_rcracki_results.txt
+
+# This option requires DefaultResultsFile to be set to a file
+#AlwaysStoreResultsToFile=1
+
+# Set some default file locations to search for rainbow tables.
+# You need to use these in combination with the command line argument -a [algorithm]
+# Or you can set a default algorithm here with 'DefaultAlgorithm'.
+# Algorithm is the name you use as specifier after 'DefaultRainbowTablesPath.'
+# You can specify multiple lines per algorithm, one path/directory per line.
+# Any locations you specify on the command line will be added to the list as well.
+# For Windows users: locations in this file with a different case
+#   as on the command line are treated as separate locations (run through twice)
+#DefaultRainbowTablePath.MD5=X:\RTI\MD5
+#DefaultRainbowTablePath.NTLM=X:\RTI\NTLM\ntlm_loweralpha-space#1-9_*
+
+# This option requires at least one 'DefaultRainbowTablePath.[algorithm]' to be set
+#DefaultAlgorithm=MD5
+
+# Always show debugging infomation (command line option -v)
+# AlwaysDebug=1
+
+# Always keep precalculation files after cracking, don't remove them.
+# These files are saved by session name. So you can store precalculations over multiple jobs.
+#AlwaysKeepPrecalcFiles=1
\ No newline at end of file
diff --git a/Client Applications/rcracki_mt/rcracki_mt.sln b/Client Applications/rcracki_mt/rcracki_mt.sln
new file mode 100644 (file)
index 0000000..d323c38
--- /dev/null
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcracki_mt", "rcracki_mt.vcproj", "{D484ABA1-C117-4AB1-B361-22E5EA62FA00}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {D484ABA1-C117-4AB1-B361-22E5EA62FA00}.Debug|Win32.ActiveCfg = Debug|Win32
+               {D484ABA1-C117-4AB1-B361-22E5EA62FA00}.Debug|Win32.Build.0 = Debug|Win32
+               {D484ABA1-C117-4AB1-B361-22E5EA62FA00}.Release|Win32.ActiveCfg = Release|Win32
+               {D484ABA1-C117-4AB1-B361-22E5EA62FA00}.Release|Win32.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/Client Applications/rcracki_mt/rcracki_mt.suo b/Client Applications/rcracki_mt/rcracki_mt.suo
new file mode 100644 (file)
index 0000000..12af4a6
Binary files /dev/null and b/Client Applications/rcracki_mt/rcracki_mt.suo differ
diff --git a/Client Applications/rcracki_mt/rcracki_mt.vcproj b/Client Applications/rcracki_mt/rcracki_mt.vcproj
new file mode 100644 (file)
index 0000000..53f7498
--- /dev/null
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="9,00"
+       Name="rcracki_mt"
+       ProjectGUID="{D484ABA1-C117-4AB1-B361-22E5EA62FA00}"
+       RootNamespace="rcracki_mt"
+       Keyword="Win32Proj"
+       TargetFrameworkVersion="196613"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+                       IntermediateDirectory="$(ConfigurationName)"
+                       ConfigurationType="1"
+                       CharacterSet="0"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="&quot;C:\Users\mwj\git\others\openssl-0.9.8k\include&quot;;&quot;C:\Users\mwj\git\others\pthreads-w32-2-8-0-release&quot;"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="3"
+                               UsePrecompiledHeader="0"
+                               WarningLevel="3"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libeay32.lib pthreadVC2.lib"
+                               LinkIncremental="2"
+                               GenerateDebugInformation="true"
+                               SubSystem="1"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+                       IntermediateDirectory="$(ConfigurationName)"
+                       ConfigurationType="1"
+                       CharacterSet="0"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               EnableIntrinsicFunctions="true"
+                               AdditionalIncludeDirectories="&quot;C:\Users\mwj\git\others\openssl-0.9.8k\include&quot;;&quot;C:\Users\mwj\git\others\pthreads-w32-2-8-0-release&quot;"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+                               RuntimeLibrary="2"
+                               EnableFunctionLevelLinking="true"
+                               UsePrecompiledHeader="0"
+                               WarningLevel="3"
+                               DebugInformationFormat="3"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libeay32.lib pthreadVC2.lib"
+                               LinkIncremental="1"
+                               GenerateDebugInformation="true"
+                               SubSystem="1"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\BaseRTReader.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\ChainWalkContext.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\ChainWalkSet.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\CrackEngine.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\fast_md5.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashAlgorithm.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashRoutine.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashSet.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\lm2ntlm.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\md4.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\MemoryPool.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\Public.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\RainbowCrack.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\rcrackiThread.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\RTI2Reader.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\sha1.cpp"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Header Files"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\BaseRTReader.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\ChainWalkContext.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\ChainWalkSet.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\CrackEngine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\fast_md5.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashAlgorithm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashRoutine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\HashSet.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\lm2ntlm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\md4.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\MemoryPool.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\Public.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\rcrackiThread.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\RTI2Reader.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\sha1.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Resource Files"
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/Client Applications/rcracki_mt/sha1.cpp b/Client Applications/rcracki_mt/sha1.cpp
new file mode 100644 (file)
index 0000000..339ebb9
--- /dev/null
@@ -0,0 +1,355 @@
+//#include <stdio.h>
+#if defined(WIN32)
+#include <windows.h>
+#endif
+#include <string.h>
+
+
+
+#define SHA1CircularShift(bits,word) (((word) << (bits)) | ((word) >> (32-(bits))))
+
+// this rotate isn't faster with me
+#if defined(WIN32)
+#define ROTATE(a,n)     _lrotl(a,n)
+#else
+#define ROTATE(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#if defined(WIN32)
+/* 5 instructions with rotate instruction, else 9 */
+#define Endian_Reverse32(a) \
+       { \
+       unsigned long l=(a); \
+       (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \
+       }
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define Endian_Reverse32(a) \
+       { \
+       unsigned long l=(a); \
+       l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \
+       (a)=ROTATE(l,16L); \
+       }
+#endif
+
+#define        F_00_19(b,c,d)  ((((c) ^ (d)) & (b)) ^ (d)) 
+#define        F_20_39(b,c,d)  ((b) ^ (c) ^ (d))
+#define F_40_59(b,c,d) (((b) & (c)) | (((b)|(c)) & (d))) 
+#define        F_60_79(b,c,d)  F_20_39(b,c,d)
+
+#define K0 0x5A827999
+#define K1 0x6ED9EBA1
+#define K2 0x8F1BBCDC
+#define K3 0xCA62C1D6
+
+#define H0 0x67452301
+#define H1 0xEFCDAB89
+#define H2 0x98BADCFE
+#define H3 0x10325476
+#define H4 0xC3D2E1F0
+
+typedef unsigned int UINT4;
+#define SHA1HashSize 20
+
+void SHA1_NEW( unsigned char * pData, int length, unsigned char * pDigest)
+{
+       if (length > 16)
+               return;
+
+    UINT4 Message_Block_Index    = 0;
+
+       union
+       {
+               unsigned char Message_Block[64];
+               UINT4 Message_Block_W[16];
+       };
+
+       Message_Block_W[0] = 0x00000000;
+       Message_Block_W[1] = 0x00000000;
+       Message_Block_W[2] = 0x00000000;
+       Message_Block_W[3] = 0x00000000;
+       Message_Block_W[4] = 0x00000000;
+
+       UINT4 Intermediate_Hash[5] = { H0, H1, H2, H3, H4 };
+       
+       memcpy(Message_Block, pData, length);
+       Message_Block_Index += length;
+
+       //padMessage
+       Message_Block[length] = 0x80;
+       
+       UINT4 W_15 = length << 3;
+       
+    int           t;                 /* Loop counter                */
+    UINT4      temp;              /* Temporary word value        */
+    UINT4      W[80];             /* Word sequence               */
+    UINT4      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     *  Initialize the first 16 words in the array W
+     */
+
+       #define INIT_OLD(x) \
+        W[x] = (Message_Block[(x) * 4] << 24) | \
+               (Message_Block[(x) * 4 + 1] << 16) | \
+               (Message_Block[(x) * 4 +2] << 8) | \
+               (Message_Block[(x) * 4 +3])
+
+       #define INIT(x) W[x] = Message_Block_W[x];
+       
+       #define INIT_NULL(x) W[x] = 0;
+
+       
+       Endian_Reverse32(Message_Block_W[0]);
+       INIT(0);
+
+       #define INIT_NULL_1_14 \
+               INIT_NULL(1);  INIT_NULL_2_14;
+
+       #define INIT_NULL_2_14 \
+               INIT_NULL(2);  INIT_NULL_3_14;
+
+       #define INIT_NULL_3_14 \
+               INIT_NULL(3);  INIT_NULL_4_14;
+
+       #define INIT_NULL_4_14 \
+               INIT_NULL(4); INIT_NULL_5_14;
+
+       #define INIT_NULL_5_14 \
+               INIT_NULL(5);  INIT_NULL(6);  INIT_NULL(7); \
+               INIT_NULL(8);  INIT_NULL(9);  INIT_NULL(10); INIT_NULL(11); \
+               INIT_NULL(12); INIT_NULL(13); INIT_NULL(14);
+
+       #define ROTATE1_NULL_1_14 \
+               ROTATE1_NULL;  ROTATE1_NULL_2_14;
+
+       #define ROTATE1_NULL_2_14 \
+               ROTATE1_NULL;  ROTATE1_NULL_3_14;
+
+       #define ROTATE1_NULL_3_14 \
+               ROTATE1_NULL;  ROTATE1_NULL_4_14;
+
+       #define ROTATE1_NULL_4_14 \
+               ROTATE1_NULL; ROTATE1_NULL_5_14;
+
+       #define ROTATE1_NULL_5_14 \
+               ROTATE1_NULL; ROTATE1_NULL; ROTATE1_NULL; \
+               ROTATE1_NULL; ROTATE1_NULL; ROTATE1_NULL; ROTATE1_NULL; \
+               ROTATE1_NULL; ROTATE1_NULL; ROTATE1_NULL;
+
+
+       #define EXPAND(t) \
+               W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); \
+
+       #define EXPAND_3(t) W[t] = SHA1CircularShift(1,W[t-3]);
+       #define EXPAND_16(t) W[t] = SHA1CircularShift(1,W[t-16]);
+       #define EXPAND_3_8(t) W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8]);
+
+
+       if (length < 4) {
+               INIT_NULL_1_14;
+               W[15] = W_15;
+               EXPAND_16(16);
+               W[17] = 0;
+               W[18] = W_15<<1;
+       }
+       else if (length < 8) {
+               Endian_Reverse32(Message_Block_W[1]);
+               INIT(1);
+               INIT_NULL_2_14;
+               W[15] = W_15;
+               EXPAND_16(16);
+               EXPAND_16(17);
+               W[18] = W_15<<1;
+       }
+       else {
+               Endian_Reverse32(Message_Block_W[1]);
+               Endian_Reverse32(Message_Block_W[2]);
+               Endian_Reverse32(Message_Block_W[3]);
+               Endian_Reverse32(Message_Block_W[4]);
+               INIT(1); INIT(2); INIT(3); INIT(4); 
+               INIT_NULL_5_14;
+               W[15] = W_15;
+               EXPAND(16);
+               EXPAND(17);
+               EXPAND(18);
+       }
+
+
+       if (length < 12) {
+               EXPAND_3(19);
+       }
+       else {
+               EXPAND(19);
+       }
+
+       if (length < 16) {
+               EXPAND_3(20);
+       }
+       else {
+               EXPAND(20);
+       }
+       EXPAND_3(21); EXPAND_3(22);
+       EXPAND(23);
+
+       EXPAND(24); EXPAND(25); EXPAND_3_8(26); EXPAND_3_8(27);
+       EXPAND(28);     EXPAND(29);     EXPAND(30);     EXPAND(31);
+       EXPAND(32);     EXPAND(33);     EXPAND(34);     EXPAND(35);
+       EXPAND(36);     EXPAND(37);     EXPAND(38);     EXPAND(39);
+       EXPAND(40);     EXPAND(41);     EXPAND(42);     EXPAND(43);
+       EXPAND(44);     EXPAND(45);     EXPAND(46);     EXPAND(47);
+       EXPAND(48);     EXPAND(49);     EXPAND(50);     EXPAND(51);
+       EXPAND(52);     EXPAND(53);     EXPAND(54);     EXPAND(55);
+       EXPAND(56);     EXPAND(57);     EXPAND(58);     EXPAND(59);
+       EXPAND(60);     EXPAND(61);     EXPAND(62);     EXPAND(63);
+       EXPAND(64);     EXPAND(65);     EXPAND(66);     EXPAND(67);
+       EXPAND(68);     EXPAND(69);     EXPAND(70);     EXPAND(71);
+       EXPAND(72);     EXPAND(73);     EXPAND(74);     EXPAND(75);
+       EXPAND(76);     EXPAND(77);     EXPAND(78);     EXPAND(79);
+
+
+       #define ROTATE1(t) \
+                       temp = SHA1CircularShift(5,A) + F_00_19(B,C,D) + E + W[t] + K0; \
+                       E = D; D = C; \
+                       C = SHA1CircularShift(30,B); \
+                       B = A; A = temp; \
+
+       #define ROTATE1_NEW(a, b, c, d, e, x) \
+                       e += SHA1CircularShift(5,a) + F_00_19(b,c,d) + x + K0; \
+                       b = SHA1CircularShift(30,b);
+
+       #define ROTATE1_W(w) \
+                       temp = SHA1CircularShift(5,A) + F_00_19(B,C,D) + E + w + K0; \
+                       E = D; D = C; \
+                       C = SHA1CircularShift(30,B); \
+                       B = A; A = temp;
+
+       #define ROTATE1_NULL \
+                       temp = SHA1CircularShift(5,A) + F_00_19(B,C,D) + E + K0; \
+                       E = D; D = C; \
+                       C = SHA1CircularShift(30,B); \
+                       B = A; A = temp; \
+                       
+       #define ROTATE2_NEW(a, b, c, d, e, x) \
+                       e += SHA1CircularShift(5,a) + F_20_39(b,c,d) + x + K1; \
+                       b = SHA1CircularShift(30,b);
+       
+       #define ROTATE2(t) \
+               temp = SHA1CircularShift(5,A) + F_20_39(B,C,D) + E + W[t] + K1; \
+        E = D; D = C; \
+        C = SHA1CircularShift(30,B); \
+        B = A; A = temp;
+
+       #define ROTATE2_W(w) \
+               temp = SHA1CircularShift(5,A) + F_20_39(B,C,D) + E + w + K1; \
+        E = D; D = C; \
+        C = SHA1CircularShift(30,B); \
+        B = A; A = temp;
+
+       #define ROTATE3(t) \
+               temp = SHA1CircularShift(5,A) + F_40_59(B,C,D) + E + W[t] + K2; \
+        E = D; D = C; \
+        C = SHA1CircularShift(30,B); \
+        B = A; A = temp;
+
+       #define ROTATE4(t) \
+               temp = SHA1CircularShift(5,A) + F_60_79(B,C,D) + E + W[t] + K3; \
+               E = D; D = C; \
+               C = SHA1CircularShift(30,B); \
+               B = A; A = temp;
+
+       A = H0;
+    B = H1;
+    C = H2;
+    D = H3;
+    E = H4;
+
+       
+       E = H2;
+       //D = 2079550178;
+       //C = 1506887872;
+       B = 2679412915 + W[0];
+       if (length < 4) {
+               A = SHA1CircularShift(5,B) + 1722862861;
+       }
+       else {
+               A = SHA1CircularShift(5,B) + 1722862861 + W[1];
+       }
+
+       if (length < 8) {
+               temp = SHA1CircularShift(5,A) + ((((1506887872) ^ (2079550178)) & (B)) ^ (2079550178)) + H2 + K0;
+       }
+       else {
+               temp = SHA1CircularShift(5,A) + (((572662306) & (B)) ^ (2079550178)) + H2 + K0 + W[2];
+       }
+       C = SHA1CircularShift(30,B);  //SHA1CircularShift(30,(2679412915 + W[0]));
+       B = A;
+       A = temp;
+       
+       if (length < 12) {
+               temp = SHA1CircularShift(5,A) + ((((C) ^ (1506887872)) & (B)) ^ (1506887872)) + 2079550178 + K0;
+       }
+       else {
+               temp = SHA1CircularShift(5,A) + ((((C) ^ (1506887872)) & (B)) ^ (1506887872)) + 2079550178 + K0 + W[3];
+       }
+       E = 1506887872;
+       D = C;
+       C = SHA1CircularShift(30,B);
+       B = A;
+       A = temp;
+
+       if (length < 16) {
+               temp = SHA1CircularShift(5,A) + F_00_19(B,C,D) + 1506887872 + K0;
+       }
+       else {
+               temp = SHA1CircularShift(5,A) + F_00_19(B,C,D) + 1506887872 + K0 + W[4];
+       }
+       E = D;
+       D = C;
+       C = SHA1CircularShift(30,B);
+       B = A;
+       A = temp;
+
+       ROTATE1_NULL_5_14;
+
+       ROTATE1_NEW( A, B, C, D, E, W_15 );
+    ROTATE1_NEW( E, A, B, C, D, W[16] );
+    ROTATE1_NEW( D, E, A, B, C, W[17] );
+    ROTATE1_NEW( C, D, E, A, B, W[18] );
+    ROTATE1_NEW( B, C, D, E, A, W[19] );
+       
+    for(t = 20; t < 40; t++)
+    {
+               if (t == 21 && length < 8) {
+                       ROTATE2_W((length<<5)); // *32
+               }
+               else {
+                       ROTATE2(t);
+               }
+    }
+
+    for(t = 40; t < 60; t++)
+    {
+               ROTATE3(t);
+    }
+
+    for(t = 60; t < 80; t++)
+    {
+               ROTATE4(t);
+    }
+
+    Intermediate_Hash[0] += A;
+    Intermediate_Hash[1] += B;
+    Intermediate_Hash[2] += C;
+    Intermediate_Hash[3] += D;
+    Intermediate_Hash[4] += E;
+
+       Endian_Reverse32(Intermediate_Hash[0]);
+       Endian_Reverse32(Intermediate_Hash[1]);
+       Endian_Reverse32(Intermediate_Hash[2]);
+       Endian_Reverse32(Intermediate_Hash[3]);
+       Endian_Reverse32(Intermediate_Hash[4]);
+
+       memcpy(pDigest, Intermediate_Hash, 20);
+}
diff --git a/Client Applications/rcracki_mt/sha1.h b/Client Applications/rcracki_mt/sha1.h
new file mode 100644 (file)
index 0000000..e10a64b
--- /dev/null
@@ -0,0 +1 @@
+void SHA1_NEW( unsigned char * pData, int length, unsigned char * pDigest);