关于python:可逆哈希函数?

Reversible hash function?

我需要一个可逆的哈希函数(显然输入的大小要比输出的小得多),它以随机的方式将输入映射到输出。基本上,我希望有一种方法可以将"123"这样的数字转换为"9874362483910978"这样的更大数字,但不能以保存比较的方式进行转换,因此,如果x1>x2,f(x1)>f(x2)(但两者都不一定总是错的)这一点不一定总是正确的。

这方面的用例是,我需要找到一种方法,将小数字转换成大的、随机的数字。它们实际上不需要是随机的(事实上,它们需要具有确定性,因此相同的输入总是映射到相同的输出),但它们确实需要看起来是随机的(至少当base64编码到字符串中时,因此Z位的移位不会起作用,因为相似的数字将具有相似的MSB)。

此外,简单(快速)计算和逆转是一个优势,但不是必需的。

我不知道我是否清楚,或者是否存在这样的算法,但我会感谢任何和所有的帮助!


考虑到这个问题,所提供的答案似乎没有一个特别有用。我也遇到了同样的问题,需要一个简单的、可逆的哈希来实现不安全的目的,然后决定进行位重定位。它很简单,速度很快,而且不需要知道任何关于布尔数学或crypo算法的知识,或者任何其他需要实际思考的知识。

最简单的方法可能是左移一半位,右移另一半位:

1
2
def hash(n):
  return ((0x0000FFFF & n)<<16) + ((0xFFFF0000 & n)>>16)

这是可逆的,在散列(hash(n))=n中,具有非顺序对n,m,n

为了获得一个不那么顺序的实现,您可能还需要考虑从[msb,z,…,a,lsb]到[msb,lsb,z,a,…]或[lsb,msb,a,z,…]的交错重新排序,或者您认为为您处理的数字提供了一个适当的非顺序序列的任何其他重定位。

(上述功能对于32位的数字是安全的,较大的数字保证会引起冲突,并且需要更多的位屏蔽覆盖来防止问题发生。也就是说,32位通常足够用于任何非安全的uid)。

还可以看看下面安迪·海登给出的乘法逆解。


你要求的是加密。块密码在其基本操作模式ECB中,可逆地将输入块映射到相同大小的输出块上。输入和输出块可以解释为数字。

例如,aes是一个128位的块密码,因此它将输入的128位数字映射到输出的128位数字上。如果128位对于您的目的足够好,那么您可以简单地将输入数字填充到128位,用AES转换单个块,然后将输出格式化为128位数字。

如果128位太大,可以使用64位块密码,如3DES、IDEA或Blowfish。

ECB模式被认为是弱的,但它的弱点是您假定为需求的约束(即映射是"确定性的")。这是一个弱点,因为一旦攻击者发现123映射到9874362483910978,从那时起每当她看到后一个数字,她就知道明文是123。攻击者可以执行频率分析和/或建立已知明文/密文对的字典。


另一个简单的解决方案是使用乘法逆(参见eri clippert的博客):

we showed how you can take any two coprime positive integers x and m and compute a third positive integer y with the property that (x * y) % m == 1, and therefore that (x * z * y) % m == z % m for any positive integer z. That is, there always exists a"multiplicative inverse", that"undoes" the results of multiplying by x modulo m.

我们取一个较大的数字,例如4000000000,而一个较大的联合质数,例如387420489:

1
2
3
4
5
def rhash(n):
    return n * 387420489 % 4000000000

>>> rhash(12)
649045868

我们首先用modinv计算乘法逆,结果是3513180409:

1
2
>>> 3513180409 * 387420489 % 4000000000
1

现在,我们可以定义反转:

1
2
3
4
5
def un_rhash(h):
    return h * 3513180409 % 4000000000

>>> un_rhash(649045868)  # un_rhash(rhash(12))
12

注意:这个答案计算速度很快,适用于4000000000以下的数字,如果需要处理更大的数字,请选择一个足够大的数字(和另一个辅素数)。

您可能需要对十六进制进行此操作(打包int):

1
2
3
4
5
6
7
8
9
10
11
def rhash(n):
    return"%08x" % (n * 387420489 % 4000000000)

>>> rhash(12)
'26afa76c'

def un_rhash(h):
    return int(h, 16) * 3513180409 % 4000000000

>>> un_rhash('26afa76c')  # un_rhash(rhash(12))
12

如果你选择一个相对较大的余素数,那么这看起来是随机的,不是连续的,而且计算起来也很快。


为什么不把XOR和一个很长的数字放在一起呢?

容易的。快。可逆的。

或者,如果这不需要非常安全,可以将基数10转换为较小的基数(如基数8或基数4,具体取决于您希望数字的长度)。


基本上,您正在寻找双向加密,并且可能使用salt

您有许多选择:

  • 三元组
  • 俄歇电子能谱
  • 下面是一个例子:"简单的不安全的双向"模糊C#

    你在看什么语言?如果是.NET,请查看加密命名空间以了解一些想法。