Фрагмент кода 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
.
Счастливого программирования.
EDIT:
Для выполнения вашей задачи я бы сделал что-то вроде этого:
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();
}