简体   繁体   中英

Brute-Force java recursive password crack

I've been given another home assignment that I'm cracking my head about for a week now: I've been given a class that creates a password of az only at a given length.

public class Password {
private String _password = "";

// Constructor that generates a password
public Password(int length) {
    Random generator = new Random();
    for (int i = 0; i < length; ++i) {
        this._password = this._password + (char) (generator.nextInt(26) + 97);
    }
}

//Method that compares a given string to the password
public boolean isPassword(String st) {
    return st.equals(this._password);
}
}  

Rules:

  • If you want to use String class, only the following are allowed: charAt,equals,length,substring.
  • You must use recursion.
  • You cannot use 26 recursive calls.
  • No support methods.
  • No arrays.
  • No static variables.
  • Overloading is ok.

here's what I got until now:

public static String findPassword(Password p, int length) {
    String pswd= "";
    char char2Check = 'a';

    if (length == 0) {
        return "";
    }
    else {
        return findPassword(p,length, pswd, char2Check);
    }
}

public static String findPassword(Password p,int length, String pswd, char char2Check) {
    if (pswd.length() < length) {
            pswd+= char2Check;
            pswd = findPassword(p,length,pswd,char2Check);
        if (pswd.length() < length) {
            if (pswd.length() == 0) {
                if (char2Check == 'z') {
                    return pswd;
                }
                if (char2Check < 'z') {
                    char2Check++;
                    pswd += char2Check;
                    return findPassword(p, length, pswd, char2Check);
                }
            }
            else {
                if (char2Check == 'z') {
                    return pswd.substring(0, pswd.length() - 1);
                }
                if (char2Check < 'z') {
                    pswd = pswd.substring(0, pswd.length() - 1);
                    char2Check++;
                    pswd += char2Check;
                    return findPassword(p, length, pswd, char2Check);
                }
            }
        }
    }
    if (pswd.length() == length) {
        System.out.println(pswd);
        if (p.isPassword(pswd)) {
            return pswd;
        }
        if (char2Check < 'z') {
            pswd = pswd.substring(0, pswd.length() - 1);
            char2Check++;
            pswd+= char2Check;
            return findPassword(p,length,pswd,char2Check);
        }
        if (char2Check == 'z'){
            return pswd.substring(0, pswd.length() - 1);
        }
    }
    return pswd;
}

the problem is:

If the first char is ie 'r' it will not check a, b or c after it, it'll go stright to s, t, u...

there are a few more problems, but once this problem is gone I think the rest will be easier to solve..

here a paste of the output: http://pastebin.com/CK9AyKUi

hopefully someone can help me out :)

You went to great length for something supposed to be simple: generating all strings of length n containing only az characters.

A note about the performances: use StringBuilder instead of String when you want to do lots of append and deletion of chars. String are immutable, so they are copied again and again in your code.

Now, about recursion, you have only two things to think of: what is your general case ? What is your stop condition ?

Here, the stop condition is simple: the real password and current trial have the same length. If the trial is correct, then return it ; else go up in the recursion. Second stop condition: all possibilities have been tried for the current prefix and there is no match, then go up in the recursion.

General case is also simple: given the current prefix, try to append every possible letter az and add one level of recursion.

Now, you may want to give it another shot with those leads (hint: fresh start is easier than trying to fix your current code). My solution follows, but you can come up with your own:

public static String findPassword(Password p, int length) {
    return findPassword(p,length, new StringBuilder());
}

public static String findPassword(Password password, int length, StringBuilder str) {
    // Stop condition, password and trial have same length
    if (length == str.length()) {
        if (password.isPassword(str.toString())) {
            return str.toString();
        } else {
            return "";
        }
    }

    String s;

    for (char c = 'a'; c <= 'z'; c++) {
        // Add a new character to the given prefix
        str.append(c);
        // Try to find a password for the new prefix
        s = findPassword(password, length, str);
        if (!s.equals("")) {
            return s;
        }
        // Didn't work out, remove the character
        str.deleteCharAt(str.length()-1);
    }
    // All chars have been tried without success, go up one level
    return "";
}

