2017-03-09 1 views
-1

私はCS50と呼ばれるedxコースを取っています。多分あなたの中にはそれに精通している人もいます。C - crypt() - コードは5ループ以上で4ループ以上で実行するのに同じパラメータ/ハッシュを使用します。

設定された問題の1つは、DESベースの暗号化を使用してハッシュされたパスワードを解読するアルゴリズムを実装するよう求められます。最大4文字です。

これまでのところ、とても良いです。私はそれをやった。

しかし、私はそれを少し改良して、DESベースの暗号化の最大値である8文字までのパスワードを解読することに決めました。

問題は、5文字目(またはそれ以上)の可能性を追加すると、私のコードはもう機能しません。

#define _XOPEN_SOURCE 

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

/* 
    Use this to compile 

    clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wshadow crack4.c -lcrypt -lm -o crack4 

*/ 


int main(int argc, char *argv[]) 
{ 
    if (argc != 2) //Checks if number of command-line arguments is valid 
    { 
     printf ("usage: ./crack + hash \n"); 
     return 1; //Retuns 1 (error) 
    } 

    char *hash = argv[1]; //Gets hash passed as argument 

    char salt[3]; //Gets the salt 
    salt[0] = hash[0]; 
    salt[1] = hash[1]; 
    salt[2] = '\0'; 


    //All possible characters used in a DES-based hashed password (taken from gnu library) 
    const char *const seedchars = " ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 

    char text[9] = "\0"; //Text that is gonna be tried with crypt() 




    for (int d = 0; d <= 64 ; d++) //To check for passwords of up to 4 characters 
    { 
     printf("d %d \n", d); 
     if(d > 0) 
     { 
      text[4] = '\0'; //Defining null-terminator at index 4  
      text[3] = seedchars[d]; //Iterates through the seedchars list at index 3 
     } 

     for (int c = 0; c <= 64 ; c++) //To check for passwords of up to 3 characters 
     { 
      if(c > 0) 
      { 
       if (d == 0) 
       { 
        text[3] = '\0'; //Defining null-terminator at index 3 
       } 
       text[2] = seedchars[c]; //Iterates through the seedchars list at index 2 
      } 

      for (int b = 0; b <= 64 ; b++) //To check for passwords of up to 2 characters 
      { 
       if(b > 0) 
       { 
        if (c == 0 && d == 0) 
        { 
         text[2] = '\0'; //Defining null-terminator at index 2 
        } 
        text[1] = seedchars[b]; //Iterates through the seedchars list at index 1 
       } 

       for (int a = 0; a <= 64 ; a++) //To check for passwords of up to 1 character 
       { 
        if(b == 0 && c == 0 && d == 0) 
        { 
         text[1] = '\0'; //Defining null-terminator at index 1 
        } 

        text[0] = seedchars[a]; //Iterates through the seedchars list at index 0 

        char *password = crypt(text, salt); //Hash var text and save it to var password 

        if (strcmp(hash, password) == 0) //Compares the hash passed as argv with created above 
        { 
         printf("%s\n", text); //prints the text that led to said hash 
         return 0; //Returns 0 (okay) 
        } 
       } 
      } 
     } 
    } 

    return 1; //Retuns 1 (error) 
} 

この1が動作していない:

#define _XOPEN_SOURCE 

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

/* 
    Use this to compile 

    clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wshadow crack.c -lcrypt -lm -o crack 

*/ 


