为什么这个unhash函数不能反转这个散列?

问题描述:

我写了一个用于密码和密钥生成的散列函数,但很快就意识到能够颠倒散列值是非常有价值的,所以我写了一个相反的函数,但是它的工作量很大。我不明白为什么这个DOESNT工作。为什么这个unhash函数不能反转这个散列?

function hash64(n:uint):uint 
{ 
    n = (~n) + (n << 21); 
    n = n^(n >> 24); 
    n = (n + (n << 3)) + (n << 8); 
    n = n ^(n >> 14); 
    n = (n + (n << 2)) + (n << 4); 
    n = n^(n >> 28); 
    n = n + (n << 31); 
    return n; 
} 

function unhash64(n:uint):uint 
{ 
    n = (~n) - (n >> 21); 
    n = n^(n << 24); 
    n = (n - (n >> 3)) - (n >> 8); 
    n = n^(n << 14); 
    n = (n - (n >> 2)) - (n >> 4); 
    n = n^(n << 28); 
    n = n - (n >> 31); 
    return n; 
} 

输出馈送1000时:

Hashed from 1000:   1221775646 
Unhash output:    1963490760 
+0

你期望什么? 1000? – Organis

+0

是的,这是不可能的吗? – ZxZ

+3

这就是密码学的重点,实际上:它不应该有可能从哈希中重新创建原始数据。否则,在过去的几年里,不是蛮力的,而是它。 – Organis

第一个明显的问题是,它不是在时间镜像。那有时工作(如果操作的顺序并不重要),但通常y = f(g(x))的倒数是x = g⁻¹(f⁻¹(y))。 f最后被应用,所以它必须先被撤消。比较:如果你先穿上你的袜子,然后穿上你的鞋子,那么你应该先脱下你的鞋子然后脱下你的袜子。

此外,许多反向错误开始。例如,
m = n^(n >> 24)的倒数是n = m^(m >> 24),并且m = (n + (n << 2)) + (n << 4)的倒数是n = m * 0x3cf3cf3d(它是modular multiplicative inverse)。这并不像换档的方向那么简单。

没有测试,但这些都是以正确的顺序所有的倒数:

n = n * 0x80000001; 
n = n^(n >> 28); 
n = n * 0x3cf3cf3d; 
n = n^(n >> 14)^(n >> 28); 
n = n * 0x1c03dd39; 
n = n^(n >> 24); 
n = (n + 1) * 0xffdfffff; 

哈希是不可逆的。如果您想要隐藏原始输入的可逆函数,请改为使用加密。只要您拥有正确的密钥,加密就被设计为可逆的。

已经有众所周知的密码和密钥生成技术。如果你试图设计自己的版本,那么他们将是不安全的。这并不重要,所有你想要做的就是把你的小弟弟藏起来。如果你在商业领域工作,那么你可能会被起诉,所以使用所有标准的现有安全方法。您可能需要研究像PBKDF2或argon2这样的密钥派生函数。