If you goto : http://www.hanewin.net/encrypt/aes/aes-test.htm
for "Key in Hex" enter 00000000000000000000000000000056
for "Plaintext in Hex" enter 00000000000000000000000000000000
and click on "Encrypt" you get: 1bb171d2afef6e7f1ccb895ee9b35fe0
The password "56" is a two hex characters that was encrypted with a key of all zeros.
I am trying to implement the pre-computed hashes described here:
http://en.wikipedia.org/wiki/Rainbow_table
so that I can "discover" the password "56" given the encrypted hash (1bb171d2afef6e7f1ccb895ee9b35fe0)and key (00000000000000000000000000000000).
According to the algorithm on the wikipedia page, once all the end points are computed, you reduced the hash given to you and check if it exists in one of your end points. If so, get the corresponding starting point for the matching end point and compute the chain until you reach the hash (1bb171d2afef6e7f1ccb895ee9b35fe0). The password should be the one preceding this hash in the chain.
When I run my program I keep getting "00000000000000000000000000000084" as the password but when I hash it I get "1bf162058f3d909cddab3debd64ff2c4", which is not equal to the hash we are looking for. But I think it is interesting the first two characters "1b" are the same as the first two characters of the hash I am interested in finding.
I feel like I am really close but I'm missing an important piece of this algorithm. I was wondering if someone could point me in the right direction.
My code is below:
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class RainbowCrack {
public static TreeMap<String, String> map = new TreeMap<String, String>();
public static final String myPassword = "00000000000000000000000000000056";
public static final String plaintextHex = "00000000000000000000000000000000";
public static final String hash1 = "1bb171d2afef6e7f1ccb895ee9b35fe0".toUpperCase();
public static int m = 500;
public static int t = 500;
public static void main(String args[]) throws Exception {
String[] SPi = new String[m];
String[] EPi = new String[m];
Random randomGenerator = new Random();
for (int x = 0; x < m; x++) {
int randomHex = randomGenerator.nextInt(255);
String currRandomStrHexVal = String.format("%032x", randomHex);
SPi[x] = getHashStr(currRandomStrHexVal);
String currHash = SPi[x];
for (int chain = 0; chain < t; chain++) {
// reduce hash to a 2 characters (in order to simulate another potential password)
currHash = R_low30(currHash);
// perform AES
currHash = getHashStr(currHash);
}
EPi[x] = currHash;
// store map (endpoint -> starting point)
map.put(EPi[x], SPi[x]);
}
// pre compuated table completed
String origHash = hash1;
int distanceFromEndpoint=0;
while (distanceFromEndpoint != t){
// check if the original hash is one of the endpoints
if (map.containsKey(origHash)){
// compute # of times to iterate through chian
int numIterations = t - distanceFromEndpoint - 1;
String startingPoint = map.get(origHash);
for (int currChain=0;currChain < numIterations; currChain++){
startingPoint = R_low30(startingPoint);
startingPoint = getHashStr(startingPoint);
}
System.out.print("potential password = " + R_low30(startingPoint));
System.out.println(" hashes to " + getHashStr(R_low30(startingPoint)));
if (getHashStr(R_low30(startingPoint)).equalsIgnoreCase(hash1)){
System.out.println("Done");
break;
}
else{
System.out.println("Keep looking...");
origHash = R_low30(origHash);
origHash = getHashStr(origHash);
distanceFromEndpoint++;
}
}
// original hash is not one of the endpoints
else {
// perform H(R(origHash)) to prepare for next round of searching
origHash = R_low30(origHash);
origHash = getHashStr(origHash);
distanceFromEndpoint++;
}
}
}
public static String bytesToString(byte[] byteArr) {
if (byteArr == null) {
return null;
}
return DatatypeConverter.printHexBinary(byteArr);
}
public static byte[] stringToBytes(String str) {
if (str == null) {
return null;
}
return DatatypeConverter.parseHexBinary(str);
}
public static String getHashStr(String str) throws Exception {
SecretKey key1 = new SecretKeySpec(DatatypeConverter.parseHexBinary(str), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key1);
byte[] currEndPoint = cipher.doFinal(DatatypeConverter.parseHexBinary(plaintextHex));
return bytesToString(currEndPoint);
}
private static String R_low30(String str) {
if (str == null) {
return null;
} else {
return "000000000000000000000000000000" + str.substring(0, str.length() - 30); // chop off 104 bits from 128 = 24 bits = 6 hex chars
}
}
The password "56" is a two hex characters that was encrypted with a key of all zeros.
you mix key and plaintext.