4 символа трещины заканчиваются быстро, но добавление 5-го цикла замедляет всю программу - PullRequest
0 голосов
/ 17 октября 2019

Я пишу программу для класса, который взламывает 5-символьный (aA-zZ) пароль, собирая хеш-пароль в командной строке и сопоставляя хеш с хешами, сгенерированными с помощью функции crypt (). Моя проблема заключается в том, что добавление 5-го цикла для взлома 5-символьного пароля замедляет работу программы, даже для 1-4-символьных паролей, и я должен отменить ее. Удаление 5-го цикла взламывает пароли из 1-4 символов менее чем за минуту.

Мы рассмотрели только основы в классе, что продемонстрировано в моем коде. Таким образом, решение должно соответствовать этому уровню кодирования.

#include <cs50.h>
#include <stdio.h>
#include <crypt.h>
#include <string.h>

void printpass (string fst, string hsh1, string hsh);
/* prompt user for 1 cmd line argument */
int main(int argc, string argv[])

{    
    /* only allow 1 cmd line argument and return cmd line error
    and exit if false */    
    if (argc != 2)
    {
        printf("Invalid request!\n");
            return 1;
    }
    string hash = argv[1];
    char slt1 = hash[0];
    char slt2 = hash[1];
    char salt[3] = {slt1, slt2, '\0'};
    char alpha[52] = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";//upper & lowercase passwords only

    for (int d = 0; d < 52; d++) //search for one character pw
    {
        char s1 = alpha[d];
        char first1[2] = {s1, '\0'};
        string hash0 = crypt(first1, salt);
        printpass (first1, hash0, hash);

        if (strcmp(hash0, hash) != 0) 
        for (int f = 0; f < 52; f++) //search for two character pw
        {
            char s2 = alpha[f];
            char first2[3] = {s1, s2, '\0'};
            string hash1 = crypt(first2, salt);
            printpass (first2, hash1, hash);

            if (strcmp(hash1, hash) != 0 || strcmp(hash0, hash) != 0)
            for (int h = 0; h < 52; h++) //search for two character pw
                {
                    char s3 = alpha[h];
                    char first3[4] = {s1, s2, s3, '\0'};
                    string hash2 = crypt(first3, salt);
                    printpass (first3, hash2, hash);

                    if (strcmp(hash2, hash) != 0 || strcmp(hash1, hash) != 0 || strcmp(hash0, hash) != 0)
                    for (int j = 0; j < 52; j++) //search for two character pw
                        {
                            char s4 = alpha[j];
                            char first4[5] = {s1, s2, s3, s4, '\0'};
                            string hash3 = crypt(first4, salt);
                            printpass (first4, hash3, hash);

                            if (strcmp(hash3, hash) != 0 || strcmp(hash2, hash) != 0 || strcmp(hash1, hash) != 0 || strcmp(hash0, hash) != 0)
                            for (int l = 0; l < 52; l++) //search for two character pw
                                {
                                    char s5 = alpha[l];
                                    char first5[6] = {s1, s2, s3, s4, s5, '\0'};
                                    string hash4 = crypt(first5, salt);
                                    printpass (first5, hash4, hash);

                                }
                            }
                }
        }
    }
}

void printpass (string fst, string hsh1, string hsh) //compare hashes and print if true
{
    if (strcmp(hsh1, hsh) == 0)
    {
        printf("%s", fst);
    }
}

1-4-символьные пароли должны завершиться в течение минуты с 5-м циклом в коде.

Ответы [ 4 ]

0 голосов
/ 19 октября 2019

Как отмечалось в других ответах, комбинаторная сложность такого рода проблем делает ее очень сложной. надеюсь, вы поймете, почему рекомендации по длине пароля, как правило, представляют собой «что-то более 8 букв»

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

в качестве комментария к стилю вашего кода, все ваши вложенные циклы выглядят очень похоже. Я бы рекомендовал превратить это в рекурсивную функцию, она должна быть довольно простой и значительно сократить код. большую часть времени будет потрачено на выполнение crypt(3), поэтому вам не нужно сильно беспокоиться о производительности вашего кода, но это может стоить профилирование просто чтобы убедиться, что

0 голосов
/ 17 октября 2019

Код запускает 5 вложенных циклов (d, f, j, h, l). Попытка Q, QQ, QQQ, QQQQ, QQQQQ, QQQQW, ..., попытка всех комбинаций (различной длины) паролей, начинающихся с Q, перед попыткой оценить любой пароль, начинающийся с любой другой буквы.

Хотясуществует около 7,2 млн 4-буквенных комбинаций (52 ^ 4), код оценит многие 5-буквенные комбинации (их около 380 млн.), прежде чем пытаться выполнить полное меньшее подмножество 4-буквенных комбинаций. Даже для однобуквенного пароля (например, A) код будет оценивать почти половину пятибуквенных комбинаций, прежде чем использовать простое «A».

В качестве альтернативы рассмотрите возможность переупорядочения циклов:

  1. однобуквенные пароли
  2. 2-буквенные пароли
  3. 3-буквенные пароли
  4. 4-буквенные пароли
  5. 5-буквенные пароли
0 голосов
/ 18 октября 2019

Из комментариев видно, что требуемый порядок - более короткие пароли будут проверены перед более длинным паролем. Это приведет к следующей последовательности: (Q, W, E, ... QQ, QW, QE, ..., WQ, WW, WE, ..., QQQ, QQE, ...) вместотекущий порядок словаря (Q, QQ, QQQ, QQQQ, QQQQQ, QQQQW, QQQQE, ...).

С МИНИМАЛЬНЫМИ изменениями текущего кода это может быть достигнуто с помощью следующего. Ниже приведено дополнительное предложение, которое потребует более чем минимальных изменений.

   bool done = false ;
   for (int pwlen=1 ; pwlen<=5 && !done ; pwlen++ ) {
       for (int d = 0; d < 52 && done; d++) {
           char s1 = alpha[d];

           if ( pwlen == 1 ) {
               char first1[2] = {s1, '\0'};
               string hash0 = crypt(first1, salt);
               printpass (first1, hash0, hash);
               if (strcmp(hash0, hash) == 0 ) { done = true ; break } ;
           } else {
               for (int f = 0; f < 52 && done; f++) {
               ... same changes ...
               if ( pwlen == 2 ) {
               } else {
                  ... level 3 here.
               } ;
           } ;
       } ;
   } ;

Также рассмотрите следующие изменения:

  1. Перемещение всей логики из 'main' в другую функцию, котораябудет вызываться по главной. Это облегчит модификацию кода (например, используйте «return» для выхода из внутренних циклов и т. Д.). Функция должна ВЕРНУТЬ соответствующий ключ.
  2. Изменение прохода печати для возврата значения true / false, если пароль совпадает. Это исключит избыточные strcmp.
0 голосов
/ 17 октября 2019
Пароль длиной до 1000 * 4 символов может взломать до 7311616 (or 52^4) итераций, а пароль длиной 5 символов может занять до 380204032 (or 52^5) итераций.
...