2 RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
4 Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
8 #pragma warning(disable : 4786)
11 #include "ChainWalkContext.h"
14 #include <openssl/rand.h>
16 #pragma comment(lib, "libeay32.lib")
19 //////////////////////////////////////////////////////////////////////
21 string CChainWalkContext::m_sHashRoutineName;
22 HASHROUTINE CChainWalkContext::m_pHashRoutine;
23 int CChainWalkContext::m_nHashLen;
24 int CChainWalkContext::m_nPlainLenMinTotal = 0;
25 int CChainWalkContext::m_nPlainLenMaxTotal = 0;
26 int CChainWalkContext::m_nHybridCharset = 0;
27 vector<stCharset> CChainWalkContext::m_vCharset;
28 uint64 CChainWalkContext::m_nPlainSpaceUpToX[MAX_PLAIN_LEN + 1];
29 uint64 CChainWalkContext::m_nPlainSpaceTotal;
30 unsigned char CChainWalkContext::m_Salt[MAX_SALT_LEN];
31 int CChainWalkContext::m_nSaltLen = 0;
32 int CChainWalkContext::m_nRainbowTableIndex;
33 uint64 CChainWalkContext::m_nReduceOffset;
35 //////////////////////////////////////////////////////////////////////
37 CChainWalkContext::CChainWalkContext()
41 CChainWalkContext::~CChainWalkContext()
45 bool CChainWalkContext::LoadCharset(string sName)
52 for (i = 0x00; i <= 0xff; i++)
53 tCharset.m_PlainCharset[i] = i;
54 tCharset.m_nPlainCharsetLen = 256;
55 tCharset.m_sPlainCharsetName = sName;
56 tCharset.m_sPlainCharsetContent = "0x00, 0x01, ... 0xff";
57 m_vCharset.push_back(tCharset);
60 if(sName.substr(0, 6) == "hybrid") // Hybrid charset consisting of 2 charsets
65 if (ReadLinesFromFile(CHARSET_TXT, vLine))
68 for (i = 0; i < vLine.size(); i++)
71 if (vLine[i][0] == '#')
75 if (SeperateString(vLine[i], "=", vPart))
78 string sCharsetName = TrimString(vPart[0]);
79 if (sCharsetName == "")
82 // sCharsetName charset check
83 bool fCharsetNameCheckPass = true;
85 for (j = 0; j < sCharsetName.size(); j++)
87 if ( !isalpha(sCharsetName[j])
88 && !isdigit(sCharsetName[j])
89 && (sCharsetName[j] != '-'))
91 fCharsetNameCheckPass = false;
95 if (!fCharsetNameCheckPass)
97 printf("invalid charset name %s in charset configuration file\n", sCharsetName.c_str());
102 string sCharsetContent = TrimString(vPart[1]);
103 if (sCharsetContent == "" || sCharsetContent == "[]")
105 if (sCharsetContent[0] != '[' || sCharsetContent[sCharsetContent.size() - 1] != ']')
107 printf("invalid charset content %s in charset configuration file\n", sCharsetContent.c_str());
110 sCharsetContent = sCharsetContent.substr(1, sCharsetContent.size() - 2);
111 if (sCharsetContent.size() > 256)
113 printf("charset content %s too long\n", sCharsetContent.c_str());
117 //printf("%s = [%s]\n", sCharsetName.c_str(), sCharsetContent.c_str());
119 // Is it the wanted charset?
120 if(m_nHybridCharset == 1)
122 vector<tCharset> vCharsets;
123 GetHybridCharsets(sName, vCharsets);
124 if(sCharsetName == vCharsets[m_vCharset.size()].sName)
126 stCharset tCharset = {0};
127 tCharset.m_nPlainCharsetLen = sCharsetContent.size();
128 memcpy(tCharset.m_PlainCharset, sCharsetContent.c_str(), tCharset.m_nPlainCharsetLen);
129 tCharset.m_sPlainCharsetName = sCharsetName;
130 tCharset.m_sPlainCharsetContent = sCharsetContent;
131 tCharset.m_nPlainLenMin = vCharsets[m_vCharset.size()].nPlainLenMin;
132 tCharset.m_nPlainLenMax = vCharsets[m_vCharset.size()].nPlainLenMax;
133 m_vCharset.push_back(tCharset);
134 if(vCharsets.size() == m_vCharset.size())
136 i = 0; // Start the lookup over again for the next charset
139 else if (sCharsetName == sName)
142 tCharset.m_nPlainCharsetLen = sCharsetContent.size();
143 memcpy(tCharset.m_PlainCharset, sCharsetContent.c_str(), tCharset.m_nPlainCharsetLen);
144 tCharset.m_sPlainCharsetName = sCharsetName;
145 tCharset.m_sPlainCharsetContent = sCharsetContent;
146 m_vCharset.push_back(tCharset);
151 printf("charset %s not found in charset.txt\n", sName.c_str());
154 printf("can't open charset configuration file\n");
158 //////////////////////////////////////////////////////////////////////
160 bool CChainWalkContext::SetHashRoutine(string sHashRoutineName)
163 hr.GetHashRoutine(sHashRoutineName, m_pHashRoutine, m_nHashLen);
164 if (m_pHashRoutine != NULL)
166 m_sHashRoutineName = sHashRoutineName;
173 bool CChainWalkContext::SetPlainCharset(string sCharsetName, int nPlainLenMin, int nPlainLenMax)
175 // m_PlainCharset, m_nPlainCharsetLen, m_sPlainCharsetName, m_sPlainCharsetContent
176 if (!LoadCharset(sCharsetName))
179 if(m_vCharset.size() == 1) // Not hybrid charset
181 // m_nPlainLenMin, m_nPlainLenMax
182 if (nPlainLenMin < 1 || nPlainLenMax > MAX_PLAIN_LEN || nPlainLenMin > nPlainLenMax)
184 printf("invalid plaintext length range: %d - %d\n", nPlainLenMin, nPlainLenMax);
187 m_vCharset[0].m_nPlainLenMin = nPlainLenMin;
188 m_vCharset[0].m_nPlainLenMax = nPlainLenMax;
190 // m_nPlainSpaceUpToX
191 m_nPlainSpaceUpToX[0] = 0;
192 m_nPlainLenMaxTotal = 0;
193 m_nPlainLenMinTotal = 0;
196 for(j = 0; j < m_vCharset.size(); j++)
199 m_nPlainLenMaxTotal += m_vCharset[j].m_nPlainLenMax;
200 m_nPlainLenMinTotal += m_vCharset[j].m_nPlainLenMin;
201 for (i = 1; i <= m_vCharset[j].m_nPlainLenMax; i++)
203 nTemp *= m_vCharset[j].m_nPlainCharsetLen;
204 if (i < m_vCharset[j].m_nPlainLenMin)
205 m_nPlainSpaceUpToX[k] = 0;
207 m_nPlainSpaceUpToX[k] = m_nPlainSpaceUpToX[k - 1] + nTemp;
211 // m_nPlainSpaceTotal
212 m_nPlainSpaceTotal = m_nPlainSpaceUpToX[m_nPlainLenMaxTotal];
217 bool CChainWalkContext::SetRainbowTableIndex(int nRainbowTableIndex)
219 if (nRainbowTableIndex < 0)
221 m_nRainbowTableIndex = nRainbowTableIndex;
222 m_nReduceOffset = 65536 * nRainbowTableIndex;
227 bool CChainWalkContext::SetSalt(unsigned char *Salt, int nSaltLength)
229 memcpy(&m_Salt[0], Salt, nSaltLength);
231 m_nSaltLen = nSaltLength;
236 bool CChainWalkContext::SetupWithPathName(string sPathName, int& nRainbowChainLen, int& nRainbowChainCount)
238 // something like lm_alpha#1-7_0_100x16_test.rt
241 int nIndex = sPathName.find_last_of('\\');
243 int nIndex = sPathName.find_last_of('/');
246 sPathName = sPathName.substr(nIndex + 1);
248 if (sPathName.size() < 3)
250 printf("%s is not a rainbow table\n", sPathName.c_str());
254 if (sPathName.substr(sPathName.size() - 4) != ".rti")
256 printf("%s is not a rainbow table\n", sPathName.c_str());
261 vector<string> vPart;
262 if (!SeperateString(sPathName, "___x_", vPart))
264 printf("filename %s not identified\n", sPathName.c_str());
268 string sHashRoutineName = vPart[0];
269 int nRainbowTableIndex = atoi(vPart[2].c_str());
270 nRainbowChainLen = atoi(vPart[3].c_str());
271 nRainbowChainCount = atoi(vPart[4].c_str());
273 // Parse charset definition
274 string sCharsetDefinition = vPart[1];
276 int nPlainLenMin = 0, nPlainLenMax = 0;
278 // printf("Charset: %s", sCharsetDefinition.c_str());
280 if(sCharsetDefinition.substr(0, 6) == "hybrid") // Hybrid table
282 sCharsetName = sCharsetDefinition;
286 if (sCharsetDefinition.find('#') == -1) // For backward compatibility, "#1-7" is implied
288 sCharsetName = sCharsetDefinition;
294 vector<string> vCharsetDefinitionPart;
295 if (!SeperateString(sCharsetDefinition, "#-", vCharsetDefinitionPart))
297 printf("filename %s not identified\n", sPathName.c_str());
302 sCharsetName = vCharsetDefinitionPart[0];
303 nPlainLenMin = atoi(vCharsetDefinitionPart[1].c_str());
304 nPlainLenMax = atoi(vCharsetDefinitionPart[2].c_str());
309 if (!SetHashRoutine(sHashRoutineName))
311 printf("hash routine %s not supported\n", sHashRoutineName.c_str());
314 if (!SetPlainCharset(sCharsetName, nPlainLenMin, nPlainLenMax))
316 if (!SetRainbowTableIndex(nRainbowTableIndex))
318 printf("invalid rainbow table index %d\n", nRainbowTableIndex);
321 m_nPlainSpaceTotal = m_nPlainSpaceUpToX[m_nPlainLenMaxTotal];
325 string CChainWalkContext::GetHashRoutineName()
327 return m_sHashRoutineName;
330 int CChainWalkContext::GetHashLen()
335 string CChainWalkContext::GetPlainCharsetName()
337 return m_vCharset[0].m_sPlainCharsetName;
340 string CChainWalkContext::GetPlainCharsetContent()
342 return m_vCharset[0].m_sPlainCharsetContent;
345 int CChainWalkContext::GetPlainLenMin()
347 return m_vCharset[0].m_nPlainLenMin;
350 int CChainWalkContext::GetPlainLenMax()
352 return m_vCharset[0].m_nPlainLenMax;
355 uint64 CChainWalkContext::GetPlainSpaceTotal()
357 return m_nPlainSpaceTotal;
360 int CChainWalkContext::GetRainbowTableIndex()
362 return m_nRainbowTableIndex;
365 void CChainWalkContext::Dump()
367 printf("hash routine: %s\n", m_sHashRoutineName.c_str());
368 printf("hash length: %d\n", m_nHashLen);
370 printf("plain charset: ");
372 for (i = 0; i < m_vCharset[0].m_nPlainCharsetLen; i++)
374 if (isprint(m_vCharset[0].m_PlainCharset[i]))
375 printf("%c", m_vCharset[0].m_PlainCharset[i]);
381 printf("plain charset in hex: ");
382 for (i = 0; i < m_vCharset[0].m_nPlainCharsetLen; i++)
383 printf("%02x ", m_vCharset[0].m_PlainCharset[i]);
386 printf("plain length range: %d - %d\n", m_vCharset[0].m_nPlainLenMin, m_vCharset[0].m_nPlainLenMax);
387 printf("plain charset name: %s\n", m_vCharset[0].m_sPlainCharsetName.c_str());
388 //printf("plain charset content: %s\n", m_sPlainCharsetContent.c_str());
389 //for (i = 0; i <= m_nPlainLenMax; i++)
390 // printf("plain space up to %d: %s\n", i, uint64tostr(m_nPlainSpaceUpToX[i]).c_str());
391 printf("plain space total: %s\n", uint64tostr(m_nPlainSpaceTotal).c_str());
393 printf("rainbow table index: %d\n", m_nRainbowTableIndex);
394 printf("reduce offset: %s\n", uint64tostr(m_nReduceOffset).c_str());
398 void CChainWalkContext::GenerateRandomIndex()
400 RAND_bytes((unsigned char*)&m_nIndex, 8);
401 m_nIndex = m_nIndex % m_nPlainSpaceTotal;
404 void CChainWalkContext::SetIndex(uint64 nIndex)
409 void CChainWalkContext::SetHash(unsigned char* pHash)
411 memcpy(m_Hash, pHash, m_nHashLen);
414 void CChainWalkContext::IndexToPlain()
418 for (i = m_nPlainLenMaxTotal - 1; i >= m_nPlainLenMinTotal - 1; i--)
420 if (m_nIndex >= m_nPlainSpaceUpToX[i])
427 m_nPlainLen = m_nPlainLenMinTotal;
428 uint64 nIndexOfX = m_nIndex - m_nPlainSpaceUpToX[m_nPlainLen - 1];
433 for (i = m_nPlainLen - 1; i >= 0; i--)
436 for(int j = 0; j < m_vCharset.size(); i++)
438 nCharsetLen += m_vCharset[j].m_nPlainLenMax;
439 if(i < nCharsetLen) // We found the correct charset
441 m_Plain[i] = m_vCharset[j].m_PlainCharset[nIndexOfX % m_nPlainCharsetLen];
442 nIndexOfX /= m_vCharset[j].m_nPlainCharsetLen;
450 for (i = m_nPlainLen - 1; i >= 0; i--)
453 if (nIndexOfX < 0x100000000I64)
456 if (nIndexOfX < 0x100000000llu)
460 for(int j = 0; j < m_vCharset.size(); j++)
462 nCharsetLen += m_vCharset[j].m_nPlainLenMax;
463 if(i < nCharsetLen) // We found the correct charset
465 m_Plain[i] = m_vCharset[j].m_PlainCharset[nIndexOfX % m_vCharset[j].m_nPlainCharsetLen];
466 nIndexOfX /= m_vCharset[j].m_nPlainCharsetLen;
472 unsigned int nIndexOfX32 = (unsigned int)nIndexOfX;
476 for(int j = 0; j < m_vCharset.size(); j++)
478 nCharsetLen += m_vCharset[j].m_nPlainLenMax;
479 if(i < nCharsetLen) // We found the correct charset
482 // m_Plain[i] = m_PlainCharset[nIndexOfX32 % m_vCharset[j].m_nPlainCharsetLen];
483 // nIndexOfX32 /= m_vCharset[j].m_nPlainCharsetLen;
485 unsigned int nPlainCharsetLen = m_vCharset[j].m_nPlainCharsetLen;
496 m_Plain[i] = m_vCharset[j].m_PlainCharset[nTemp];
498 __asm__ __volatile__ ( "mov %2, %%eax;"
503 : "=m"(nIndexOfX32), "=m"(nTemp)
504 : "m"(nIndexOfX32), "m"(nPlainCharsetLen)
507 m_Plain[i] = m_vCharset[j].m_PlainCharset[nTemp];
516 void CChainWalkContext::PlainToHash()
518 m_pHashRoutine(m_Plain, m_nPlainLen, m_Hash);
521 void CChainWalkContext::HashToIndex(int nPos)
523 m_nIndex = (*(uint64*)m_Hash + m_nReduceOffset + nPos) % m_nPlainSpaceTotal;
526 uint64 CChainWalkContext::GetIndex()
530 const uint64 *CChainWalkContext::GetIndexPtr()
535 string CChainWalkContext::GetPlain()
539 for (i = 0; i < m_nPlainLen; i++)
542 if (c >= 32 && c <= 126)
551 string CChainWalkContext::GetBinary()
553 return HexToStr(m_Plain, m_nPlainLen);
556 string CChainWalkContext::GetPlainBinary()
561 for (i = 0; i < m_nPlainLenMax - m_nPlainLen; i++)
567 for (i = 0; i < m_nPlainLenMax - m_nPlainLen; i++)
573 string CChainWalkContext::GetHash()
575 return HexToStr(m_Hash, m_nHashLen);
578 bool CChainWalkContext::CheckHash(unsigned char* pHash)
580 if (memcmp(m_Hash, pHash, m_nHashLen) == 0)