Java SHA256输出的哈希值与PHP SHA256不同?

10

PHP代码:

echo hash('sha256', 'jake');

PHP输出结果:

cdf30c6b345276278bedc7bcedd9d5582f5b8e0c1dd858f46ef4ea231f92731d

Java代码:

String s = "jake";
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(s.getBytes(Charset.forName("UTF-8")));
byte[] hashed = md.digest();
String s2 = "";
for (byte b : hashed) {
    s2 += b;
}
System.out.println(s2);

Java输出:

-51-1312107528211839-117-19-57-68-19-39-43884791-1141229-4088-12110-12-223531-11011529

我本来期望这两个会返回相同的结果。显然,情况并非如此。我该如何让它们匹配起来,还是说这是不可能的?

编辑:我犯了一个错误,不过我现在想我已经得出了答案。


2
请检查您的字符编码 - PHP 使用字节,Java 使用 UTF8 还是 UTF16(或其他)? - Piskvor left the building
3个回答

13

首先需要做的是使用一致的字符串编码。我不知道PHP会怎么做,但是"jake".getBytes()将使用Java平台默认的编码方式,这是一个非常糟糕的想法。使用UTF-8可能是一个很好的开始,前提是PHP能够处理Unicode字符串(如果不能,你需要找出它在做什么并尝试使两者保持一致)。在Java中,使用重载的String.getBytes(),其中一个输入参数为Charset或者输入参数为字符集名称的方法。(个人喜欢使用Guava库的Charsets.UTF_8

然后说服PHP也使用UTF-8。

最后,将Java的结果以十六进制输出。我非常怀疑你提供的代码是你实际运行的代码,否则我希望看到比如"[B@e48e1b"之类的输出。无论你用什么方式将byte数组转换成字符串,请更改为使用十六进制。


Python倾向于使用ISO-8859-1,但正在尝试采用Unicode,因此这可能取决于版本。对于“'jake'”这样的全ASCII字符串,应该产生与UTF-8相同的结果。尽管如此,我强烈支持一致的字符串编码要求。 - Thomas Pornin
@Thomas:是的 - 我觉得在处理其他事情之前,首先把这个做对很重要...因为否则,一旦 OP 看到一个“工作”的摘要(例如仅通过将其现有字节数组转换为十六进制),他们可能会决定宣布胜利 :) - Jon Skeet

6

他们正在打印相同的内容..将您的byte[]转换为十六进制字符串,然后您也会看到Java输出的CDF30C6B345276278BEDC7BCEDD9D5582F5B8E0C1DD858F46EF4EA231F92731D:

public void testSomething() throws Exception {
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update("jake".getBytes());
    System.out.println(getHex(md.digest()));
}

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
      return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
      hex.append(HEXES.charAt((b & 0xF0) >> 4))
         .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

2

在打印摘要之前,您需要将其转换为十六进制字符串。可以在此处找到示例代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接