Pour le code:
Je tiens à rappeller que je n'ai pas voulu le rendre lisible, conforme à un standard quelconque ni même à maintenir les noms de mes variables cohérents avec les évolutions de mon algo. (oui, c'est mal.)
package fr.octopoid.ssdg.stringtools.brute;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class searchForMD5Sums {
private static final String findableString = "bonj";
private static final byte[] target = searchForMD5Sums.buildDigest().digest(
searchForMD5Sums.findableString.getBytes());
// ici, ton nombre de coeurs proc (-1 si tu veux pouvoir utiliser ta
// machine)
private static final int MAX_POOL_SIZE = 7;
// Ici, un nombre choisi au pifomètre pour éviter un overhead entre chaque
// test de combinaisons
private static final int BATCH_SIZE = 65536;
// j'utilise un logger. System.out serait tout aussi bien.
static final Logger l = LoggerFactory.getLogger(searchForMD5Sums.class);
// Là, le CallerRunsPolicy est la partie intéressante, Elle évite d'ignorer
// des jobs.
static final ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(searchForMD5Sums.MAX_POOL_SIZE,
searchForMD5Sums.MAX_POOL_SIZE, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(
searchForMD5Sums.MAX_POOL_SIZE * 100),
new ThreadPoolExecutor.CallerRunsPolicy());
/**
* pousse un ensemble de lots de calculs et le prochain AddNextWork (des
* fois qu'on aie pas trouvé)
*/
private static final class AddNextWork implements Runnable {
// Je travaille avec des BigInteger parceque je ne voulais pas
// me limiter aux 2^64 premiers essais et que faire soit même
// le calcul du tableau de Bytes était fastidieu.
private final BigInteger nextTry;
private AddNextWork(final BigInteger nextTry) {
this.nextTry = nextTry;
}
/**
* Ajoute 8 lots de calculs avant d'ajouter la tâche insérant les 8 lots
* d'après.
*/
@Override
public void run() {
for (int a = 0; a < 8; a++) {
searchForMD5Sums.threadPoolExecutor.execute(new MD5Runnable(
this.nextTry.add(BigInteger
.valueOf(searchForMD5Sums.BATCH_SIZE * a))));
}
final AddNextWork nextCommand =
new AddNextWork(this.nextTry.add(BigInteger
.valueOf(searchForMD5Sums.BATCH_SIZE * 8)));
searchForMD5Sums.threadPoolExecutor.execute(nextCommand);
}
}
// Que je sache, MessageDigest n'est pas thread safe, du coup, Threadlocal
// en crée un par thread.
private static final ThreadLocal<MessageDigest> local =
new ThreadLocal<MessageDigest>() {
@Override
protected MessageDigest initialValue() {
return searchForMD5Sums.buildDigest();
};
};
/**
* Traite un lot de calculs de sommes MD5 et arrête le travail si la chaine
* d'entrée est trouvée.
*/
private static final class MD5Runnable implements Runnable {
private final BigInteger string;
private MD5Runnable(final BigInteger bigInteger) {
this.string = bigInteger;
}
@Override
public void run() {
final MessageDigest messageDigest = searchForMD5Sums.local.get();
for (int add = 0; add < searchForMD5Sums.BATCH_SIZE; add++) {
final byte[] toTest =
this.string.add(BigInteger.valueOf(add)).toByteArray();
final byte[] digest = messageDigest.digest(toTest);
if (Arrays.equals(searchForMD5Sums.target, digest)) {
searchForMD5Sums.l.info(" {} - {} ", new String(toTest),
Hex.encodeHexString(digest));
searchForMD5Sums.threadPoolExecutor.shutdownNow();
break;
}
}
}
}
public static void main(final String[] args) throws InterruptedException {
final long start = System.currentTimeMillis();
searchForMD5Sums.threadPoolExecutor.execute(new AddNextWork(
BigInteger.ZERO));
searchForMD5Sums.threadPoolExecutor.awaitTermination(Long.MAX_VALUE,
TimeUnit.DAYS);
searchForMD5Sums.l.info("Run Time : {}",
(System.currentTimeMillis() - start) / 1000);
}
private static MessageDigest buildDigest() {
try {
return MessageDigest.getInstance("MD5");
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
return null;// oui, c'est de la lâcheté que de transformer une vrai
// exception en une nullpointerexception. Heureusement,
// ceci est du code jouet
}
}
}