Java SHA256 выводит другой хеш для PHP SHA256?

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

Я ожидал, что они вернут один и тот же результат. Очевидно, это не так. Как я могу заставить их совпадать или это невозможно?

РЕДАКТИРОВАТЬ: я сделал ошибку, думаю, теперь у меня есть ответ на вопрос.


person Finbarr    schedule 13.01.2011    source источник
comment
Проверьте свою кодировку символов - PHP работает с байтами, использует ли Java UTF8 или UTF16 (или что-то еще)?   -  person Piskvor left the building    schedule 13.01.2011


Ответы (3)


Итак, самое первое действие, которое вам нужно сделать, это использовать согласованную кодировку строк. Я понятия не имею, что будет делать PHP, но "jake".getBytes() будет использовать любую кодировку вашей платформы по умолчанию для Java. Это действительно плохая идея. Использование UTF-8, вероятно, было бы хорошим началом, если предположить, что PHP с самого начала справляется со строками Unicode. (Если это не так, вам нужно выяснить, что он делает, и попытаться сделать их согласованными.) В Java используйте перегрузку String.getBytes(), которая принимает Charset, или ту, которая принимает имя Charset. (Лично мне нравится использовать Charsets.UTF_8 Гуавы.)

Затем убедите PHP также использовать UTF-8.

Затем выведите результат Java в шестнадцатеричном формате. Я очень сомневаюсь, что код, который вы дали, является фактическим кодом, который вы используете, так как в противном случае я ожидал бы вывода, такого как «[B@e48e1b». Что бы вы ни делали для преобразования массива байтов в строку, измените его, чтобы использовать шестнадцатеричный формат.

person Jon Skeet    schedule 13.01.2011
comment
Python, как правило, использует ISO-8859-1, но пытается принять Unicode, поэтому это может зависеть от версии. Для 'jake', строки, полностью состоящей из ASCII, это должно дать то же самое, что и UTF-8. Тем не менее, я горячо поддерживаю требование последовательного кодирования строк. - person Thomas Pornin; 13.01.2011
comment
@Thomas: Да, я чувствовал, что важно сделать это правильно сначала, перед остальными ... потому что в противном случае, как только OP увидит рабочий дайджест (например, просто преобразовав его существующий массив байтов наговорить) они вполне могут решить заявить о победе :) - person Jon Skeet; 13.01.2011

Они печатают одно и то же.. преобразуйте ваш byte[] в шестнадцатеричную строку, тогда вы также увидите CDF30C6B345276278BEDC7BCEDD9D5582F5B8E0C1DD858F46EF4EA231F92731D в качестве вывода Java:

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();
}
person mglauche    schedule 13.01.2011

Вам необходимо преобразовать дайджест в строку HEX перед его печатью. Пример кода можно найти здесь.

person orlp    schedule 13.01.2011