aaron ward aaron ward - 2 months ago 11
Java Question

How to return a value from a Thread to another class

I am currently writing a java application to do a brute force attack on an MD5 hash. I made a JFrame that takes the uses hash input.

Picture 1

for example i hashed the word "password" to MD5. (seen in picture 1) when the JButton is clicked
it will send the hash to a Comparative class that will iterate trough all the possibilities in sequential order. IE go from AAAAAAAA. then to AAAAAAAB and so on. and hashes them. If the hash of the possibility matched the hash of the word "password". A dialog box will appear informing the user that a match has been found.

My problem is that i don't know how to return a value from a thread in a class that

implements Runnable
to the GUI class without using setters and getters.

public void actionPerformed(ActionEvent e)
{
if(e.getSource().equals(bruteForceButton))
{
enterLabel.setText("Brute force in process");

String enteredHash = input.getText();
int lengthOfPass = (int) length.getSelectedItem();

//Send the information to the comparative class
HashComparative comp = new HashComparative();
comp.setHash(enteredHash);
comp.setLengthOfPass(lengthOfPass);
Thread t1 = new Thread(comp);

t1.start();
hash.setText(comp.getHash());
}


this starts the thread sending the appropriate data to the comparative class.
And here is the other class.

public class HashComparative implements Runnable
{

private String h;
private int l;
private Thread thread;


public void start()
{
thread = new Thread(this, "");
thread.start();
}
@Override
public void run()
{
try
{
//CODE WILL GO HERE TO COMPUTE HASHES

setHash(h);
}
catch(Exception e)
{
e.printStackTrace();
}
}

public void setHash(String h)
{
this.h = h;
}
//Returns the hash currently being compared
public String getHash()
{
return h;
}
}


While the brute force is in operation. I want the display the hashes that it tries by sending the hash string back to the GUI class and set the text to a JLabel. For Example

Picture 2

I have looked online but can't find an answer to this. Any help will be appreciated

Answer

What you need to implement is rather Callable instead of Runnable as this interface allows you to return a value which is what you want here. As you can only provide Runnable to a Thread, you need to use a pool thread instead, that you can create from Executors. It will allow you to submit your task as a Callable or a Runnable, and then get a Future to be able to wait until the task is completed successfully or not.

In your case you can create a pool of only one thread using Executors.newSingleThreadExecutor()

ExecutorService executor = Executors.newSingleThreadExecutor();
...

Then your class HashComparative will be:

public class HashComparative implements Callable<String> {
    private final String enteredHash;
    private final int lengthOfPass;

    public HashComparative(final String enteredHash, final int lengthOfPass) {
        this.enteredHash = enteredHash;
        this.lengthOfPass = lengthOfPass;
    } 
    @Override
    public String call() throws Exception {
        //CODE WILL GO HERE TO COMPUTE HASHES
        return h;
    }
    ...
}

And finally you will submit your task as next:

HashComparative comp = new HashComparative(enteredHash, lengthOfPass);
Future<String> future = executor.submit(comp);
hash.setText(future.get());

What can be used to display the unmatching hashes?

The design pattern that matches the best with this kind of need is Observer. Indeed here you want to make your UI observes the progress of your computation. Out of the box, you have Observable and Observer that you can use to implement this pattern.

So here for the sake of simplicity, you could make your class HashComparative extends Observable to be able to notify the Observers (your UI here) any time a new hash is being processed.

public class HashComparative extends Observable implements Callable<String> {

    private String h;

    ...

    public void setHash(String h) {
        this.h = h;
        setChanged();
        notifyObservers();
    }

    public String getHash() {
        return h;
    }
}

Then in your UI, you can change the text accordingly by implementing Observer

HashComparative comp = new HashComparative(enteredHash, lengthOfPass);
comp.addObserver(new Observer() {
    @Override
    public void update(final Observable o, final Object arg) {
        HashComparative hc = (HashComparative)o;
        hash.setText(hc.getHash());
    }
});