Skip to content

Instantly share code, notes, and snippets.

@bufferings
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bufferings/8934915 to your computer and use it in GitHub Desktop.
Save bufferings/8934915 to your computer and use it in GitHub Desktop.
package example.mdsample.java;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.StringUtils;
public class MyApp {
public static void main(String[] args) {
// 温めておくと速いのだ
findPasswordOnSingleThread("", "");
// Data
String salt = "hoge";
String hashValue = "4b364677946ccf79f841114e73ccaf4f";
int trialCount = 10;
// Single Thread
System.out.println("Single Thread ====");
int additionalThreadCount = 0;
measure(salt, hashValue, trialCount, additionalThreadCount);
// Multi Thread
System.out.println("Multi Thread ====");
additionalThreadCount = 4;
measure(salt, hashValue, trialCount, additionalThreadCount);
}
static void measure(String salt, String hash, int trialCount,
int additionalThreadCount) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < trialCount; i++) {
long t1 = System.currentTimeMillis();
String password;
if (additionalThreadCount == 0) {
password = findPasswordOnSingleThread(salt, hash);
} else {
password = findPasswordOnMultiThread(salt, hash, additionalThreadCount);
}
long t2 = System.currentTimeMillis();
System.out
.println("password=" + password + " time=" + (t2 - t1) + "[ms]");
}
long endTime = System.currentTimeMillis();
System.out.println("average time=" + (endTime - startTime) / trialCount
+ "[ms]");
}
static final byte[] DIGIT_BYTES = new byte[] { 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39 };
static byte[] convertToDigitBytes(int i) {
return new byte[] { DIGIT_BYTES[(i / 100000) % 10],
DIGIT_BYTES[(i / 10000) % 10], DIGIT_BYTES[(i / 1000) % 10],
DIGIT_BYTES[(i / 100) % 10], DIGIT_BYTES[(i / 10) % 10],
DIGIT_BYTES[i % 10] };
}
static String findPasswordOnSingleThread(String salt, String hash) {
byte[] prefixBytes = (salt + "$").getBytes();
byte[] hashBytes = DatatypeConverter.parseHexBinary(hash);
return new PasswordFinder(prefixBytes, hashBytes, 0, 1).call();
}
static String findPasswordOnMultiThread(String salt, String hash,
int maxThreads) {
byte[] prefixBytes = (salt + "$").getBytes();
byte[] hashBytes = DatatypeConverter.parseHexBinary(hash);
List<PasswordFinder> finders = new ArrayList<>();
for (int i = 0; i < maxThreads; i++) {
finders.add(new PasswordFinder(prefixBytes, hashBytes, i, maxThreads));
}
ExecutorService service = Executors.newFixedThreadPool(maxThreads);
try {
List<Future<String>> futures = service.invokeAll(finders);
for (Future<String> future : futures) {
String password = future.get();
if (password != null) {
return password;
}
}
return null;
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
} finally {
service.shutdown();
}
}
public static class PasswordFinder implements Callable<String> {
final byte[] prefixBytes;
final byte[] hashBytes;
final int start;
final int step;
public PasswordFinder(byte[] prefixBytes, byte[] hashBytes, int start,
int step) {
this.prefixBytes = prefixBytes;
this.hashBytes = hashBytes;
this.start = start;
this.step = step;
}
@Override
public String call() {
return findPassword(prefixBytes, hashBytes, start, step);
}
String findPassword(byte[] prefixBytes, byte[] hashBytes, int start,
int step) {
MessageDigest digester;
try {
digester = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
for (int i = start; i < 1000000; i += step) {
digester.update(prefixBytes);
digester.update(convertToDigitBytes(i));
if (Arrays.equals(hashBytes, digester.digest())) {
return StringUtils.leftPad(String.valueOf(i), 6, '0');
}
}
return null;
}
}
}
@bufferings
Copy link
Author

MBA 1.7 GHz Intel Core i5 で。

Single Thread ====
password=567890 time=221[ms]
password=567890 time=204[ms]
password=567890 time=202[ms]
password=567890 time=210[ms]
password=567890 time=196[ms]
password=567890 time=205[ms]
password=567890 time=203[ms]
password=567890 time=208[ms]
password=567890 time=190[ms]
password=567890 time=201[ms]
average time=204[ms]
Multi Thread ====
password=567890 time=137[ms]
password=567890 time=135[ms]
password=567890 time=131[ms]
password=567890 time=132[ms]
password=567890 time=126[ms]
password=567890 time=139[ms]
password=567890 time=128[ms]
password=567890 time=125[ms]
password=567890 time=131[ms]
password=567890 time=129[ms]
average time=131[ms]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment