Фрагмент кода 1 правильный, но вам нужно добавить к нему оператор печати, чтобы получить ожидаемый результат. Однако для этого вам нужно использовать настоящий шестнадцатеричный кодировщик/декодер, который, к сожалению, не поставляется по умолчанию в java.util
.
Вот переработанный пример без конкатенации, который я намеренно опустил, чтобы вам было чем заняться.
В коде используется относительно медленная, но легко запоминающаяся и читаемая функция toHex
. Сначала BigInteger
нужно построить BigInteger
, что расточительно и, возможно, еще медленнее. Хотя код, кажется, работает правильно для 32-байтовых хеш-значений, я все же считаю, что код сложно поддерживать.
public static byte[] printHexadecimalHashIterations(byte[] input, int iterations)
{
var digest = input.clone();
MessageDigest md;
try
{
md = MessageDigest.getInstance("SHA-256");
}
catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException("SHA-256 hash should be available", e);
}
for (int i = 0; i < iterations; i++)
{
md.update(digest);
digest = md.digest();
printDigest("Intermediate hash", digest);
}
printDigest("Final hash", digest);
return digest;
}
public static void printDigest(String hashType, byte[] digest)
{
var digestInHex = toHex(digest);
System.out.printf("%s: %s%n", hashType, digestInHex);
}
public static String toHex(byte[] data)
{
var sb = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++)
{
sb.append(String.format("%02X", data[i]));
}
return sb.toString();
}
public static void main(String[] args)
{
printHexadecimalHashIterations("password".getBytes(StandardCharsets.UTF_8), 2);
}
Главное, что нужно вынести из этого, это то, что данные для (защиты) хеш-функций состоят из байтов (или октетов, если вы предпочитаете это имя). Шестнадцатеричная строка — это просто текстовое представление этих байтов. Он не идентичен самим данным.
Вы должны уметь отличать двоичные данные от шестнадцатеричных, которые являются просто представлением двоичных данных. Никогда не называйте двоичные данные «шестнадцатеричными», как в вопросе: это красный флаг, что вы не понимаете разницы.
Однако в вашем случае вам нужны только шестнадцатеричные числа, чтобы распечатать их на экране; вам вообще не нужно преобразовывать digest
байтовый массив в шестнадцатеричный; он остается доступным. Так что можете просто продолжать.
Если вам нужно преобразовать это текстовое представление обратно в байты, вам потребуется выполнить шестнадцатеричное декодирование. Очевидно, вам снова понадобится хороший метод, который не использует для этого BigInteger
. Существует множество библиотек (Guava, Apache Commons, Bouncy Castle), которые предоставляют хорошие шестнадцатеричные кодировщики/декодеры и хорошие вопросы/ответы на этот на SO а>. Оператор hash.getBytes(StandardCharsets.UTF_8)
во фрагменте кода 2 выполняет не шестнадцатеричное декодирование, а кодирование символов.
И последний совет: методы update
позволяют передавать данные в функцию дайджеста. Это означает, что вам никогда не придется ничего конкатенировать для вычисления дайджеста по конкатенации: вместо этого вы можете просто выполнить несколько вызовов update
.
Удачного программирования.
РЕДАКТИРОВАТЬ:
Чтобы выполнить вашу задачу, я бы сделал что-то вроде этого:
final byte[] passwordBytes = "password".getBytes(StandardCharsets.UTF_8);
final byte[] rBytes = "f@ghj!$g".getBytes(StandardCharsets.UTF_8);
digest.update(passwordBytes);
digest.update(rBytes);
byte[] currentHash = digest.digest();
for (int i = 1; i < iterations; i++)
{
digest.update(currentHash);
digest.update(rBytes);
currentHash = digest.digest();
}
person
Maarten Bodewes
schedule
30.03.2019