Password Cracker Issue

This is a recreational project perfectly within the conatraints of the law.

With that out of the way, I have an issue with comparing the correct password to the generated password. I have successfully found a way to loop through the ASCII regular (not extended) table for a string of eight characters. Allthough, the problem is that if I have a password less than 8 bits (say one character), lets say the correct password is 'a', then my program, the way its designed, compares 'a' to 'a ', which are odviously different. Therefore, the password is not identified correctly. I tried a method of erasing the whitespace, but it's still not working correctly, passing the correct character.

Please Help.

Here's the relevant function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
string findPaswdBrute(string pasw) {
	char ee[9] = "        ";
	//to compare passwords
	string pas = ee;
	//looping through all possible 8-bit ascii combinations (not including spaces)
	for (int a = 32; a < 137; a++) {
		for (int b = 32; b < 137; b++) {
			for (int c = 32; c < 137; c++) {
				for (int d = 32; d < 137; d++) {
					for (int e = 32; e < 137; e++) {
						for (int f = 32; f < 137; f++) {
							for (int g = 32; g < 137; g++) {
								for (int h = 32; h < 137; h++) {
									ee[0] = h;
									ee[1] = g;
									ee[2] = f;
									ee[3] = e;
									ee[4] = d;
									ee[5] = c;
									ee[6] = b;
									ee[7] = a;
									pas = ee;
									//erasing any unecissary space
									for (int i = 0; i < pas.length(); i++)
										if (pas[i] == ' ') pas.erase(i, 1);
									cout << pas + "\n";
									//comparing. if the password equals the given password, return the working password.
									if (pas == pasw) {
										return pas;
									}
								}
							}
						}
					}
				}
			}
		}
	}
	//if it doesn't find an eight-bit password through all the combinations possible, returns false.
	return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void all_passwords(std::string &accum, size_t max_length, std::function<std::string> &callback){
    callback(accum);
    if (!max_length)
        return;
    size_t n = accum.size();
    accum.push_back(0);
    for (int i = 32; i < 137; i++){
        accum[n] = (char)i;
        all_passwords(accum, max_length - 1, callback);
    }
    accum.resize(n);
}

void all_passwords(size_t max_length, std::function<std::string> &callback){
    std::string accum;
    all_passwords(accum, max_length, callback);
}

//...

all_passwords(2, [](const std::string &s){ std::cout << s << std::endl; });
Outputs "", "a", "aa", "ab" ..., "az", "b", "ba", ..., "zz".

EDIT: Okay, the output is not quite that, but you get the idea.
Last edited on
The whole point of this project is to understand how things work. I don't have an issue with the looping process, just a way to clear whitespace from a string.
I'm a beginner at c++, so I would just like some help understanding.

For your example I have a number of questions:
1: What do all the arguments point to?
2: Why do you have that many arguments?
3: Why do you have a function to instantiate your first function (2 times)?
4: You use some functions that I'm not familiar with, can you please make a reference or post links?
5: Why don't you just use an int for max size?
6: WHY ARE YOU CALLING YOUR FUNCTION INSIDE YOUR FUNCTION???
7: I don't want to use any arbitrary libraries, just c++. I will if I have to, but I just want to understand if there are any.

Well, I don't understand much of your code, but you have given me a new approach to attack
my probem.

Instead of incrementing a fixed char array, just create a string and add a new character for each go-arround.

Thanks, and please respond.
Last edited on
I solved my own problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
string findPaswdBrute(string pasw) {
        //ee has no space defined.
	char ee[9] = "";
	string pas = ee;
	for (int a = 32; a < 137; a++) {
		for (int b = 32; b < 137; b++) {
			for (int c = 32; c < 137; c++) {
				for (int d = 32; d < 137; d++) {
					for (int e = 32; e < 137; e++) {
						for (int f = 32; f < 137; f++) {
							for (int g = 32; g < 137; g++) {
								for (int h = 32; h < 137; h++) {
									ee[0] = h;
                                                                        //don't include other characters that are spaces.
									if (g >= 33)
										ee[1] = g;
									if (f >= 33)
										ee[2] = f;
									if (e >= 33)
										ee[3] = e;
									if (d >= 33)
										ee[4] = d;
									if (c >= 33)
										ee[5] = c;
									if (b >= 33)
										ee[6] = b;
									if (a >= 33)
										ee[7] = a;
									pas = ee;
									cout << pas + "\n";
									if (pas == pasw) {
										return pas;
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return false;
}


It turns out that the only thing I needed to do is to prevent characters with spaces from being declared entirely.

Thanks for the help.
Last edited on
1
2
3
									//erasing any unecissary space
									for (int i = 0; i < pas.length(); i++)
										if (pas[i] == ' ') pas.erase(i, 1);


If there are consecutive spaces, you have a problem. This is not a natural fit for a for loop:

1
2
3
4
5
6
7
8
9
    //erasing any unecissary space
    std::size_t i = 0;
    while ( i < pas.length() )
    {
        if (pass[i] == ' ')
            pass.erase(i,1);
        else
            ++i;
    }


Or, google the erase-remove idiom.

Of course, you still have a problem. Your code wouldn't detect passwords with spaces in them. A different approach really is required.
1. What do you mean?
2. How many would you like there to be? There's a minimum number required to hold the recursive state.
3. Just a matter of convenience. When writing recursive functions it's often useful to have an entry function that sets up certain data structures required by the algorithm. In this case, it would be a bit of a hassle to declare a helper string every time all_passwords() is called.
4. You can find the reference on this site, just use the search function at the top.
5. Using an unsigned type lets me ignore negative inputs.
6. Recursion is the only way to implement variable-depth loop nesting. It's also the method that produces the cleanest code, as you can see by the relative sizes of our codes.
7. I only used types included in the standard library.

Another possibility that would have been slightly more efficient would have been:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void all_passwords(char *accum, size_t accum_length, size_t max_length, std::function<const char *> &callback){
    size_t i = accum_length - max_length;
	accum[i] = 0;
    callback(accum);
    if (!max_length)
        return;
    for (int i = 32; i < 137; i++){
        accum[i] = (char)i;
        all_passwords(accum, accum_length, max_length - 1, callback);
    }
}

void all_passwords(size_t max_length, std::function<std::string> &callback){
    char *s = new char[max_length + 1];
    all_passwords(accum, max_length, max_length, callback);
    delete[] s;
}

//...

all_passwords(2, [](const char *s){ std::cout << s << std::endl; });
Last edited on
On an issue related to the OP's code, but not the problem he sought to address. Initializing a string with the boolean value false is the same as feeding the constructor an invalid pointer, so if your function fails to find a password and hits that return statement at the end of the function, you're going to run into undefined behavior.

Like so:
http://ideone.com/dEEKVr
Topic archived. No new replies allowed.