我需要一个可逆的哈希函数(显然输入的大小要小于输出),它以一种随机的方式将输入映射到输出。基本上,我想要一种方法将像“123”这样的数字转换为更大的数字,如“9874362483910978”,但不是以保留比较的方式,所以如果x1>,则不能总是如此。 x2,f(x1)> f(x2)(但也不一定总是假的)。
这个用例就是我需要找到一种方法将小数字转换成更大的,随机的数字。它们实际上并不需要是随机的(事实上,它们需要是确定性的,因此相同的输入始终映射到相同的输出),但它们确实需要看起来随机(至少在base64encoded时)转换为字符串,因此移位Z位将无法工作,因为类似的数字将具有类似的MSB)。
此外,简单(快速)计算和反转是一个优点,但不是必需的。
我不知道我是否清楚,或者是否存在这样的算法,但我会感激任何帮助!
答案 0 :(得分:37)
鉴于这个问题,所提供的答案似乎都没有特别有用。我有同样的问题,需要一个简单的,可逆的哈希用于非安全目的,并决定使用位重定位。它很简单,速度很快,并且不需要了解布尔数学或crypo算法或任何其他需要实际思考的内容。
最简单的可能是只剩下一半的位,而另一半则向右移动:
def hash(n):
return ((0x0000FFFF & n)<<16) + ((0xFFFF0000 & n)>>16)
这是可逆的,因为散列(hash(n))= n,并且具有非顺序对{n,m},n <1。 m,其中hash(m)&lt;散列(n)的
为了获得不那么顺序的实现,您可能还需要考虑从[msb,z,...,a,lsb]到[msb,lsb,z,a,...]或[msb,lsb,z,a,...]的交织重新排序lsb,msb,a,z,...]或您认为的任何其他重定位为您处理的数字提供了一个适当的非连续序列。
(上述函数对于适合32位的数字是安全的,更大的数字保证会引起冲突,并且需要更多位掩码覆盖以防止出现问题。也就是说,对于任何非安全性的uid,32位通常就足够了)。
另请参阅下面的Andy Hayden给出的multiplicative inverse答案。
答案 1 :(得分:15)
您要求的是加密。处于其基本操作模式的块密码ECB可逆地将输入块映射到相同大小的输出块。输入和输出块可以解释为数字。
例如,AES是128位分组密码,因此它将输入128位数映射到输出128位数。如果128位足以满足您的需要,那么您只需将输入数字填充到128位,使用AES转换该单个块,然后将输出格式化为128位数。
如果128位太大,您可以使用64位分组密码,如3DES,IDEA或Blowfish。
ECB模式被认为是弱的,但其弱点 是您假定为需求的约束(即,映射是“确定性的”)。这是一个弱点,因为一旦攻击者观察到123映射到9874362483910978,从那时起每当她看到后一个数字时,她就知道明文是123.攻击者可以执行频率分析和/或建立已知明文的字典/密文对。
答案 2 :(得分:9)
另一个简单的解决方案是使用multiplicative inverses (see Eri Clippert's blog):
我们展示了如何使用任意两个互质正整数x和m并计算第三个正整数y,其属性为(x * y)%m == 1,因此(x * z * y)%对于任何正整数z,m == z%m。也就是说,总是存在“乘法逆”,即“撤消”乘以x模m的结果。
我们采取大量例如4000000000和一个大的共素数,例如387420489:
def rhash(n):
return n * 387420489 % 4000000000
>>> rhash(12)
649045868
我们首先使用modinv
计算乘法逆,结果为3513180409:
>>> 3513180409 * 387420489 % 4000000000
1
现在,我们可以定义逆:
def un_rhash(h):
return h * 3513180409 % 4000000000
>>> un_rhash(649045868) # un_rhash(rhash(12))
12
注意:这个答案可以快速计算,适用于最高达4000000000的数字,如果你需要处理更大的数字,请选择一个足够大的数字(和另一个共同素数)。
您可能希望使用十六进制(以打包int):
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
如果你选择一个相对较大的共同素数,那么这将是随机的,非顺序的,也可以快速计算。
答案 3 :(得分:3)
基本上,您正在寻找双向加密,并且可能使用salt
。
您有多种选择:
以下是一个示例:“Simple insecure two-way "obfuscation" for C#
你在看什么语言?如果.NET然后查看加密命名空间的一些想法。
答案 4 :(得分:3)
为什么不只是一个很好的长号的XOR?
易。快速。可逆的。
或者,如果这不需要非常安全,您可以从基数10转换为更小的基数(如基数8或基数4,具体取决于您希望数字的长度)。