HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Brute force passwords in Java

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
brutepasswordsforcejava

Problem

I made this little code to see what brute forcing is like. I made this with a complete guess on how it works. This code works fine but it seems to take much much longer than it really should. I have the Scanner there so I can tell the program what password it is searching for. I have the timeMillis also just for personal reasons to see how long it takes to find a password.

I have the

System.out.println(newPass);


to see if I ever run into errors where would I run into it. The way my code works is that it loops chars^length times until it hits the password.

If there is any way I can improve this?

```
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

public class Main {
static String newPass = "";
static String chars = "0123456789aABbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyzZ";

public static void main(String[] args) {
Scanner userIn = new Scanner(System.in);
String password = userIn.nextLine();
System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
String choose = userIn.nextLine();
boolean decideSymb = true;
boolean again = true;
while (again == true) {
if (choose.equalsIgnoreCase("y")) {
again = false;
} else if (choose.equalsIgnoreCase("n")) {
again = false;
decideSymb = false;
} else {
System.out.println("Try again! \nIs using symbols an option? if so type in [Y] if not type in [N]");
choose = userIn.nextLine();
}
}
long start = System.currentTimeMillis();
crack(password, decideSymb);
long end = System.currentTimeMillis();
long milliSecs = TimeUnit.MILLISECONDS.toSeconds(end - start);
;
long secs = milliSecs / 1000;
long mins = secs / 60;
long hours = mins / 60;
long days = hours / 24;
long years = days / 365;

Solution

Do while you must

System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
    String choose = userIn.nextLine();
    boolean decideSymb = true;
    boolean again = true;
    while (again == true) {
        if (choose.equalsIgnoreCase("y")) {
            again = false;
        } else if (choose.equalsIgnoreCase("n")) {
            again = false;
            decideSymb = false;
        } else {
            System.out.println("Try again! \nIs using symbols an option? if so type in [Y] if not type in [N]");
            choose = userIn.nextLine();
        }
    }


You have some awkward-feeling repeated code in here (the prompt for input). This can be refactored into a cleaner, more natural feeling do/while loop:

do {
    System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
    String choose = userIn.nextLine();
} while(!choose.equalsIgnoreCase("y") && !choose.equalsIgnoreCase("n"));


By changing this to a do/while, we were able to remove those clunky if statements along with the two flag variables.

The above loop will continuously ask for input until proper input is given.
Or use a pattern you can

Instead of using a loop to shorten the above code, you could use the Scanner's built-in next(Pattern pattern). This will ensure that you only get input that follows your specified pattern.

First, create a final Pattern in a class field so you can easily access it in the code:

public static final Pattern yesOrNo = Pattern.compile("(y|n)", CASE_INSENSITIVE);


The above regex should only pass for either y, n, Y, or N. Also, it may be better to compile the regex in the main method itself.

Then, in your code, instead of having the loop, you can simply write:

System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
String choose = userIn.next(yesOrNo);


I believe this is a much better solution.

Too far for a single letter

if (years == 1) {
            System.out.println("it took\n" + years + "year\n" + days + " days\n" + hours + " hours\n" + mins
                    + " mins\n" + secs + " secs\n" + milliSecs + " milliseconds\nto find the password");
        } else {
            System.out.println("it took\n" + years + "years\n" + days + " days\n" + hours + " hours\n" + mins
                    + " mins\n" + secs + " secs\n" + milliSecs + " milliseconds\nto find the password");
        }


You have two entirely separate conditional statements just to add a single character? That's a waste, and it makes your code look ugly.

Honestly, I don't think you'll even need to worry about that "s".

  • The chances of it being exactly 1 are very low.



  • It's such a small thing that most applications ignore.



However, if you really want to have that "s" there, use a ternary instead:

System.out.println("it took\n" + years + "year" + (years == 1 ? "s" : "") + "\n" + days + " days\n" + hours + " hours\n" + mins + " mins\n" + secs + " secs\n" + milliSecs + " milliseconds\nto find the password");


The date is exactly...

This chunk of code here:

long secs = milliSecs / 1000;
    long mins = secs / 60;
    long hours = mins / 60;
    long days = hours / 24;
    long years = days / 365;
    days -= (years * 365);
    hours -= (days * 24);
    mins -= (hours * 60);
    secs -= (mins * 60);


Doesn't belong. It should be extracted into a separate method that accepts the milliSecs variable. As for returning, it could probably return a custom class that looks like this:

public class TimeData {
    private final long secs;
    private final long mins;
    ...
}


with getters for each field. This will make your code more OO.

If you want to be extra OOP-y, you can put the method that generates the TimeData in this TimeData class, make it static, and have it return an instance of TimeData with filled data.
Over-complicating the time printing

Again, you are over-complicating the time printing section. In my opinion, it is perfectly okay to have something like:

"It took 0 days, 0 hours, 24 minutes, 13 seconds, and 1 millisecond."

Those 0's there don't harm the UI at all. Instead of having that huge conditional chain in your code, you should just use System.out.printf and print out all the time values you have.

Going back to OOP, you could extract this into the TimeData's toString method.

Code Snippets

System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
    String choose = userIn.nextLine();
    boolean decideSymb = true;
    boolean again = true;
    while (again == true) {
        if (choose.equalsIgnoreCase("y")) {
            again = false;
        } else if (choose.equalsIgnoreCase("n")) {
            again = false;
            decideSymb = false;
        } else {
            System.out.println("Try again! \nIs using symbols an option? if so type in [Y] if not type in [N]");
            choose = userIn.nextLine();
        }
    }
do {
    System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
    String choose = userIn.nextLine();
} while(!choose.equalsIgnoreCase("y") && !choose.equalsIgnoreCase("n"));
public static final Pattern yesOrNo = Pattern.compile("(y|n)", CASE_INSENSITIVE);
System.out.println("Is using symbols an option? if so type in [Y] if not type in [N]");
String choose = userIn.next(yesOrNo);
if (years == 1) {
            System.out.println("it took\n" + years + "year\n" + days + " days\n" + hours + " hours\n" + mins
                    + " mins\n" + secs + " secs\n" + milliSecs + " milliseconds\nto find the password");
        } else {
            System.out.println("it took\n" + years + "years\n" + days + " days\n" + hours + " hours\n" + mins
                    + " mins\n" + secs + " secs\n" + milliSecs + " milliseconds\nto find the password");
        }

Context

StackExchange Code Review Q#114594, answer score: 8

Revisions (0)

No revisions yet.