【发布时间】:2020-04-22 20:04:18
【问题描述】:
我最近一直在搞乱加密和散列,我试图做一些东西来暴力破解 SHA-1 只是使用文本。在编写了基本代码并确认它可以工作之后,我想尝试让它更高效,但是我找不到太多需要提高效率的东西。所以,我做了我认为明智的做法:添加线程。
唯一的问题是,如果有的话,我找不到实现它们的好方法。我尝试了一种实现,尽管使用了几乎 3 倍的 CPU 功率,但它所花费的时间是单线程版本的 10 倍。
所以,如果您愿意看一看并给我一些建议,我将不胜感激。
单线程
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public int tim1;
void setup(){ //This is the main code block.
String input = "9e05e6832caffca519722b608570b8ff4935b94d"; //SHA-1 Hexadecimal Hash to be cracked
String chars = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._!"; //Alphabet to use
int num = 7; //Maximum number of letters to try
tim1=millis(); //Starting timer
println(crack(input,chars,num)); //Cracking the input and outputting the result
println((millis()-tim1)/(float)1000); //Printing how long it took to crack.
}
//This function will take as input, a SHA-1 hash, an alphabet, and a maximum number of characters to test.
//It will either output the original string which converts to the hash, or "Unable to crack" if the given parameters do not lead to it.
String crack(String input, String chars, int num){
byte[] inp = hexStringToByteArray(input); //Converting the input to a byte array.
String output;
for(int i = 1; i<=num;i++){ //Bruteforce all passwords of length i, where i = 1 through num
output = bforce("",chars,i,inp);
if(output!=null){ //If the brute force algorithm outputs anything other than null, then the output is the cracked hash.
return output;
}
}
//If it returns null every time then either we didn't try enough characters, or it contained characters outside of our alphabet.
return "Unable to crack";
}
//This function will take as input, an intermediate string, an alphabet, a number of characters, and a sha-1 byte array to test against.
//It will test every combination of characters from the alphabet that can be added to the end intermediate string
//It only tests for a given length of num.
//To use the function on its own, you should simply provide an empty intermediate string.
//The function will either output null if it couldn't find the input that leads to the hash, or it will output the string that leads to the hash.
String bforce(String inter, String chars, int num,byte[] inp){
//This function will do pretty much all of the computations.
try{ //Try to run this code
String test; //String to be tested.
if(num-inter.length()==1){ //If the intermediate string contains all but one character, then run this code.
for(int i=0;i<chars.length();i++){ //For every character in the given alphabet
test=inter+chars.charAt(i); //Set the test string to the intermediate string + that character
if(bEquals(MessageDigest.getInstance("SHA-1").digest(test.getBytes()),inp)){ //Then convert that string into a SHA-1 Hash and see if it's equal to the input
return test; //If it is, then stop the code and return it.
} //Otherwise, keep going.
}
} else { //Otherwise, run this code.
for(int i=0;i<chars.length();i++){//For every character in the given alphabet
test=bforce(inter+chars.charAt(i),chars,num,inp);//Try every combination of letters after the intermediate string + that character
if(test!=null){//If one of their hashes is equal to the input byte array
return test; //Then stop the code and return it
} // Otherwise, keep going.
}
}
return null; //If the code is still running at this point, it means that we've tried every possibility.
} catch(NoSuchAlgorithmException e) { //If the code gives this specific type of error.
throw new RuntimeException(e); //Then stop the code and print the error.
}
}
//This function simply takes two byte arrays and outputs true if they're equal, or false if they're not.
boolean bEquals(byte[] x,byte[] y){
if(x.length!=y.length){ //If the lengths of the arrays aren't equal,
return false; //Then the arrays can't be equal, so return false and stop here.
} else { //Otherwise,
for(int i = 0;i<x.length;i++){//For every element in the first array
if(x[i]!=y[i]){//If it's not equal to the corresponding element in the second array,
return false;//Then return false and stop here.
}//Otherwise, keep going.
}
return true;//If the code is still running here, then it means that the arrays are equal, so return true.
}
}
//This function is not mine. I borrowed it off the internet, it simply takes a hexadecimal number in the form of a string, and converts it to a binary number in the form of a Byte array.
byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
多线程
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public int tim1;
//Variables which will be used to pass data between threads
Thread thrd1;
Thread thrd2;
Thread thrd3;
MessageDigest msgdig1;
MessageDigest msgdig2;
MessageDigest msgdig3;
public int third1num1;
public int third2num1;
public int third3num1;
public int third1num2;
public int third2num2;
public int third3num2;
public String thread1output = null;
public String thread2output = null;
public String thread3output = null;
public String intermediate1;
public String intermediate2;
public String intermediate3;
public String alphabet1;
public String alphabet2;
public String alphabet3;
public byte[] inpt1;
public byte[] inpt2;
public byte[] inpt3;
void setup(){ //This is the main code block.
String input = "9e05e6832caffca519722b608570b8ff4935b94d"; //SHA-1 Hexadecimal Hash to be cracked
String chars = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._!"; //Alphabet to use
int num = 5; //Maximum number of letters to try
tim1=millis(); //Starting timer
println(crack(input,chars,num)); //Cracking the input and outputting the result
println((millis()-tim1)/(float)1000); //Printing how long it took to crack.
}
//This function will take as input, a SHA-1 hash, an alphabet, and a maximum number of characters to test.
//It will either output the original string which converts to the hash, or "Unable to crack" if the given paramaters do not lead to it.
String crack(String input, String chars, int num){
byte[] inp = hexStringToByteArray(input); //Converting the input to a byte array.
String output;
for(int i = 1; i<=num;i++){ //Bruteforce all passwords of length i, where i = 1 through num
output = bforce("",chars,i,inp);
if(output!=null){ //If the brute force algorithm outputs anything other than null, then the output is the cracked hash.
return output;
}
}
//If it returns null every time then either we didn't try enough characters, or it contained characters outside of our alphabet.
return "Unable to crack";
}
//This function will take as input, an intermediate string, an alphabet, a number of characters, and a sha-1 byte array to test against.
//It will test every combination of characters from the alphabet that can be added to the end intermediate string
//It only tests for a given length of num.
//To use the function on its own, you should simply provide an empty intermediate string.
//The function will either output null if it couldn't find the input that leads to the hash, or it will output the string that leads to the hash.
String bforce(String inter, String chars, int num,byte[] inp){
//This function will do pretty much all of the computations.
if(inter.equals("aaaa")){println("aaaa");}
String test; //String to be tested.
if(inter.equals("")){
//Setting up the threads
thrd1 = new Thread(new thread1());
thrd2 = new Thread(new thread2());
thrd3 = new Thread(new thread3());
//Setting up Message digesters for threads
try{
msgdig1 = MessageDigest.getInstance("SHA-1");
msgdig2 = MessageDigest.getInstance("SHA-1");
msgdig3 = MessageDigest.getInstance("SHA-1");
} catch(NoSuchAlgorithmException e){
throw new RuntimeException(e);
}
//Dividing the alphabet into thirds for the threads to use.
println("mhm");
alphabet1 = chars;
alphabet2 = chars;
alphabet3 = chars;
third3num1 = chars.length();
third1num1 = third3num1/3;
third2num1 = third1num1*2;
third1num2 = third1num1;
third2num2 = third2num1;
third3num2 = third3num1;
//Setting the input for the threads to use
inpt3 = inp;
inpt2 = inp;
inpt1 = inp;
}
if(num-inter.length()==1){ //If the intermediate string contains all but one character, then run this code.
//Provide the intermediate for the threads to use
intermediate1=inter;
intermediate2=inter;
intermediate3=inter;
//Set up the threads
thrd1 = new Thread(new thread1());
thrd2 = new Thread(new thread2());
thrd3 = new Thread(new thread3());
//Run the threads
try{
thrd1.start();
thrd2.start();
thrd3.start();
} catch(Exception e){
println(thrd1.getState());
println(thrd2.getState());
println(thrd3.getState());
throw new RuntimeException(e);
}
//Wait for the other threads to finish
try{
thrd1.join();
thrd2.join();
thrd3.join();
} catch(Exception e) {
throw new RuntimeException(e);
}
if(thread1output!=null){ //If any of the threads found matching strings, then return them and stop the code.
return thread1output;
} else if (thread2output!=null){
return thread2output;
} else if (thread3output!=null){
return thread3output;
}
return null; //Otherwise, return null and stop the code.
} else { //Otherwise, run this code.
for(int i=0;i<chars.length();i++){//For every character in the given alphabet
test=bforce(inter+chars.charAt(i),chars,num,inp);//Try every combination of letters after the intermediate string + that character
if(test!=null){//If one of their hashes is equal to the input byte array
return test; //Then stop the code and return it
} // Otherwise, keep going.
}
}
return null; //If the code is still running at this point, it means that we've tried every possibility.
}
//These threads help spread the workload out across the CPU threads
public class thread1 implements Runnable {
public void run(){ //When this thread is started, run this code.
try { //Try to run this code
for(int i=0;i<third1num1;i++){//For every character in the first third of the alphabet
String test1=intermediate1+alphabet1.charAt(i);//Set the test string to the intermediate string + that character
if(bEquals(msgdig1.digest(test1.getBytes()),inpt1)){//Then convert that string into a SHA-1 Hash and see if it's equal to the input
thread1output=test1;//If it is, then stop the code and return it.
return;
} // Otherwise, keep going.
}
thread1output=null;//If none of the test strings' hashes are equivalent to the input, then set our output to null
return;
} catch (Exception e) { //If there's an error,
throw new RuntimeException(e); //Stop everything and print it.
}
}
}
public class thread2 implements Runnable {
public void run(){ //When this thread is started, run this code.
try { //Try to run this code
for(int i=third1num2;i<third2num1;i++){//For every character in the second third of the alphabet
String test2=intermediate2+alphabet2.charAt(i);//Set the test string to the intermediate string + that character
if(bEquals(msgdig2.digest(test2.getBytes()),inpt2)){//Then convert that string into a SHA-1 Hash and see if it's equal to the input
thread2output=test2;//If it is, then stop the code and return it.
return;
} // Otherwise, keep going.
}
thread2output=null;//If none of the test strings' hashes are equivalent to the input, then set our output to null
return;
} catch (Exception e) { //If there's an error,
throw new RuntimeException(e); //Stop everything and print it.
}
}
}
public class thread3 implements Runnable {
public void run(){ //When this thread is started, run this code.
try { //Try to run this code
for(int i=third2num2;i<third3num1;i++){//For every character in the final third of the alphabet
String test3=intermediate3+alphabet3.charAt(i);//Set the test string to the intermediate string + that character
if(bEquals(msgdig3.digest(test3.getBytes()),inpt3)){//Then convert that string into a SHA-1 Hash and see if it's equal to the input
thread3output=test3;//If it is, then stop the code and return it.
return;
} // Otherwise, keep going.
}
thread3output=null;//If none of the test strings' hashes are equivalent to the input, then set our output to null
return;
} catch (Exception e) { //If there's an error,
throw new RuntimeException(e); //Stop everything and print it.
}
}
}
//This function simply takes two byte arrays and outputs true if they're equal, or false if they're not.
boolean bEquals(byte[] x,byte[] y){
if(x.length!=y.length){ //If the lengths of the arrays aren't equal,
return false; //Then the arrays can't be equal, so return false and stop here.
} else { //Otherwise,
for(int i = 0;i<x.length;i++){//For every element in the first array
if(x[i]!=y[i]){//If it's not equal to the corresponding element in the second array,
return false;//Then return false and stop here.
}//Otherwise, keep going.
}
return true;//If the code is still running here, then it means that the arrays are equal, so return true.
}
}
//This function is not mine. I borrowed it off the internet, it simply takes a hexadecimal number in the form of a string, and converts it to a binary number in the form of a Byte array.
byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
【问题讨论】:
-
我正在仔细观察,但到目前为止,我还没有发现两个不同版本的代码之间的任何区别。第二个版本中哪些方法/行实际上不同?
-
@Bobulous 很抱歉!有时我可能是个空脑袋。我想我复制粘贴了两次相同的东西,但无论如何,我现在修复了这个帖子。
-
仅供参考:您构建程序的方式,具有
thread1类和几乎相同的thread2类和thread3类以及所有这些foo1bar、foo2bar、@ 987654328@ 变量,强烈表明您对编程非常陌生。 IMO,在尝试使用多线程之前,您应该多练习编写单线程程序。
标签: java multithreading performance processing