反转哈希函数

时间:2010-12-24 00:46:56

标签: c# algorithm hash

我有以下哈希函数,我正试图改变它,以便我可以从散列值中找到密钥。

uint Hash(string s)
{
    uint result = 0;
    for (int i = 0; i < s.Length; i++)
    {
        result = ((result << 5) + result) + s[i];
    }
    return result;
}

代码在C#中,但我认为很清楚。

我知道对于一个散列值,可以有多个键,但我的意图不是找到它们,只需要满足散列函数就足够了。

编辑:

函数接受的字符串仅由数字0到9以及字符'*'和'#'构成,因此Unhash函数也必须遵守此条件。

有什么想法吗?谢谢。

5 个答案:

答案 0 :(得分:8)

这应该扭转操作:

string Unhash(uint hash)
{
    List<char> s = new List<char>();
    while (hash != 0)
    {
        s.Add((char)(hash % 33));
        hash /= 33;
    }
    s.Reverse();
    return new string(s.ToArray());
}

这应该返回一个字符串,该字符串提供与原始字符串相同的哈希值,但它不太可能是完全相同的字符串。

答案 1 :(得分:3)

字符0-9,*,#具有ASCII值48-57,42,35或二进制:00110000 ... 00111001,00101010,00100011

这些值的前5位是不同的,第6位总是1.这意味着您可以通过获取当前哈希来推断循环中的最后一个字符:

uint lastChar = hash & 0x1F - ((hash >> 5) - 1) & 0x1F + 0x20;

(如果这不起作用,我不知道是谁写的)

现在回滚哈希,

hash = (hash - lastChar) / 33;

并重复循环,直到散列变为零。我没有C#,但我有70%的信心认为这只应该做一些小改动。

答案 2 :(得分:2)

哈希函数被设计为难以或不可能反转,因此名称(可视化肉+土豆被磨碎)

答案 3 :(得分:2)

如果uint为32位,暴力应该有效。尝试至少2 ^ 32个字符串,其中一个可能会散列到相同的值。在现代电脑上只需几分钟。

你有12个可能的字符,12 ^ 9大约是2 ^ 32,所以如果你尝试9个字符串,你可能会找到你的目标哈希。为了安全,我会做10个字符串。

(在C ++中简单的递归实现,不太了解C#)

#define NUM_VALID_CHARS 12
#define STRING_LENGTH 10
const char valid_chars[NUM_VALID_CHARS] = {'0', ..., '#' ,'*'};

void unhash(uint hash_value, char *string, int nchars) {
  if (nchars == STRING_LENGTH) {
    string[STRING_LENGTH] = 0;
    if (Hash(string) == hash_value) { printf("%s\n", string); }
  } else {
    for (int i = 0; i < NUM_VALID_CHARS; i++) {
      string[nchars] = valid_chars[i];
      unhash(hash_value, string, nchars + 1);
    }
  }
}

然后用:

调用它
char string[STRING_LENGTH + 1];
unhash(hash_value, string, 0);

答案 4 :(得分:0)

我首先要写一个result = ((result << 5) + result) + s[i];在单独一行上执行的每一步。这将使解决更容易。然后你所要做的就是每一行的相反(也是相反的顺序)。