我正在尝试开发一个缩减函数,以便在彩虹表生成器中使用。
简化函数背后的基本原理是它接受哈希,执行一些计算,并返回一定长度的字符串。
目前我正在使用SHA1哈希,我需要返回一个长度为3的字符串。我需要在以下任意三个随机字符上组成字符串:
abcdefghijklmnopqrstuvwxyz0123456789
我面临的主要问题是我写的任何缩减函数总是返回已经生成的字符串。一个好的缩减函数只会很少返回重复的字符串。
有人可以提出任何有关实现这一目标的想法吗?或者对哈希到字符串操作的任何建议都很棒。
提前致谢
乔什答案 0 :(得分:6)
所以听起来你需要将基数255(SHA1哈希的长度)的20位数字映射到基数36的三位数。我只需从哈希字节中生成BigInteger ,模数36 ^ 3,并在基数36中返回字符串。
public static final BigInteger N36POW3 = new BigInteger(""+36*36*36));
public static String threeDigitBase36(byte[] bs) {
return new BigInteger(bs).mod(N36POW3).toString(36);
}
// ...
threeDigitBase36(sha1("foo")); // => "96b"
threeDigitBase36(sha1("bar")); // => "y4t"
threeDigitBase36(sha1("bas")); // => "p55"
threeDigitBase36(sha1("zip")); // => "ej8"
当然会有碰撞,就像你将任何空间映射到一个较小的空间时一样,但熵应该比上述解决方案更好。
答案 1 :(得分:4)
应用KISS原则:
String
的JDK哈希码是“足够随机”Integer
可以在任何基础上呈现这一行代码就是这样做的:
public static String shortHash(String sha) {
return Integer.toString(sha.hashCode() & 0x7FFFFFFF, 36).substring(0, 3);
}
注意:& 0x7FFFFFFF
将符号位置零(哈希码可以是负数,否则会以前导减号呈现)。
我原来的解决方案是天真的 - 当int
哈希小于100
(基数为36)时,它没有处理这种情况 - 这意味着它将打印少于3个字符。此代码修复了这一点,同时仍保持值“随机”。它还避免了substring()
调用,因此性能应该更好。
static int min = Integer.parseInt("100", 36);
static int range = Integer.parseInt("zzz", 36) - min;
public static String shortHash(String sha) {
return Integer.toString(min + (sha.hashCode() & 0x7FFFFFFF) % range, 36);
}
此代码通过强制它在100
和zzz
之间保证最终散列有3个字符 - 基数36中最低和最高的3字符散列,同时仍然使其“随机”。