0

I need to write a recursive function that can guess a 4 character long password. I am using this to generate a random "password":

/*start random password generating code*/
$random_password = "";
$charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for($i = 0; $i < 4; $i++){
  $random_int = mt_rand();
  $random_password .= $charset[$random_int % strlen($charset)];
}
echo "The password to guess is: " . $random_password . "\n";
/*end random password generating code*/

I can easily do the same and check if it matches against the password with a while loop but this exercise is meant to do it with a recursive function.

How would I do this? My previous exercise was just to calculate the Fibonacci number but this goes a bit past that.

Should I do it something like this:

$counter = array(1, 0, 0, 0);
function enumurate(){
  global $counter;
  if($counter[0] != 0){
    echo $counter[0];
    if($counter[1] != 0){
      echo $counter[1];
      if($counter[2] != 0){
        echo $counter[2];
        if($counter[3] != 0){
          echo $counter[3];
        }else{
          echo 'error! $counter[3] is: ' . $counter[3];
        }
      }else{
        echo 'error! $counter[2] is: ' . $counter[2];
      }
    }else{
      echo 'error! $counter[1] is: ' . $counter[1];
    }
  }else{
    echo 'error! $counter[0] is: ' . $counter[0];
  }

}
enumurate();

I believe the thing I am looking for is something among bit shifting(after I have iterated 62 times[26 + 26 + 10= lowercase + UPPERCASE + numerical]) and then recursively call the function again but I am at a loss.

Or am I overthinking this?

PS: I did look for it on google but for some reason I can't find any on the specific of recursive function matching against a string enumeration as well as checking on here. My 1337 searching skills may have failed me though.

  • What do you mean with guessing? Generating all possible passwords? I mean the program has the variable `$random_password`, so what is there to guess? – trincot Jun 13 '17 at 17:27
  • The point is that I have to generate a random password and then sort of "bruteforce" the generated password. – rootshelled Jun 13 '17 at 20:37
  • What do you mean with "bruteforce"? Is `return $random_password;` not good enough as a guess? – trincot Jun 13 '17 at 20:41

1 Answers1

0

It seems a bit useless to guess a password that you have just generated... why would you not just "guess" that password? Also, there is no fun in just generating all possible 4-letter words until it equals the password you already knew from the start. Talk about inefficient code...

To make this a bit less trivial, I'll assume that the function that needs to guess the password does not get the password as argument (as then it could just return that as the only correct guess), but instead would get a callback function it could call to verify which of the following is true:

  • The guess is completely correct: the callback will return value 2
  • The guess matches with the first characters of the password, but more characters are needed for a complete match: the callback will return 1 in that case
  • All other cases: the callback will return 0

That callback function would thus look like this:

function ($guess) use ($random_password) {
    if ($guess === $random_password) return 2; // it is correct!
    if (substr($random_password, 0, strlen($guess)) === $guess) return 1; // partial match;
    return 0; // the password does not start with the guessed characters
}

With this set up the challenge is somewhat more interesting, because the solution will not be allowed to peek at the password it needs to guess.

Here is then the recursive solution (following your function to produce the random password):

function getRandomPassword() { // Your function
    $random_password = "";
    $charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for($i = 0; $i < 4; $i++){
        $random_int = mt_rand();
        $random_password .= $charset[$random_int % strlen($charset)];
    }
    return $random_password;
}

function findPassword($evaluateGuess) {
    $charset = str_split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");

    function guessTheRest(&$evaluateGuess, &$charset, $password) {
        $match = $evaluateGuess($password); // call the callback function
        if ($match === 0) return; // mismatch
        if ($match === 2) return $password; // all characters correct
        foreach ($charset as $char) { // taking each character as a "guess"
            $guess = guessTheRest($evaluateGuess, $charset, $password . $char);
            if ($guess) return $guess;
        }
    }

    return guessTheRest($evaluateGuess, $charset, "");
}

$random_password = getRandomPassword();
echo "The password to guess is: $random_password\n";

$guess = findPassword(function ($guess) use ($random_password) {
    if ($guess === $random_password) return 2; // it is correct!
    if (substr($random_password, 0, strlen($guess)) === $guess) return 1; // partial match;
    return 0; // the password does not start with the guessed characters
});

echo "guessed $guess\n";

See it run on repl.it.

trincot
  • 317,000
  • 35
  • 244
  • 286