Как я могу создать строку дайджеста SHA512 в Java, используя надувной замок?

Этот модульный тест не работает:

    public void testDigest() throws NoSuchAlgorithmException {
    String hashExpected = "150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197";
    MessageDigest md = new MessageDigest();
    String hashActual = new String(md.digest("hi"));
    Assert.assertEquals(hashExpected, hashActual);
}

Ниже моя реализация моего класса MessageDigest:


import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.io.DigestInputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class MessageDigest { private Digest messageDigest;

public MessageDigest() throws NoSuchAlgorithmException {
    Security.addProvider(new BouncyCastleProvider());
    messageDigest = new SHA512Digest();
}

public byte[] digest(String message) {
    byte[] retValue = new byte[messageDigest.getDigestSize()];
    messageDigest.update(message.getBytes(), 0, message.length());
    messageDigest.doFinal(retValue, 0);
    return retValue;
}

}

Тест не проходит по следующей причине:


junit.framework.ComparisonFailure: expected:<150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197> but was:<
í[êlÇ1φÄf¬Bz�´Žñ¹ýbfd³¿»™¤É"ó=Þ8q›ŒƒTâ·«�wàæÁ(C’
q.sÕXá

У меня такое чувство, что я использую неправильную схему кодирования, когда конвертирую дайджест byte[] в строку. Любая помощь будет оценена по достоинству.


person Lee Warner    schedule 05.02.2010    source источник


Ответы (4)


Ожидаемое значение представляет собой шестнадцатеричное значение. Вы создаете строку на основе необработанных байтов, что не сработает.

По возможности следует использовать стандартный Java Crypto API вместо специальных API BouncyCastle.

Попробуйте следующее (библиотека Hex взята из commons-codec):

Security.addProvider(new BouncyCastleProvider());

String data = "hello world";

MessageDigest mda = MessageDigest.getInstance("SHA-512", "BC");
byte [] digesta = mda.digest(data.getBytes());

MessageDigest mdb = MessageDigest.getInstance("SHA-512", "BC");
byte [] digestb = mdb.digest(data.getBytes());

System.out.println(MessageDigest.isEqual(digesta, digestb));

System.out.println(Hex.encodeHex(digesta));
person Kevin    schedule 05.02.2010
comment
+1 Мне нравится твой более полный ответ. Вопрос: когда/почему можно использовать MessageDigest.isEqual вместо Arrays.equals? - person Chris Jester-Young; 05.02.2010
comment
Они функционально эквивалентны. MessageDigest#isEqual() обеспечивает немного больше семантического значения, но это спорно. - person Kevin; 05.02.2010
comment
Они не совсем эквивалентны. Методы Arrays.equals считают две пустые ссылки равными, тогда как метод MessageDigest.isEqual вызовет исключение NullPointerException. - person jarnbjo; 05.02.2010
comment
Кодек Commons не требуется для шестнадцатеричного преобразования. Попробуйте System.out.println(new BigInteger(1,m.digest(new byte[]{0x00})).toString(16)); - person Janus Troelsen; 14.11.2012
comment
Что касается MessageDigest#isEqual(): он является постоянным во времени, т. е. для вычисления требуется одно и то же время, и он не возвращает false, как только видит разницу. Таким образом, вы не можете рассчитать время вызова функции, чтобы проверить, есть ли у вас хеш, который имеет какой-то общий префикс с требуемым хешем. - person JesperSM; 27.11.2013
comment
Спасибо. Это лучшее объяснение постоянной времени, которое я когда-либо видел. Я не совсем понял это в первый раз, когда я прочитал это (хотя я прочитал это очень кратко). - person Kevin M; 31.01.2017

Просто дополнение к ответу Кевина: начиная с Java 5, вы можете использовать String.format("%0128x", new BigInteger(1, digesta)) вместо commons-codec для форматирования массива байтов как 128-значного шестнадцатеричного числа с ведущими нулями.

person jarnbjo    schedule 05.02.2010
comment
Спасибо за это, но один вопрос. Помимо отсутствия необходимости извлекать другую библиотеку, есть ли какая-либо польза от использования этого метода по сравнению с тем, который указан в ответе commons-codec? - person jtbradle; 27.06.2014
comment
@jtbradle: Наверное, нет. - person jarnbjo; 06.10.2014

Да, вам нужно превратить массив байтов в шестнадцатеричную строку. :-) Изучите кодек Apache Commons, особенно Hex.

person Chris Jester-Young    schedule 05.02.2010

Начиная с BouncyCastle 1.49, в классе Hex есть несколько методов toHexString. Например:

Hex.toHexString(digest);

вернет вам хеш-дайджест в виде Java String в шестнадцатеричном формате.

Для справки см. Javadoc BouncyCastle или grepcode.

person Diego    schedule 06.02.2014