7
\$\begingroup\$

For a school project I am tasked to decrypt DES passwords. I have sample code provided below and I want to know if this is the best method. Also should I code in error handling for the dictionary file or does the while condition take care of this?

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

#define _XOPEN_SOURCE

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./crack <password>\n");
        return 1;
    }

    int n = strlen(argv[1]);
    char password[n];

    for (int i = 0; i < n; i++)
    {
        password[i] = argv[1][i];
    }

    char salt[2]; 
    salt[0] = password[0];
    salt[1] = password[1]; 

    FILE *fp;
    fp = fopen("/usr/share/dict/words", "r");
    char line[50];

    while(fgets(line,50,fp)!= NULL)
    {
        line[strlen(line) - 1] = '\0';            
        if (!strcmp(argv[1], crypt(line, salt)))
        {
            printf("Password found!\n");
            return 0;
        }
    }
    printf("Not found\n");
    fclose(fp);
    return 0;
}
\$\endgroup\$
4
\$\begingroup\$

You're keeping us in suspense — I'm dying to know which password matched!

Many password crackers also test for common character substitutions, e.g. o → 0, i → 1, s → $.

Other than that, the general technique seems sound.

I do have a few general remarks, though.

  • What is #define _XOPEN_SOURCE for? Sometimes, defining it will change some of the functions you call. However, it would only have any effect if you put it before your #includes.
  • It would be good to make a function, even for a simple program like this. I suggest that main() be responsible for parsing and validating the command line and opening the word list, calling crack(const char *pwhash, FILE *wordlist) to do the actual work.
  • You don't close the word list if you find a match.
  • Consider returning a non-zero exit status if the password is not found. That makes your program more useful to scripts.
\$\endgroup\$
2
\$\begingroup\$

The code is neatly-formatted, the variables are well-named, which is good.


I don't see why you have a variable named password. You only use for first two characters of it, to initialize salt. You could initialize salt from argv instead. If you want to have password then I recommend null-terminating it to make sure it behave like a C-string. I don't understand why password isn't of length n+1, why you didn't use strcpy or strncpy.


The salt is required to be 2 characters; maybe you should check that argv[1] is long enough before starting.


Do you have reason to believe that 50 is the length of the largest string in the dictionary?


Also should I code in error handling for the dictionary file

Probably yes; because you want to tell the difference between:

  • Failed to find password because word wasn't in dictionary
  • Failed to find password because couldn't open the dictionary

Dictionary-based attack may be a fast way to find long, commonly-used passwords; but it's not the most reliable way (because if the word is not in the dictionary then it won't be found).

The school project might have asking you to build all permutations, for example like this.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.