Какой SHA-256 правильный? Java SHA-256 дайджест или инструмент командной строки Linux
Когда я вычисляю в Java SHA-256 строки со следующим методом
public static void main(String[] args) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password".getBytes());
StringBuffer sb = new StringBuffer();
for(byte b : hash) {
sb.append(Integer.toHexString(b & 0xff));
}
System.out.println(sb.toString());
}
Я получаю:
5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8
в командной строке я делаю следующее (мне нужно -n
не добавлять новую строку):
echo -n "password" | sha256sum
и получим
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
если сравнить их более близко, я нахожу 2 тонких различия
5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
или:
5e884898da28 47151d0e56f8dc6292773603d d6aabbdd62a11ef721d1542d8
5e884898da28 0 47151d0e56f8dc6292773603d 0 d6aabbdd62a11ef721d1542d8
Какое из двух здесь верно?
Результат: Оба являются, но я ошибался...
зафиксировал его, используя:
StringBuffer sb = new StringBuffer();
for(byte b : hash) {
sb.append(String.format("%02x", b));
}
Спасибо!
Ответы
Ответ 1
Я возьму разумное предположение: оба выводят один и тот же дайджест, но в вашем Java-коде, который выводит результат byte[]
в виде шестнадцатеричной строки, вы выводите маленькие байтовые значения (менее 16) без ведущего 0. Таким образом, байт со значением "0x0d" записывается как "d", а не "0d".
Ответ 2
Преступником является toHexString
. Кажется, он выводит 6
для значения 6, тогда как sha256sum
выводит 06
. Документы Java для Integer.toHexString()
state:
Это значение преобразуется в строку из цифр ASCII в шестнадцатеричной форме (базовая 16) без дополнительных начальных 0.
Другие нули в строке не затрагиваются, так как они являются второй половиной байтов (например, 30
).
Один из способов исправить это - изменить:
for(byte b : hash) {
sb.append(Integer.toHexString(b & 0xff));
}
в
for(byte b : hash) {
if (b < 16) sb.append("0");
sb.append(Integer.toHexString(b & 0xff));
}
Ответ 3
Они оба правы - это ваш код Java, который виноват, потому что он не печатает ведущее 0 для шестнадцатеричного значения меньше 0x10.
Ответ 4
Вам все равно нужно "echo -n", чтобы предотвратить завершение\n
Ответ 5
Тот, который генерируется sha256sum, кажется правильным. Кажется, что ваша реализация снижает эти два нуля.
Ответ 6
Использование идеи @paxdiablo имело проблему с большим числом, поскольку оно показалось отрицательным, поэтому
Вместо:
for(byte b : hash) {
sb.append(Integer.toHexString(b & 0xff));
}
вы можете сделать:
for(byte b : hash) {
if (b > 0 && b < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(b & 0xff));
}
И прочитайте @Sean Owen ответ.
Ответ 7
Вы также можете получить правильный результат, используя следующее:
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password".getBytes());
BigInteger bI = new BigInteger(1, hash);
System.out.println(bI.toString(16));