11

我遇到了 MessageDigest 在不同计算机上返回不同哈希值的问题。

一台计算机在 Windows Vista 上运行 32 位 Java,另一台在 Mac OS 上运行 64 位 Java。我不确定这是否是因为 MessageDigest 依赖于机器,或者我需要在某处明确指定字符编码,或者可能是其他东西。这是代码:

public static boolean authenticate(String salt, String encryptedPassword, 
    char[] plainTextPassword ) throws NoSuchAlgorithmException {

    // do I need to explcitly specify character encoding here? -->
    String saltPlusPlainTextPassword = salt + new String(plainTextPassword);

    MessageDigest sha = MessageDigest.getInstance("SHA-512");

    // is this machine dependent? -->
    sha.update(saltPlusPlainTextPassword.getBytes());
    byte[] hashedByteArray = sha.digest();

    // or... perhaps theres a translation problem here? -->
    String hashed = new String(hashedByteArray);

    return hashed.equals(encryptedPassword);
}

这段代码是否应该在这两台不同的机器上以不同的方式执行?如果它是我编写的方式依赖于机器,是否有另一种方法散列这些密码更便携?谢谢!

编辑:::::

这是我用来生成盐的代码:

public static String getSalt() {
   int size = 16;
   byte[] bytes = new byte[size];
   new Random().nextBytes(bytes);
   return org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(bytes);
}

解决方案:::

感谢接受的解决方案,我能够修复我的代码:

public static boolean authenticate_(String salt, String encryptedPassword, 
        char[] plainTextPassword ) throws NoSuchAlgorithmException, UnsupportedEncodingException {

        // This was ok
        String saltPlusPlainTextPassword = salt + new String(plainTextPassword);    

        MessageDigest sha = MessageDigest.getInstance("SHA-512");

        // must specify "UTF-8" encoding
        sha.update(saltPlusPlainTextPassword.getBytes("UTF-8"));
        byte[] hashedByteArray = sha.digest();

        // Use Base64 encoding here -->
        String hashed = org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(hashedByteArray);

        return hashed.equals(encryptedPassword);
    }
4

2 回答 2

18

编码给你带来了问题。首先在这里:

saltPlusPlainTextPassword.getBytes()

这将使用机器的默认编码。馊主意。指定“UTF-8”作为一个简单的解决方案。(它保证存在。)

接下来这会导致问题:

String hashed = new String(hashedByteArray);

hashedByteArray是任意二进制数据。要安全地将其转换为文本,请使用 base-64 编码或仅使用十六进制。同样,您当前使用的是默认编码,该编码因机器而异。Java中有大量用于base64编码的第三方库。

于 2010-06-19T21:07:12.053 回答
5

可能上面 Jon Skeet 的解决方案是原因,他的建议绝对应该考虑在内,但另一个可能的原因是对盐的误解。

Salt 是一个半秘密的随机值,在散列之前应用于字符串。这使得在尝试猜测原始字符串是什么时更难执行暴力攻击,因为攻击者可能不知道盐。

盐值通常因安装而异。实际原因可能只是您在不同机器上设置了不同的盐值。

于 2010-06-19T21:11:40.500 回答