Какие оптимизации можно сделать для этого пользовательского сравнения MD5?

Я пытаюсь оптимизировать этот код, который принимает строки, сгенерированные maskprocessor. конвейер командной строки, запускает на них два раунда библиотеки OpenSSL MD5 (где второй запуск использует только часть результата из первого) и сравнивает их с предоставленными хэшами, предоставленными в командной строке.

В настоящее время он работает со скоростью около 800 000 строк в секунду на процессоре Lenovo ThinkPad X201 с процессором Core i7 2,67 ГГц, выполняя 7 311 616 строк менее чем за 10 секунд. Я действительно хотел бы посмотреть, можно ли что-нибудь сделать, чтобы улучшить это. Я использую Visual Studio 2012, а теперь 2013 в качестве базы (развился из сценариев bash, а затем Perl).

Я бы поверил, что единственная часть процесса, которая здесь является узким местом, — это сравнение, которое я переключил на memcmp из strcmp (хотя не увидел от этого большого прироста). Генерация MD5 и процессора маски не в моих силах заменить моим собственным кодом.

Этот код является частью моего проекта по восстановлению паролей StuffIt 5 путем коллизии хэшей и работает очень хорошо, но любое увеличение скорости было бы большим бонусом (особенно при запуске нескольких экземпляров).

Изображение процесса доступно по адресу Performance Perl vs. . скомпилировано

Я ни в коем случае не компетентный программист, и я знаю, что если бы Hashcat или любой из взломщиков паролей с ускорением на графическом процессоре могли бы реализовать этот алгоритм, он бы взорвал мой из воды, но для его реализации недостаточно спроса. Поверь мне, я спросил :(

    #define _CRT_SECURE_NO_WARNINGS 
    // Need OpenSSL Libs linked, headers linked, dlls linked
    #include <stdio.h>
    #include <string.h>
    #include <openssl/md5.h>
    #include <iostream>
    #include <ctime>

    using namespace std;
    int main(int argc, char* argv[]) 
    { 
    /* Start - Setup Timer */

    std::clock_t start;
    double duration;
    start = std::clock();

    /* End - Setup Timer */

    /* Start - Hash Length Check */

    int j;
    for(int i = 1; i < argc; i++) {
      j = strlen(argv[i]);
    if (j != 10){
            std::cout<<argv[i]<<" is "<<j<<" characters long - not 10! Quitting\n";
            return 0;}
    }

    /* End - Hash Length Check */

    /* Start - Line Entry and Count */
     char string[40]; 
     int i;
     __int64 linecount = 0; // caps at 9,223,372,036,854,775,807
     int millioncount = 0;
//  printf("Enter a string: ");
  while(fgets(string, 40, stdin)){

  /* remove newline, if present */
  i = strlen(string)-1;
  if( string[i] == '\n') 
      string[i] = '\0';

  //printf("This is your string: %s", string);
  linecount++;
  if(linecount%10000000 == 0){
      millioncount++;
    duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
    double linespersec = linecount/duration;
    std::cout<<millioncount*10<<" million tries ("<<linespersec<<" l/s)\n";
  }
    /* End- Line Entry */

  /* Start - MD5 Round 1 */

   unsigned char digest[MD5_DIGEST_LENGTH];
    char string2[5];     
    MD5((unsigned char*)&string, strlen(string), (unsigned char*)&digest);    

    /* End - MD5 Round 1 */

    /* Start - MD5 Round 2 */

// Set the string to the second MD5 hash of the first 5 characters (10 bit)
    //for(int i = 0; i < 5; i++)
        //string2[i] = digest[i];
    memcpy(string2, digest, 5);
    MD5((unsigned char*)&string2, 5, (unsigned char*)&digest);    

    char mdString3[33];

    for(int i = 0; i < 5; i++)
         sprintf(&mdString3[i*2], "%02x", (unsigned int)digest[i]);

  //  printf("\nmd5 digest: %s\n", mdString3);
       /* End - MD5 Round 2 */

    /* Start - Hash Check */
for(int i = 1; i < argc; i++) {

    //if (mdString3[0] == argv[i][0] && strcmp(mdString3, argv[i]) == 0){ // added the 0 comp, no real improvements
    if (memcmp(mdString3, argv[i], 10) == 0){ // 785-795k
            printf("Success at: %s", string);
    duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
    double linespersec = linecount/duration;
    std::cout<<" for "<< argv[i]<<" in "<< duration <<" seconds at line "<<linecount<<" ("<<linespersec<<" l/s)\n";
    }
}
  }
    /* End - Hash Check*/

  /* Start - Timer Closeout */
    duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
        double linespersec = linecount/duration;
    std::cout<<"Exhausted search of "<<linecount<<" lines in "<< duration <<" seconds ("<<linespersec<<" l/s)\n";
/* End - Timer Closeout */
    return 0;
}

person Greg Esposito    schedule 30.12.2013    source источник
comment
@davidlaporte Ваше изменение увеличило мой средний показатель с 750-800 тысяч до 900-950 тысяч. Я очень благодарен.   -  person Greg Esposito    schedule 31.12.2013


Ответы (1)


Вы можете получить улучшение, устранив цикл вокруг вызова sprintf и используя вместо этого:

sprintf(&mdString3[0], 
        "%02x%02x%02x%02x%02x", 
        (unsigned char)digest[0],
        (unsigned char)digest[1], 
        (unsigned char)digest[2], 
        (unsigned char)digest[3], 
        (unsigned char)digest[4]);
person David LaPorte    schedule 30.12.2013