]> git.sesse.net Git - freerainbowtables/blob - Server Applications/rsearchi/CrackEngine.cpp
initial
[freerainbowtables] / Server Applications / rsearchi / CrackEngine.cpp
1 /*
2    RainbowCrack - a general propose implementation of Philippe Oechslin's faster time-memory trade-off technique.
3
4    Copyright (C) Zhu Shuanglei <shuanglei@hotmail.com>
5 */
6
7 #ifdef _WIN32
8         #pragma warning(disable : 4786)
9 #endif
10
11 #include "CrackEngine.h"
12
13 #include <time.h>
14
15 CCrackEngine::CCrackEngine()
16 {
17         ResetStatistics();
18 }
19
20 CCrackEngine::~CCrackEngine()
21 {
22 }
23
24 //////////////////////////////////////////////////////////////////////
25
26 void CCrackEngine::ResetStatistics()
27 {
28         m_fTotalDiskAccessTime               = 0.0f;
29         m_fTotalCryptanalysisTime            = 0.0f;
30         m_nTotalChainWalkStep                = 0;
31         m_nTotalFalseAlarm                   = 0;
32         m_nTotalChainWalkStepDueToFalseAlarm = 0;
33 }
34
35 RainbowChain *CCrackEngine::BinarySearch(RainbowChain *pChain, int nChainCountRead, uint64 nIndex, IndexChain *pIndex, int nIndexSize, int nIndexStart)
36 {
37         uint64 nPrefix = nIndex >> 16;
38         int nLow, nHigh;        
39         //vector<RainbowChain> vChain;
40         //clock_t t1Search = clock();
41 //      for (int j = 0; j < vIndex.size(); j++)
42 //      {
43                 bool found = false;
44                 int nChains = 0;
45                 
46                 if(nPrefix > pIndex[nIndexSize-1].nPrefix) // check if its in the index file
47                 {
48                         return NULL;
49                 }
50                 /*
51                 clock_t t1Index = clock();              
52                 for(int i = 0; i < vIndexSize[j]; i++)
53                 {
54                         
55                         if(nPrefix > pIndex[i].nPrefix)
56                         {
57                 //              nChains += pIndex[i].nChainCount;
58                                 continue;
59                         }
60                         else if(nPrefix == pIndex[i].nPrefix)
61                         {
62                 //              nLow = nChains;
63                 //              nHigh = nLow + pIndex[i].nChainCount;
64                                 nLow = 5;
65                                 nHigh = 8;
66                 //              unsigned int nChunk = pIndex[i].nChainCount * 8;
67                                 //printf("prefix found %i. Limiting chunk size to %i chains\n", pIndex[i].nPrefix, pIndex[i].nChainCount);
68                                 found = true;
69                                 break;
70                         }
71                         else 
72                         {
73                                 break;
74                         }
75                 }
76                 clock_t t2Index = clock();
77                 m_fIndexSearchTime += 1.0f * (t2Index - t1Index) / CLOCKS_PER_SEC;
78                 */
79
80                 clock_t t1Index = clock();              
81                 int nBLow = 0;
82                 int nBHigh = nIndexSize - 1;
83                 while (nBLow <= nBHigh)
84                 {
85                         int nBMid = (nBLow + nBHigh) / 2;
86                         if (nPrefix == pIndex[nBMid].nPrefix)
87                         {
88                                 //nLow = nChains;
89                                 int nChains = 0;
90 /*                              for(int i = 0; i < nBMid; i++)
91                                 {
92                                         nChains += pIndex[i].nChainCount;
93                                 }*/
94
95                                 nLow = pIndex[nBMid].nFirstChain;
96                                 nHigh = nLow + pIndex[nBMid].nChainCount;
97                                 if(nLow >= nIndexStart && nLow <= nIndexStart + nChainCountRead) 
98                                 {                                       
99                                         if(nHigh > nIndexStart + nChainCountRead)
100                                                 nHigh = nIndexStart + nChainCountRead;
101                                 }
102                                 else if(nLow < nIndexStart && nHigh >= nIndexStart)
103                                 {
104                                         nLow = nIndexStart;
105                                 }
106                                 else break;                                     
107
108 //                              printf("Chain Count: %u\n", pIndex[nBMid].nChainCount);
109 //                              unsigned int nChunk = pIndex[nBMid].nChainCount * 8;
110                                 //printf("prefix found %i. Limiting chunk size to %i chains\n", pIndex[i].nPrefix, pIndex[i].nChainCount);
111
112                                 found = true;
113                                 break;
114                         }
115                         else if (nPrefix < pIndex[nBMid].nPrefix)
116                                 nBHigh = nBMid - 1;
117                         else
118                                 nBLow = nBMid + 1;
119                 }
120                 clock_t t2Index = clock();
121 //              m_fIndexSearchTime += 1.0f * (t2Index - t1Index) / CLOCKS_PER_SEC;
122
123 //              printf("Time: %.2f nLow: %i nHigh %i\n", (1.0f * (t2Index - t1Index) / CLOCKS_PER_SEC), nLow, nHigh);
124                 if(found == true)
125                 {
126 /*                      for(int i = 0; i < numChains; i++)
127                         {
128                                 RainbowChain *chains = new RainbowChain();
129                                 memcpy(chains, pChain[nLow + i], sizeof(RainbowChain));
130                         }*/
131 //                      printf("Numchains: %i ", numChains);
132                         //                      clock_t t1 = clock();
133                         if(pChain == NULL) // The chains are not preloaded. We need to seek the file for the chains
134                         {
135                                 int numChains = nHigh - nLow;
136                                 fseek(m_fChains, nLow * 8, SEEK_SET);
137                                 RainbowChain *tmpChain = (RainbowChain*) new unsigned char[numChains * sizeof(RainbowChain)];
138                                 memset(tmpChain, 0x00, numChains * sizeof(RainbowChain));
139                                 unsigned char *data = new unsigned char[numChains * 8];
140                                 fread(data, 1, numChains * 8, m_fChains);
141
142                                 for(int i = 0; i < numChains; i++)
143                                 {
144                                         memcpy(&tmpChain[i].nIndexS, &data[i * 8], 5);
145                                         memcpy(&tmpChain[i].nIndexE, &data[i * 8 + 5], 2);
146                                         memcpy(&tmpChain[i].nCheckPoint, &data[i * 8 + 7], 1);                          
147                                 }
148                                 for(int i = 0; i < numChains; i++)
149                                 {
150                                         // TODO: Seek to the position in the file, read the chains and check them
151                                         int nSIndex = ((int)nIndex) & 0x0000FFFF;                               
152                                         if (nSIndex == tmpChain[i].nIndexE)
153                                         {
154                                                 RainbowChain *chain = new RainbowChain();
155                                                 memcpy(chain, &tmpChain[i], sizeof(tmpChain));
156                                                 delete tmpChain;
157                                                 return chain;
158                                         }                               
159                                         else if(tmpChain[i].nIndexE > nSIndex)
160                                                 break;
161                                 }
162                                 delete tmpChain;
163                         }
164                         else
165                         {
166                                 for(int i = nLow - nIndexStart; i < nHigh - nIndexStart; i++)
167                                 {
168                                         // TODO: Seek to the position in the file, read the chains and check them
169                                         int nSIndex = ((int)nIndex) & 0x0000FFFF;                               
170                                         if (nSIndex == pChain[i].nIndexE)
171                                         {
172                                                 return &pChain[i];
173                                         }                               
174                                         else if(pChain[i].nIndexE > nSIndex)
175                                                 break;
176                                 }
177                         }
178                 }
179 //      }
180 //      clock_t t2Search = clock();
181 //      m_fIndexSearchTime += 1.0f * (t2Search - t1Search) / CLOCKS_PER_SEC;
182         
183         return NULL;
184 }
185
186
187 void CCrackEngine::SearchTableChunk(RainbowChain* pChain, int nRainbowChainLen, int nRainbowChainCount, CHashSet& hs, IndexChain *pIndex, int nIndexSize, int nChainStart)
188 {
189         vector<string> vHash;
190         vector<uint64 *> vIndices;
191         vector<RainbowChain *> vChains;
192         hs.GetLeftHashWithLen(vHash, vIndices, CChainWalkContext::GetHashLen());
193         printf("searching for %d hash%s...\n", vHash.size(),
194                                                                                    vHash.size() > 1 ? "es" : "");
195
196         int nChainWalkStep = 0;
197         int nFalseAlarm = 0;
198         int nChainWalkStepDueToFalseAlarm = 0;
199
200         int nHashIndex;
201         for (nHashIndex = 0; nHashIndex < vHash.size(); nHashIndex++)
202         {
203                 unsigned char TargetHash[MAX_HASH_LEN];
204                 int nHashLen;
205 //              printf("\nParsing hash...");
206                 ParseHash(vHash[nHashIndex], TargetHash, nHashLen);
207 //              printf("Done!\n");
208                 if (nHashLen != CChainWalkContext::GetHashLen())
209                         printf("debug: nHashLen mismatch\n");
210
211                 // Rqeuest ChainWalk
212                 bool fNewlyGenerated;
213 //              printf("Requesting walk...");
214                 //uint64* pStartPosIndexE = 
215                 uint64 *pStartPosIndexE = vIndices[nHashIndex];
216 /*
217                         m_cws.RequestWalk(TargetHash,
218                                                                                                         nHashLen,
219                                                                                                         CChainWalkContext::GetHashRoutineName(),
220                                                                                                         CChainWalkContext::GetPlainCharsetName(),
221                                                                                                         CChainWalkContext::GetPlainLenMin(),
222                                                                                                         CChainWalkContext::GetPlainLenMax(),
223                                                                                                         CChainWalkContext::GetRainbowTableIndex(),
224                                                                                                         nRainbowChainLen,
225                                                                                                         fNewlyGenerated);
226                                                                                                         */
227 //              printf("done!\n");
228 //              printf("debug: using %s walk for %s\n", fNewlyGenerated ? "newly generated" : "existing",
229 //                                                                                              vHash[nHashIndex].c_str());
230
231                 // Walk
232                 int nPos;
233                         /*
234                 if (fNewlyGenerated)
235                 {
236                         printf("Pregenerating index...");
237                         for (nPos = nRainbowChainLen - 2; nPos >= 0; nPos--)
238                         {
239
240                                         
241                                         CChainWalkContext cwc;
242                                         cwc.SetHash(TargetHash);
243                                         cwc.HashToIndex(nPos);
244                                         int i;
245                                         for (i = nPos + 1; i <= nRainbowChainLen - 2; i++)
246                                         {
247                                                 cwc.IndexToPlain();
248                                                 cwc.PlainToHash();
249                                                 cwc.HashToIndex(i);
250                                         }
251                                         pStartPosIndexE[nPos] = cwc.GetIndex();
252                                         nChainWalkStep += nRainbowChainLen - 2 - nPos;
253                         }
254                         printf("ok\n");
255
256                 }
257                 */
258                 
259                 for (nPos = nRainbowChainLen - 2; nPos >= 0; nPos--)
260                 {
261                         uint64 nIndexEOfCurPos = pStartPosIndexE[nPos];
262                 
263 //                      printf("%I64u,\n", nIndexEOfCurPos);
264                         
265                         // Search matching nIndexE
266                         RainbowChain *pChainFound = BinarySearch(pChain, nRainbowChainCount, nIndexEOfCurPos, pIndex, nIndexSize, nChainStart);
267                         if (pChainFound != NULL)
268                         {
269                                 
270                                 FoundRainbowChain chain; // Convert to FoundRainbowChain which allows us to add a line at which position we found the chain                             
271                                 memcpy(&chain, pChainFound, sizeof(RainbowChain));
272                                 chain.nGuessedPos = nPos;
273                                 hs.AddChain(vHash[nHashIndex], chain);
274                                 if(pChain == NULL) // We need to delete the chain because its only temporarily loaded
275                                         delete pChainFound;
276 /*                              int nMatchingIndexEFrom, nMatchingIndexETo;
277                                 GetChainIndexRangeWithSameEndpoint(pChain, nRainbowChainCount,
278                                                                                                    nMatchingIndexE,
279                                                                                                    nMatchingIndexEFrom, nMatchingIndexETo);
280                                                                                                    */
281 //                              int i;
282                         //      printf("%i - %i = \n", nMatchingIndexEFrom, nMatchingIndexETo, ((nMatchingIndexETo - nMatchingIndexEFrom) +1));
283 /*                              for (i = 0; i < vChain.size(); i++)
284 //                              {
285
286 /*                                      if (CheckAlarm(&vChain[i], nPos, TargetHash, hs))
287                                         {
288                                                 //printf("debug: discarding walk for %s\n", vHash[nHashIndex].c_str());
289                                                 //m_cws.DiscardWalk(pStartPosIndexE);
290                                                 goto NEXT_HASH;
291                                         }
292                                         else
293                                         {
294                                                 nChainWalkStepDueToFalseAlarm += nPos + 1;
295                                                 nFalseAlarm++;
296                                         }*/
297 //                              }
298                         }
299                 }
300 NEXT_HASH:;
301         }
302
303         //printf("debug: chain walk step: %d\n", nChainWalkStep);
304         //printf("debug: false alarm: %d\n", nFalseAlarm);
305         //printf("debug: chain walk step due to false alarm: %d\n", nChainWalkStepDueToFalseAlarm);
306 /*
307         m_nTotalChainWalkStep += nChainWalkStep;
308         m_nTotalFalseAlarm += nFalseAlarm;
309         m_nTotalChainWalkStepDueToFalseAlarm += nChainWalkStepDueToFalseAlarm;
310         */
311 }
312
313 void CCrackEngine::SearchRainbowTable(string sPathName, CHashSet& hs)
314 {
315         // FileName
316 #ifdef _WIN32
317         int nIndex = sPathName.find_last_of('\\');
318 #else
319         int nIndex = sPathName.find_last_of('/');
320 #endif
321         string sFileName;
322         if (nIndex != -1)
323                 sFileName = sPathName.substr(nIndex + 1);
324         else
325                 sFileName = sPathName;
326
327         // Info
328         printf("%s:\n", sFileName.c_str());
329
330         // Setup
331         int nRainbowChainLen, nRainbowChainCount;
332         if (!CChainWalkContext::SetupWithPathName(sPathName, nRainbowChainLen, nRainbowChainCount))
333                 return;
334
335         // Already finished?
336         if (!hs.AnyHashLeftWithLen(CChainWalkContext::GetHashLen()))
337         {
338                 printf("this table contains hashes with length %d only\n", CChainWalkContext::GetHashLen());
339                 return;
340         }
341
342         // Open
343         FILE* file = fopen(sPathName.c_str(), "rb");
344         if (file != NULL)
345         {
346                 // File length check
347                 unsigned int nFileLen = GetFileLen(file);
348                 if (nFileLen % 8 != 0 || nRainbowChainCount * 8 != nFileLen)
349                         printf("file length mismatch\n");
350                 else
351                 {
352                         FILE* fIndex = fopen(((string)(sPathName + string(".index"))).c_str(), "rb");
353                         IndexChain *pIndex = NULL;
354                         int nIndexSize = 0;
355                         if(fIndex != NULL)
356                         {
357                                 // File length check
358                                 unsigned int nTotalChainCount = nFileLen / 8;
359                                 unsigned int nIndexFileLen = GetFileLen(fIndex);
360
361                                 unsigned int nRows = nIndexFileLen / 11;
362                                 unsigned int nSize = nRows * sizeof(IndexChain);
363                                 if (nIndexFileLen % 11 != 0)
364                                         printf("index file length mismatch (%u bytes)\n", nIndexFileLen);
365                                 else
366                                 {
367                                         pIndex = (IndexChain*)new unsigned char[nSize];
368                                         memset(pIndex, 0x00, nSize);
369                                         fseek(fIndex, 0, SEEK_SET);
370                                         unsigned char *pData = new unsigned char[11];
371                                         int nRead = 0;
372                                         uint64 nLastPrefix = 0;
373                                         for(int i = 0; (i * 11) < nIndexFileLen; i++)
374                                         {
375                                                 nRead = fread(pData, 1, 11, fIndex);
376                                                 if(nRead == 11)
377                                                 {
378 //                                                      nDataRead += nRead;
379                                                         memcpy(&pIndex[i].nPrefix, &pData[0], 5);
380                                                         memcpy(&pIndex[i].nFirstChain, &pData[5], 4);
381                                                         memcpy(&pIndex[i].nChainCount, &pData[9], 2);
382                                                 }
383                                                 else break;
384                                                 // Index checking part
385                                                 if(i != 0 && pIndex[i].nFirstChain < pIndex[i-1].nFirstChain)
386                                                 {
387                                                         printf("Corrupted index detected (FirstChain is lower than previous)\n");
388                                                         exit(-1);
389                                                 }
390                                                 else if(i != 0 && pIndex[i].nFirstChain != pIndex[i-1].nFirstChain + pIndex[i-1].nChainCount)
391                                                 {
392                                                         printf("Corrupted index detected (LastChain + nChainCount != FirstChain)\n");
393                                                         exit(-1);
394                                                 }
395                                                 else if(pIndex[i].nPrefix < nLastPrefix)
396                                                 {
397                                                         printf("Corrupted index detected (Prefix is decreasing)\n");
398                                                         exit(-1);
399                                                 }
400                                                 nLastPrefix = pIndex[i].nPrefix;
401
402                                         }
403                                         nIndexSize = nRows;
404                                         if(pIndex[nIndexSize - 1].nFirstChain + pIndex[nIndexSize - 1].nChainCount + 1 <= nTotalChainCount) // +1 is needed.
405                                         {
406                                                 printf("Corrupted index detected: Not covering the entire file\n");
407                                                 exit(-1);
408                                         }
409                                         if(pIndex[nIndexSize - 1].nFirstChain + pIndex[nIndexSize - 1].nChainCount > nTotalChainCount) // +1 is not needed here
410                                         {
411                                                 printf("Corrupted index detected: The index is covering more than the file. Covering %u of %u chains\n", pIndex[nIndexSize - 1].nFirstChain + pIndex[nIndexSize - 1].nChainCount, nTotalChainCount);
412                                                 exit(-1);
413                                         }
414                                         fclose(fIndex);
415                                         delete pData;
416                                         printf("Index loaded successfully\n");
417                                 }               
418                         }
419                         else 
420                         {
421                                 printf("Can't load index\n");
422                                 return;
423                         }
424 /*                      if(hs.GetStatHashTotal() > 10)
425                         {*/
426                                 static CMemoryPool mp;
427                                 unsigned int nAllocatedSize;
428                                 RainbowChain* pChain = (RainbowChain*)mp.Allocate(nFileLen * 2, nAllocatedSize);
429                                 if (pChain != NULL)
430                                 {
431                                         nAllocatedSize = nAllocatedSize / 16 * 16;              // Round to 16-byte boundary
432
433                                         fseek(file, 0, SEEK_SET);
434                                         bool fVerified = false;
435                                         int nProcessedChains = 0;
436                                         while (true)    // Chunk read loop
437                                         {
438                                                 if (ftell(file) == nFileLen)
439                                                         break;
440
441                                                 // Load table chunk
442                                                 memset(pChain, 0x00, nAllocatedSize);
443                                                 printf("reading...\n");
444                                                 unsigned char *pData = new unsigned char[8];
445                                                 unsigned int nDataRead = 0;
446                                                 unsigned int nRead = 0;
447                                                 clock_t t1 = clock();
448                                                 for(int i = 0; i < nAllocatedSize / 16; i++) // Chain size is 16 bytes
449                                                 {
450                                                         nRead = fread(pData, 1, 8, file);
451                                                         if(nRead == 8)
452                                                         {
453                                                                 nDataRead += nRead;
454                                                                 memcpy(&pChain[i].nIndexS, &pData[0], 6);
455                                                                 memcpy(&pChain[i].nIndexE, &pData[6], 2);
456 //                                                              memcpy(&pChain[i].nCheckPoint, &pData[7], 1);                                           
457                                                         }
458                                                         else break;
459                                                 }
460                                                 clock_t t2 = clock();
461                                                 delete pData;
462         //                                      unsigned int nDataRead = fread(pChain, 1, nAllocatedSize, file);
463                                                 float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
464                                                 printf("%u bytes read, disk access time: %.2f s\n", nDataRead, fTime);
465                                                 m_fTotalDiskAccessTime += fTime;
466                                                 int nRainbowChainCountRead = nDataRead / 8;
467                                                 // Verify table chunk
468                                                 
469                                                 if (!fVerified)
470                                                 {
471                                                         printf("verifying the file...\n");
472
473                                                         // Chain length test
474                                                         int nIndexToVerify = nRainbowChainCountRead / 2;
475 /*                                                      CChainWalkContext cwc;
476                                                         cwc.SetIndex(pChain[nIndexToVerify].nIndexS);
477                                                         int nPos;
478                                                         for (nPos = 0; nPos < nRainbowChainLen - 1; nPos++)
479                                                         {
480                                                                 cwc.IndexToPlain();
481                                                                 cwc.PlainToHash();
482                                                                 cwc.HashToIndex(nPos);
483                                                         }
484                                                         
485                                                         uint64 nEndPoint = 0;
486                                                         for(int i = 0; i < nIndexSize; i++)
487                                                         {
488                                                                 if(nIndexToVerify >= pIndex[i].nFirstChain && nIndexToVerify < pIndex[i].nFirstChain + pIndex[i].nChainCount) // We found the matching index
489                                                                 { // Now we need to seek nIndexToVerify into the chains
490                                                                         nEndPoint += pIndex[i].nPrefix << 16;
491                                                                         nEndPoint += pChain[nIndexToVerify].nIndexE;
492                                                                         break;
493                                                                 }
494                                                         }
495                                                         if (cwc.GetIndex() != nEndPoint)
496                                                         {
497                                                                 printf("rainbow chain length verify fail\n");
498                                                                 break;
499                                                         }
500 */
501                                                         // Chain sort test
502                                                         // We assume its sorted in the indexing process
503                                                         /*
504                                                         int i;
505                                                         for (i = 0; i < nRainbowChainCountRead - 1; i++)
506                                                         {
507                                                                 if (pChain[i].nIndexE > pChain[i + 1].nIndexE)
508                                                                         break;
509                                                         }
510                                                         if (i != nRainbowChainCountRead - 1)
511                                                         {
512                                                                 printf("this file is not sorted\n");
513                                                                 break;
514                                                         }
515                                                         */
516                                                         fVerified = true;
517                                                 }
518         
519                                                 // Search table chunk
520                                                 t1 = clock();
521                                                 SearchTableChunk(pChain, nRainbowChainLen, nRainbowChainCountRead, hs, pIndex, nIndexSize, nProcessedChains);
522                                                 t2 = clock();
523                                                 fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
524                                                 printf("cryptanalysis time: %.2f s\n", fTime);
525                                                 m_fTotalCryptanalysisTime += fTime;
526                                                 nProcessedChains += nRainbowChainCountRead;
527                                                 // Already finished?
528                                                 if (!hs.AnyHashLeftWithLen(CChainWalkContext::GetHashLen()))
529                                                         break;
530                                         }
531                                 }
532                                 else printf("memory allocation fail\n");
533                         //}
534 /*                      else // So few hashes to search for. No need to load the entire chain file.
535                         {
536                                 clock_t t1 = clock();
537                                 m_fChains = file;
538                                 SearchTableChunk(NULL, nRainbowChainLen, 0, hs, pIndex, nIndexSize, 0);
539                                 clock_t t2 = clock();
540                                 float fTime = 1.0f * (t2 - t1) / CLOCKS_PER_SEC;
541                                 printf("cryptanalysis time: %.2f s\n", fTime);
542                                 m_fTotalCryptanalysisTime += fTime;
543
544                         }*/
545
546                         delete pIndex;
547                 }
548                 fclose(file);
549         }
550         else
551                 printf("can't open file\n");
552 }
553
554 void CCrackEngine::Run(vector<string> vPathName, CHashSet& hs)
555 {
556         // Reset statistics
557         ResetStatistics();
558
559         // Sort vPathName (CChainWalkSet need it)
560         int i, j;
561         for (i = 0; i < vPathName.size() - 1; i++)
562                 for (j = 0; j < vPathName.size() - i - 1; j++)
563                 {
564                         if (vPathName[j] > vPathName[j + 1])
565                         {
566                                 string sTemp;
567                                 sTemp = vPathName[j];
568                                 vPathName[j] = vPathName[j + 1];
569                                 vPathName[j + 1] = sTemp;
570                         }
571                 }
572
573         // Run
574         for (i = 0; i < vPathName.size() && hs.AnyhashLeft(); i++)
575         {
576                 SearchRainbowTable(vPathName[i], hs);
577                 printf("\n");
578         }
579 }
580
581 float CCrackEngine::GetStatTotalDiskAccessTime()
582 {
583         return m_fTotalDiskAccessTime;
584 }
585
586 float CCrackEngine::GetStatTotalCryptanalysisTime()
587 {
588         return m_fTotalCryptanalysisTime;
589 }
590
591 int CCrackEngine::GetStatTotalChainWalkStep()
592 {
593         return m_nTotalChainWalkStep;
594 }
595
596 int CCrackEngine::GetStatTotalFalseAlarm()
597 {
598         return m_nTotalFalseAlarm;
599 }
600
601 int CCrackEngine::GetStatTotalChainWalkStepDueToFalseAlarm()
602 {
603         return m_nTotalChainWalkStepDueToFalseAlarm;
604 }