给定用于修改字符串的方法,如何将修改后的字符串反转回 MD5 哈希?
How to reverse modified string back into MD5 hash given the method used to modify the string?
我正在处理一些 MD5 散列,这些散列已使用下面显示的方法转换为数字序列。鉴于下面的代码和示例哈希,我如何 "reverse" getString()
方法的效果并将数字序列转回 MD5 哈希?
例如encrypt("umadbro");
returns "1518918615824625494170109603025017352201241" 因为MD5哈希是通过getString()
方法传递的。 "umadbro" 的 MD5 散列为 9759ba9ef6fe5eaa6d3c1efaad34c9f1。我需要一种方法,该方法采用 getString()
方法修改的一串数字并将其转换为其 MD5 哈希。例如:reverseMethod("1518918615824625494170109603025017352201241");
应该输出“9759ba9ef6fe5eaa6d3c1efaad34c9f1”(输入参数是修改后的数字字符串,输出是原始字符串的MD5散列)。 注意:我不是在寻找破解 MD5 哈希的方法。我只需要一个方法来反转下面显示的 getString()
方法的效果。
public String encrypt(String source)
{
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(source.getBytes());
return getString(bytes);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private String getString(byte[] bytes) //this takes an md5 hash and turns it into a string of numbers.
// How can I reverse the effect of this method?
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
sb.append(0xFF & b);
}
return sb.toString();
}
如果不尝试所有组合并进行比较,这是不可能的。问题是 getString
不是 return 对于给定的哈希值作为字节唯一的数字。
例如,如果字节的值为 0216
十六进制,则 02
在十进制字符串编码中变为 "2"
,而 16
变为 "22"
。因此,您的方法将 return "222"
作为两者的串联。现在,如果我们对 1602
做同样的事情,那么它会产生 "22"
和 "2"
,并且串联仍然会产生 "222"
。这可能发生在字节数组中的每个字节组合上。
因此,尽管结果可能仍然是相对安全的散列,但发现冲突的机会 多 更高。您可以做的是 return 一大组哈希值,其中 1 个将导致匹配,但需要大量计算;如果你想比较你最好把你的结果通过 getString
并比较安全性低得多的散列(甚至比 MD5 更不安全)。
我尝试编写一些代码来查找所有可能的组合,结果发现比我预期的要少得多。在这种情况下只有 2 个。而且找到它们只需要很少的时间。
import java.util.ArrayList;
import java.util.Arrays;
public class Comb {
static long combinations(String str, int startIdx, int numBytes, ArrayList<byte[]> combinations, byte[] combination) {
if(startIdx >= str.length()) {
if(numBytes == 16) {
combinations.add(combination.clone());
return 1;
} else return 0;
}
if(numBytes > 15) return 0;
combination[numBytes] = (byte)(str.charAt(startIdx) - '0');
long result = combinations(str, startIdx + 1, numBytes + 1, combinations, combination);
if(startIdx < str.length() - 1 && str.charAt(startIdx) != '0') {
combination[numBytes] = (byte)((str.charAt(startIdx) - '0') * 10 + (str.charAt(startIdx + 1) - '0'));
result += combinations(str, startIdx + 2, numBytes + 1, combinations, combination);
}
if(startIdx < str.length() - 2) {
combination[numBytes] = (byte)((str.charAt(startIdx) - '0') * 100 + (str.charAt(startIdx + 1) - '0') * 10 + (str.charAt(startIdx + 2) - '0'));
if(str.charAt(startIdx) == '1') result += combinations(str, startIdx + 3, numBytes + 1, combinations, combination);
if(str.charAt(startIdx) == '2' &&
(str.charAt(startIdx + 1) < '5' || str.charAt(startIdx + 1) == '5' && str.charAt(startIdx + 2) < '6')) {
result += combinations(str, startIdx + 3, numBytes + 1, combinations, combination);
}
}
return result;
}
public static void main(String[] args) {
ArrayList<byte[]> combinations = new ArrayList<>();
System.out.println(combinations("1518918615824625494170109603025017352201241", 0, 0, combinations, new byte[16]));
for(byte[] c: combinations) {
System.out.println(Arrays.toString(c));
}
}
}
这个输出是:
2
[15, -67, -70, -98, -10, -2, 94, -86, 109, 60, 30, -6, -83, 52, -55, -15]
[-105, 89, -70, -98, -10, -2, 94, -86, 109, 60, 30, -6, -83, 52, -55, -15]
它找到的第二个解决方案确实是正确的。
我正在处理一些 MD5 散列,这些散列已使用下面显示的方法转换为数字序列。鉴于下面的代码和示例哈希,我如何 "reverse" getString()
方法的效果并将数字序列转回 MD5 哈希?
例如encrypt("umadbro");
returns "1518918615824625494170109603025017352201241" 因为MD5哈希是通过getString()
方法传递的。 "umadbro" 的 MD5 散列为 9759ba9ef6fe5eaa6d3c1efaad34c9f1。我需要一种方法,该方法采用 getString()
方法修改的一串数字并将其转换为其 MD5 哈希。例如:reverseMethod("1518918615824625494170109603025017352201241");
应该输出“9759ba9ef6fe5eaa6d3c1efaad34c9f1”(输入参数是修改后的数字字符串,输出是原始字符串的MD5散列)。 注意:我不是在寻找破解 MD5 哈希的方法。我只需要一个方法来反转下面显示的 getString()
方法的效果。
public String encrypt(String source)
{
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(source.getBytes());
return getString(bytes);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private String getString(byte[] bytes) //this takes an md5 hash and turns it into a string of numbers.
// How can I reverse the effect of this method?
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
sb.append(0xFF & b);
}
return sb.toString();
}
如果不尝试所有组合并进行比较,这是不可能的。问题是 getString
不是 return 对于给定的哈希值作为字节唯一的数字。
例如,如果字节的值为 0216
十六进制,则 02
在十进制字符串编码中变为 "2"
,而 16
变为 "22"
。因此,您的方法将 return "222"
作为两者的串联。现在,如果我们对 1602
做同样的事情,那么它会产生 "22"
和 "2"
,并且串联仍然会产生 "222"
。这可能发生在字节数组中的每个字节组合上。
因此,尽管结果可能仍然是相对安全的散列,但发现冲突的机会 多 更高。您可以做的是 return 一大组哈希值,其中 1 个将导致匹配,但需要大量计算;如果你想比较你最好把你的结果通过 getString
并比较安全性低得多的散列(甚至比 MD5 更不安全)。
我尝试编写一些代码来查找所有可能的组合,结果发现比我预期的要少得多。在这种情况下只有 2 个。而且找到它们只需要很少的时间。
import java.util.ArrayList;
import java.util.Arrays;
public class Comb {
static long combinations(String str, int startIdx, int numBytes, ArrayList<byte[]> combinations, byte[] combination) {
if(startIdx >= str.length()) {
if(numBytes == 16) {
combinations.add(combination.clone());
return 1;
} else return 0;
}
if(numBytes > 15) return 0;
combination[numBytes] = (byte)(str.charAt(startIdx) - '0');
long result = combinations(str, startIdx + 1, numBytes + 1, combinations, combination);
if(startIdx < str.length() - 1 && str.charAt(startIdx) != '0') {
combination[numBytes] = (byte)((str.charAt(startIdx) - '0') * 10 + (str.charAt(startIdx + 1) - '0'));
result += combinations(str, startIdx + 2, numBytes + 1, combinations, combination);
}
if(startIdx < str.length() - 2) {
combination[numBytes] = (byte)((str.charAt(startIdx) - '0') * 100 + (str.charAt(startIdx + 1) - '0') * 10 + (str.charAt(startIdx + 2) - '0'));
if(str.charAt(startIdx) == '1') result += combinations(str, startIdx + 3, numBytes + 1, combinations, combination);
if(str.charAt(startIdx) == '2' &&
(str.charAt(startIdx + 1) < '5' || str.charAt(startIdx + 1) == '5' && str.charAt(startIdx + 2) < '6')) {
result += combinations(str, startIdx + 3, numBytes + 1, combinations, combination);
}
}
return result;
}
public static void main(String[] args) {
ArrayList<byte[]> combinations = new ArrayList<>();
System.out.println(combinations("1518918615824625494170109603025017352201241", 0, 0, combinations, new byte[16]));
for(byte[] c: combinations) {
System.out.println(Arrays.toString(c));
}
}
}
这个输出是:
2
[15, -67, -70, -98, -10, -2, 94, -86, 109, 60, 30, -6, -83, 52, -55, -15]
[-105, 89, -70, -98, -10, -2, 94, -86, 109, 60, 30, -6, -83, 52, -55, -15]
它找到的第二个解决方案确实是正确的。