I won't give you the solution. But assuming the alphabet is "abc" and you want to find passwords of length 3, you would have to program this:

a -> aa -> aaa 
|     |      | 
|     |    aab 
|     |      | 
|     |    aac 
|     |        
|    ab -> aba 
|     |      | 
|     |    abb 
|     |      | 
|     |    abc 
|     |        
|    ac -> aca 
|            | 
|          acb 
|            | 
|          acc 
|              
b -> ba -> baa 
|     |      | 
|     |    bab 
|     |      | 
|     |    bac 
|     |        
|    bb -> bba 
|     |      | 
|     |    bbb 
|     |      | 
|     |    bbc 
|     |        
|    bc -> bca 
|            | 
|          bcb 
|            | 
|          bcc 
|              
c -> ca -> caa 
      |      | 
      |    cab 
      |      | 
      |    cac 
      |        
     cb -> cba 
      |      | 
      |    cbb 
      |      | 
      |    cbc 
      |        
     cc -> cca 
             | 
           ccb 
             | 
           ccc

There are 2 paths each recursive step you have to check.

  • -> , in case the password is not long enough, try it with 'a' appended.
  • | , which increments the last character as long it's not the last of the alphabet.

Both these 2 paths have a stop condition you have to take care for: password length & alphabet length.

 private static boolean findPassword(Password p, String pswd, int length) {

    if (length == pswd.length()) {
        if (p.isPassword(pswd))
            System.out.println(pswd);
        return p.isPassword(pswd);

    }

    String alpha = "abcdefghijklmnopqrstuvwxyz";
    for (int i = 0; i < alpha.length(); i++) {
        if (findPassword(p, pswd + alpha.charAt(i), length)) 
            return true;
    }
    return p.isPassword(pswd);
}

first of all many thanks!

u'r code gave me some good ideas fixed it for you:)

i have corrected ur code and its works perfect

and here it is:

  public static String findPassword(Password p,int length)
  {
      // string and char to be input into the overloading method
      String pswd= "";
      char char2Check = 'a';

      // Checking if the length of the password is 0 so its null
      if (length == 0)
      {
          return "";
      }
      else{
          // going to the overloading method to find the password
          return findPassword(p,length, pswd, char2Check);
      }
  }

  public static String findPassword(Password p,int length, String pswd, char      char2Check)
  {

    // Checking if the length of the password finder is less then the length of the 
    // password we add more chars until they are the same length to check if they're equal
    if (pswd.length() < length)
    {
        pswd+= char2Check;
        pswd = findPassword(p,length,pswd,char2Check);
        char2Check = pswd.charAt(pswd.length() - 1);
        if (pswd.length() < length)
        {
            if (pswd.length() == 0)
            {
                if (char2Check == 'z')
                {
                    return pswd;
                }
                if (char2Check < 'z')
                {
                    char2Check++;
                    pswd += char2Check;
                    return findPassword(p, length, pswd, char2Check);
                }
            }else{
                if (char2Check == 'z')
                {
                    return pswd.substring(0, pswd.length() - 1);
                }
                if (char2Check < 'z')
                {
                    char2Check = pswd.charAt(pswd.length() - 1);
                    pswd = pswd.substring(0, pswd.length() - 1);
                    char2Check++;
                    pswd += char2Check;
                    return findPassword(p, length, pswd, 'a');
                }
            }
        }
    }
    // Checking if the password finder length is the same as the original password
    if (pswd.length() == length)
    {
        System.out.println(pswd);
        // Checking if the two password match, if so we return the password finder.
        if (p.isPassword(pswd))
        {
            return pswd;
        }
        // Checking if the char is not the last char -> z
        if (char2Check < 'z')
        {
            pswd = pswd.substring(0, pswd.length() - 1);
            char2Check++;
            pswd+= char2Check;
            return findPassword(p,length,pswd,char2Check);
        }
        if (char2Check == 'z')
        {
            return pswd.substring(0, pswd.length() - 1);
        }
    }
    return pswd;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM