Java将哈希转换为随机字符串
我正在尝试开发一种在彩虹表生成器中使用的缩减function。
缩减函数背后的基本原理是它接受散列,执行一些计算,并返回一定长度的字符串。
目前我正在使用SHA1哈希,我需要返回一个长度为3的字符串。 我需要在任意三个随机字符上组成字符串:
abcdefghijklmnopqrstuvwxyz0123456789
我面临的主要问题是我写的任何缩减函数总是返回已经生成的字符串。 一个好的缩减函数只会很少返回重复的字符串。
有人可以提出任何想法来实现这一目标吗? 或者对哈希到字符串操作的任何建议都会很棒。
提前致谢
玩笑
应用KISS原则:
- SHA只是一个字符串
-
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字符散列,同时仍然使其“随机”。
所以听起来你需要将基数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"
当然会有碰撞,就像你将任何空间映射到一个较小的空间时一样,但是熵应该比上面的解决方案更好。