java MessageDigest 在不同机器上的散列不同

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3077196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:15:42  来源:igfitidea点击:

MessageDigest hashes differently on different machines

javahashconsistent-hashing

提问by Chris Dutrow

I'm having a problem with MessageDigest returning different hash values on different computers.

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

One computer is running 32-bit Java on Windows Vista and the other is running 64-bit Java on Mac OS. I'm not sure if it is because MessageDigest is machine dependent, or I need to explicitly specify a character encoding somewhere, or perhaps something else. Here's the code:

一台计算机在 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);
}

Should this code execute differently on these two different machines? If it is machine dependent the way I've written it, is there another way hash these passwords that is more portable? Thanks!

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

Edit:::::

编辑:::::

This is the code I'm using to generate the salts:

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

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);
}

Solution:::

解决方案:::

Thanks to the accepted solution, I was able to fix my code:

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

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);
    }

回答by Jon Skeet

Encodings are causing you problems. First here:

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

saltPlusPlainTextPassword.getBytes()

That will use the default encoding for the machine. Bad idea. Specify "UTF-8" as a simple solution. (It's guaranteed to be present.)

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

Next this causes issues:

接下来这会导致问题:

String hashed = new String(hashedByteArray);

hashedByteArrayis arbitrary binary data. To safely convert it to text, either use a base-64 encoding or just hex. Again, you're currently using the default encoding, which will vary from machine to machine. There are loads of 3rd party libraries for base64 encoding in Java.

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

回答by tschaible

Likely Jon Skeet's solution above is the cause, and his recommendations should definitely be taken into account, but another possible cause is a misunderstanding of salt.

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

Salt is a semi-secret random value that is applied to a String prior to hashing. This makes it harder to perform a brute force attack when trying to guess what an originating String was because the salt is presumably unknown to the attacker.

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

Salt values generally differ installation to installation. Its possible that the actual cause is just that you have the salt values set differently on the different machines.

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