我正在尝试用Java破解哈希算法:
public static int encode(String file) {
int hash = 0;
file = file.toUpperCase();
for(int i = 0; i < file.length(); i++) {
hash = (hash * 61 + file.charAt(i)) - 32;
}
return hash;
}
这是我的尝试:
public static String decode(int hash) {
long realHash = (hash < 0 ? Integer.MAX_VALUE + Math.abs(hash) : hash);
ByteBuffer buffer = ByteBuffer.allocate(50);
while (realHash > 0) {
buffer.put((byte) ((realHash % 61) + 32));
realHash = (realHash - 32) / 61;
}
buffer.flip();
return new String(buffer.array()).trim();
}
我的解决方案似乎有严重的数据丢失,我认为由于整数溢出,我不能完全解除更长的文本数据。有什么建议吗?
答案 0 :(得分:8)
这不是整数溢出问题。这就像驾驶熔岩,让你的汽车爆炸,并断定你没有买到合适的汽油。
真正的问题是你不能“破解”哈希算法。有一个重要原因:
信息理论中有一个称为Shannon entropy的术语。 (公平警告:那篇文章不容易通过。)快速版本是编码任何给定信息块所需的最小位数。
This site有一个计算器,声称确定无损编码给定文本所需的熵量(即最小位数)。我为它提供了artisanal filler text:
这一块Meppings牧草苦豆腐,Wes Anderson食品卡车精酿啤酒 苹果手机。单源咖啡场景独角鲸,mumblecore mlkshk牛仔裤 短信嘉信托基金艺术派对你可能还没有听说过 他们苦涩。宝丽来工艺啤酒Intelligentsia,乙烯基Marfa 布鲁克林umami。
假设系统上int
为32位,则只有32位空间来编码任何给定文件。但是上面的那个 - 与我可能使用的相比,如战争与和平或美国代码 - 并不太长,如果你想有任何改造的希望,至少需要 1472位进行编码文本。
(评论员templatetypedef指向Kolmogorov complexity(another good explanation of that concept),这是表示字符串信息内容和破解哈希的无用的更好方式。)
所以信息 - 理论上(并且除了作弊,就像预先填写的压缩字典一样),不可能重建那些少数(简单的手工制作本地来源)来自32位int的句子。不幸的是,这是宇宙的基本定律。不会发生。
Another commentor提到了Pigeonhole Principle - 这个简单的想法,如果你有N个插槽(在这种情况下是2 ^ 32),你不能放两个以上的东西而不放两个或同一时段内的更多事情。
我们来看看你的哈希函数:
public static int encode(String file) {
int hash = 0;
file = file.toUpperCase();
for(int i = 0; i < file.length(); i++) {
hash = (hash * 61 + file.charAt(i)) - 32;
}
return hash;
}
具体来说,这一行:
file = file.toUpperCase();
我想散列两个文件:
mary had a little lamb
Mary Had A Little Lamb
他们的哈希值是多少?想一想。
(旁注:即使说了这些,你 溢出int。:) Modular arithmetic是你的朋友,如果你想做那样的事情。)