int main(int argc, char *argv[]) 
{ 
    if (argc != 2) //Checks if number of command-line arguments is valid 
    { 
     printf ("usage: ./crack + hash \n"); 
     return 1; //Retuns 1 (error) 
    } 

    char *hash = argv[1]; //Gets hash passed as argument 

    char salt[3]; //Gets the salt 
    salt[0] = hash[0]; 
    salt[1] = hash[1]; 
    salt[2] = '\0'; 


    //All possible characters used in a DES-based hashed password (taken from gnu library) 
    const char *const seedchars = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 

    char text[9] = "\0"; //Text that is gonna be tried with crypt() 

    for (int h = 0; h <= 64 ; h++) //To check for passwords of up to 8 characters 
    { 
     if(h > 0) 
     { 
      text[8] = '\0'; //Defining null-terminator at index 8  
      text[7] = seedchars[h]; //Iterates through the seedchars list at index 7 
     } 

     for (int g = 0; g <= 64 ; g++) //To check for passwords of up to 7 characters 
     { 
      if(g > 0) 
      { 
       if (h == 0) 
       { 
        text[7] = '\0'; //Defining null-terminator at index 7  
       } 
       text[6] = seedchars[g]; //Iterates through the seedchars list at index 6 
      } 

      for (int f = 0; f <= 64 ; f++) //To check for passwords of up to 6 characters 
      { 
       if(f > 0) 
       { 
        if (g == 0 && h == 0) 
        { 
         text[6] = '\0'; //Defining null-terminator at index 6  
        } 
        text[5] = seedchars[f]; //Iterates through the seedchars list at index 5 
       } 

       for (int e = 0; e <= 64 ; e++) //To check for passwords of up to 5 characters 
       { 
        if(e > 0) 
        { 
         if (f == 0 && g == 0 && h == 0) 
         { 
          text[5] = '\0'; //Defining null-terminator at index 5  
         } 
         text[4] = seedchars[e]; //Iterates through the seedchars list at index 4 

         for (int d = 0; d <= 64 ; d++) //To check for passwords of up to 4 characters 
         { 
          printf("d %d \n", d); 
          if(d > 0) 
          { 
           if (e == 0 && f == 0 && g == 0 && h == 0) 
           { 
            text[4] = '\0'; //Defining null-terminator at index 4  
           } 
           text[3] = seedchars[d]; //Iterates through the seedchars list at index 3 
          } 

          for (int c = 0; c <= 64 ; c++) //To check for passwords of up to 3 characters 
          { 
           if(c > 0) 
           { 
            if (d == 0 && e == 0 && f == 0 && g == 0 && h == 0) 
            { 
             text[3] = '\0'; //Defining null-terminator at index 3 
            } 
            text[2] = seedchars[c]; //Iterates through the seedchars list at index 2 
           } 

           for (int b = 0; b <= 64 ; b++) //To check for passwords of up to 2 characters 
           { 
            if(b > 0) 
            { 
             if (c == 0 && d == 0 && e == 0 && f == 0 && g == 0 && h == 0) 
             { 
              text[2] = '\0'; //Defining null-terminator at index 2 
             } 
             text[1] = seedchars[b]; //Iterates through the seedchars list at index 1 
            } 

            for (int a = 0; a <= 64 ; a++) //To check for passwords of up to 1 character 
            {         
             if(b == 0 && c == 0 && d == 0 && e == 0 && f == 0 && g == 0 && h == 0) 
             { 
              text[1] = '\0'; //Defining null-terminator at index 1 
             } 

             text[0] = seedchars[a]; //Iterates through the seedchars list at index 0 

             char *password = crypt(text, salt); //Hash var text and save it to var password 

             if (strcmp(hash, password) == 0) //Compares the hash passed as argv with created above 
             { 
              printf("%s\n", text); //prints the text that led to said hash 
              return 0; //Returns 0 (okay) 
             } 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
    return 1; //Retuns 1 (error) 
} 

私は両方のコードで以下のハッシュを使用しますが、それだ。ここ

はこの1つが働いている私のコード

です2番目のコードでは機能しません。

hash - 50fkUxYHbnXGw 
text - rofl 

なぜ機能しないのか理解してもらえますか?

ありがとうございました。

編集:

第二のコードだけで実行が終了し、それが実際に働いているが、パスワードをクラックする方法時間がかかっています。ここではスクリーンショットです:

私はいくつかの理由でイメージとしてそれを投稿することができないんだので、ここでリンクがhttp://imgur.com/a/GVWar

編集2です:画像へのリンクを追加し、タイトル

編集3を固定:再固定タイトル

+2

申し訳ありませんが、「機能していません」は問題のある説明ではありません。また、SOのようなQ&Aサイトには適していません。 – StoryTeller

+1

「うまくいかない」「うまく動かない」「......実際にはうまくいきます」...おそらく、その混乱よりも問題が何であるかを言うためにあなたの質問を編集するべきでしょう。 – kaylum

+1

あなたのタイトルを修正してください:あなたのコードが動作するので、あなたの実際の質問はなぜそう長くかかりますか?ファビオは以下のように答えている。 – TheGreatContini

答えて

3

最初のケースでは、4文字の場合、4つのネストループがあります。どの「for」が64回まで実行されるか。したがって、あなたのコードは64^4 = 1600万回実行される可能性があります。

8番目のケースでは、8つのネストループがあります。それは64^8 = 281兆倍になります。

コンピュータがアルゴリズムを実行するのにかかる時間は、ループの量に比例します。

あなたのアルゴリズムは文字数で指数関数的であるため、非常に速くなります。詳細を知りたい場合は、「algorithm asymptotic notation」を検索してください。

+0

4の代わりに8つのネストされたループがあるので、実行に時間がかかることがあります。 しかし、問題は、私が最初のコードに投稿した画像のように、d(4番目のループ)それはパスワードを壊す。 2番目のコードでは、e(5番目のループ)は64まで上がり、前のループが64^2 = 128回実行されたことを意味します。 編集:情報を追加してください。 –

+0

もっと明確にするために、内側のループの内側に "printf"ベローを追加して(int a ...)、各ステップを出力することができます。 h、g、f、e、d、c、b、a)%dd =%dd =%dc =%dd =%da =%d \ n " ; ' 実行に時間がかかりすぎる場合は、代わりに単純なカウンタ(「total ++;」など)を追加し、最後に1回印刷します。 ** total **を** long ** intとして宣言します。 –

+0

私はすでにこれをしました。しかし、4ループと8ループのコードでは、それぞれdとeを印字するだけです。それは、その写真がどこから来ているのか、私はそれが同じハッシュを解読するよりも長い時間がかかることを知っているところです。 –

0

インデックスは0から64までの65文字で構成されるホイールと考えることができます。最後の文字は、宣言された値からの行終端文字です。

あなたがeの値のためのprintfを追加した場合:

crack08 50fkUxYHbnXGw 
e 1 
d 0 
d 1 
d 2 
d 3 
d 4 
d 5 
d 6 
d 7 
d 8 
d 9 
d 10 
d 11 
d 12 
d 13 
d 14 
d 15 
d 16 
d 17 
d 18 
d 19 
d 20 
d 21 
d 22 
d 23 
... 
d 63 
d 64 
e 2 
d 0 
d 1 
d 2 
... 

あなたは時間ので、我々は、電子の最初の値をスキップしたい参照してくださいね - fは0

見つけていますe = 64(65番目のインデックス '\ 0'文字列ターミネータ)まで、4文字の一致が遅延されます。

これは、4文字のパスワードを見つけるまでに65倍以上長くかかることを示しています。

追加パスを取り除くには、使用されている文字の 'ホイール'を再編成し、最初の文字として '\ 0'文字を追加し、最初のパスの文字列ターミネータとして使用し、次のパスのためにスキップします。

#define _XOPEN_SOURCE 

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) { 
     printf ("usage: ./crack hash\n"); 
     return 1; //Retuns 1 (error) 
    } 
    char *hash = argv[1]; 
    char salt[3]; 
    salt[0] = hash[0]; 
    salt[1] = hash[1]; 
    salt[2] = '\0'; 

# define WHEEL_SIZE 65 // all possible password characters 
         // plus null character for shorter strings 

    char seedchars[WHEEL_SIZE] = 
     "@./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 
    char text[9]; // Text that is gonna be tried with crypt() 
    text[8] = '\0'; // for h > 0 
    seedchars[0] = '\0'; // test for short strings first 
    int a_first = 0; 
    int b_first = 0; 
    int c_first = 0; 
    int d_first = 0; 
    int e_first = 0; 
    int f_first = 0; 
    int g_first = 0; 

    for (int h = 0; h <= WHEEL_SIZE - 1 ; h++) { 
     text[7] = seedchars[h]; 

     for (int g = g_first ; g <= WHEEL_SIZE - 1; g++) { 
      text[6] = seedchars[g]; 

      for (int f = f_first; f <= WHEEL_SIZE -1; f++) { 
       text[5] = seedchars[f]; 

       for (int e = e_first; e <= WHEEL_SIZE - 1; e++) { 
        printf("e %2d\n", e); 
        text[4] = seedchars[e]; 

         for (int d = d_first; d <= WHEEL_SIZE - 1; d++) { 
          printf("d %2d\n", d); 
          text[3] = seedchars[d]; 

          for (int c = c_first; c <= WHEEL_SIZE - 1; c++) { 
           if (c > 0) 
            b_first = 1; 
           text[2] = seedchars[c]; 
           for (int b = b_first; b <= WHEEL_SIZE - 1; b++) { 
             text[1] = seedchars[b]; 
            for (int a = a_first; a <= WHEEL_SIZE - 1; a++) { 
             text[0] = seedchars[a]; 

             char *password = crypt(text, salt); 
             if (strcmp(hash, password) == 0) { 
              printf("%s\n", text); 
              return 0; 
             } 
            } 
            b_first = 1; 
           } 
           c_first = 1; 
          } 
          c_first = 1; 
         } 
         d_first = 1; 
        } 
        e_first = 1; 
       } 
       f_first = 1; 
      } 
      g_first = 1; 
     } 
    return 1; 
} 

そして、それは、最小の時間で私たちに答えを与える:

crack 50fkUxYHbnXGw 
e 0 
d 0 
d 1 
d 2 
d 3 
d 4 
d 5 
d 6 
d 7 
d 8 
d 9 
d 10 
d 11 
d 12 
d 13 
d 14 
d 15 
d 16 
d 17 
d 18 
d 19 
d 20 
d 21 
d 22 
d 23 
d 24 
d 25 
d 26 
d 27 
d 28 
d 29 
d 30 
d 31 
d 32 
d 33 
d 34 
d 35 
d 36 
d 37 
d 38 
d 39 
d 40 
d 41 
d 42 
d 43 
d 44 
d 45 
d 46 
d 47 
d 48 
d 49 
d 50 
rofl 

はるかに満足のいく答え。

関連する問題