是否可以将哈希码限制为Java中特定数量的字符

时间:2013-11-11 11:55:24

标签: java algorithm security md5 message-digest

我编写了一种方法,使用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中设置哈希码的长度?

4 个答案:

答案 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()

将BigInteger向下转换为Long值

它将确保它产生的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位哈希值是相同的。这取决于你真正使用哈希的内容,但我个人觉得这种方法更正确。