我编写了一种方法,使用MD5算法将纯文本转换为哈希码。请找到我用过的代码。
public static String convertToMD5Hash(final String plainText){
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
LOGGER.warn("For some wierd reason the MD5 algorithm was not found.", e);
}
messageDigest.reset();
messageDigest.update(plainText.getBytes());
final byte[] digest = messageDigest.digest();
final BigInteger bigInt = new BigInteger(1, digest);
String hashtext = bigInt.toString(8);
return hashtext;
}
此方法工作正常,但返回冗长的哈希值。我需要将此哈希文本限制为8个字符。是否有可能在Java中设置哈希码的长度?
答案 0 :(得分:7)
是和否。如果您始终将原始哈希字符串相似(即最后/第一个字符为8),则可以使用原始哈希的子字符串。你打算用“半哈希”做什么是另一回事。
无论你要做什么,都要确保它与安全无关。
原因如下:MD5是128位散列,因此有2 ^ 128 = ~340,000,000,000,000,000,000,000,000,000,000,000,000,000种可能的排列。相当天文数字的排列使得这种字符串变得非常不可能。通过减少8个字符,您将最终得到32位哈希。这是因为单个十六进制值需要4位来表示(因此,也是128位/ 4位= 32个十六进制值)。使用32位散列时,只有2 ^ 32 = 4,294,967,296种组合。这比原来的128位散列的安全性 79,228,162,514,264,337,593,543,950,336倍,并且可以在几秒钟内使用任何具有80位计算器处理能力的旧计算机来破解。
答案 1 :(得分:1)
没有。 MD5定义为返回128位值。您可以使用Base64将它们编码为ASCII并使用String#substring(0, 8)
截断它。
在Java 8(尚未正式发布)中,您可以将byte[]
编码为Base64,如下所示:
String base64 = Base64.getEncoder().encodeToString(digest);
对于早期的Java版本,请参阅Decode Base64 data in Java
答案 2 :(得分:0)
当数据的任何部分发生变化时,所有散列算法都应随机更改整个散列中的位。所以你可以从哈希中选择8个字符。只是不要随意挑选它 - 它必须是可重复的
答案 3 :(得分:0)
首先,正如大家所提到的,64位散列不够安全。最终,这取决于你准备用哈希做什么。
如果你仍然需要将其转换为8个字符,我建议使用BigIteger.longValue()
它将确保它产生的long值与生成的哈希值一致。
我不确定从128位散列中取出最重要的64位是不错的主意。我宁愿采用最低64位。这确保了
当hash(128, a) = hash(128, b)
时,hash(64, a) = hash(64, b)
将始终为真。
但是在64位的情况下我们必须忍受冲突,即hash(64, a) = hash(64, b)
然后hash(128, a) = hash(128, b)
并非总是如此。
简而言之,我们确保我们没有两个文本的128位哈希值不同的情况,但它们的64位哈希值是相同的。这取决于你真正使用哈希的内容,但我个人觉得这种方法更正确。