【问题标题】:Exact same hashing in java as PHP with salt? (SHA-256)java中的哈希值与带盐的PHP完全相同吗? (SHA-256)
【发布时间】:2014-07-14 18:23:42
【问题描述】:

我可以简单地用盐在 PHP 中散列:

$orig_pw = "abcd";
$salt = 5f8f041b75042e56;
$password = hash('sha256', $orig_pw . $salt);

(我不是这样实现的,这只是一个例子。盐因人而异)

这样,存储的密码是:

bc20a09bc9b3d3e1fecf0ed5742769726c93573d4133dbd91e2d309155fa9929

但是如果我尝试在 Java 中做同样的事情,我会得到不同的结果。我试过String password = "abcd";

byte[] salt = hexStringToByteArray("5f8f041b75042e56");

try {
    System.out.println(new String(getHash(password, salt)));
} catch (NoSuchAlgorithmException e1) {
    e1.printStackTrace();
}

还有两种方法:

public byte[] getHash(String password, byte[] salt) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.reset();
        digest.update(salt);
        try {
            return digest.digest(password.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }


public byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

结果是:

/¬1¶ĆĽëüFd?[$?¶»_9ËZ»ç¶S‘Ęŗש

编码为十六进制的甚至不接近它:

2fac31b6434c14ebfc46643f5b243fb6bb5f39cb5abb10e7b65391454c97d7a90d0a

有人可以帮忙吗?

【问题讨论】:

    标签: java php sha256


    【解决方案1】:

    除了被交换的顺序之外,看起来在 PHP 中您将 salt 值视为要附加到密码的文字字符串,而在 Java 中您首先对 salt 进行十六进制转换,然后使用结果字节来更新MessageDigest。这显然会产生不同的结果。只看盐:

    PHP: Salt -> 到字节(文字)-> SHA-256
    Java: Salt -> 到字节(非十六进制)-> SHA-256

    我刚刚尝试了您的 Java 代码,它绝对没问题。我还尝试在 PHP 中散列与 Java 中相同的值,它给了我相同的结果。

    相当于您的 PHP 代码的 Java 代码是:

    String password = "abcd";
    String salt = "5f8f041b75042e56";
    
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
    
        return digest.digest((password + salt).getBytes("UTF-8"));
    } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
        return null;
    }
    

    对字节进行十六进制处理后,它返回以下结果:

    60359BC8A0B09898335AA5A037B1E1B9CE3A1FE0D4CEF13514901FB32F3BCEB0
    

    在 PHP 中做:

    <?
    echo hash('sha256', "abcd"."5f8f041b75042e56");
    ?>
    

    返回完全相同。

    【讨论】:

    • 我听不懂每个单词(不是英语)。那么我应该改变java中的盐吗? (如:byte[] salt = "5f8f041b75042e56".getBytes();)另外,我如何在 java 中交换它们?
    • 我不知道您的实际 PHP 代码是什么样的(您发布的代码由于裸露的十六进制字符串而无法运行)。但是,您似乎在散列"abcd"."5f8f041b75042e56"。要在 Java 中做同样的事情,你必须做 ("password" + "salt").getBytes("UTF-8") 然后消化它。
    • 对代码很抱歉,这不是它的实现方式。实际代码得到一个随机数: $salt = dechex(mt_rand(0, 2147483647)) 。 dechex(mt_rand(0, 2147483647));
    【解决方案2】:

    我觉得

    digest.update(salt);
    digest.digest(password.getBytes("UTF-8"));
    

    相当于:

    hash('sha256', $salt . $orig_pw);
    

    所以哈希和盐被交换了。你能确认一下吗?

    【讨论】:

    • 是的,我认为它们被交换了。 (如果可能的话,保持这种状态)
    • 你不能只是交换它们,PHP和Java中的输入必须相同。
    • 我的意思是让它在 php 中交换并在 java 中交换。
    猜你喜欢
    • 2014-08-19
    • 1970-01-01
    • 2017-03-16
    • 2023-04-03
    • 1970-01-01
    • 2012-05-20
    • 2023-03-18
    • 1970-01-01
    • 2017-09-20
    相关资源
    最近更新 更多