Строка Java для SHA1 - PullRequest
       30

Строка Java для SHA1

138 голосов
/ 04 февраля 2011

Я пытаюсь сделать простой преобразователь String в SHA1 в Java, и вот что у меня получилось ...

public static String toSHA1(byte[] convertme) {
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    } 
    return new String(md.digest(convertme));
}

Когда я передаю его toSHA1("password".getBytes()), я получаю [�a�ɹ??�%l�3~��.Я знаю, что это, вероятно, простое исправление кодировки, такое как UTF-8, но кто-то может сказать мне, что я должен сделать, чтобы получить то, что я хочу - 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8?Или я делаю это совершенно неправильно?

Ответы [ 12 ]

169 голосов
/ 04 февраля 2011

ОБНОВЛЕНИЕ
Вы можете использовать Кодек Apache Commons (версия 1.7+), чтобы выполнить эту работу за вас.

<a href="https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html#sha1Hex(java.lang.String)" rel="noreferrer">DigestUtils.sha1Hex(stringToConvertToSHexRepresentation)</a>

Спасибо @ Джон Онстотт за это предложение.


Старый ответ
Преобразование массива байтов в шестнадцатеричную строку. Real's How To говорит вам, как .

return byteArrayToHexString(md.digest(convertme))

и (скопировано из Real's How To)

public static String byteArrayToHexString(byte[] b) {
  String result = "";
  for (int i=0; i < b.length; i++) {
    result +=
          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
  }
  return result;
}

Кстати, вы можете получить более компактное представлениеиспользуя Base64. Apache Commons Codec API 1.4 , имеет эту замечательную утилиту, чтобы убрать всю боль. см. Здесь

63 голосов
/ 31 января 2012

Это мое решение для преобразования строки в sha1.Это хорошо работает в моем приложении для Android:

private static String encryptPassword(String password)
{
    String sha1 = "";
    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes("UTF-8"));
        sha1 = byteToHex(crypt.digest());
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return sha1;
}

private static String byteToHex(final byte[] hash)
{
    Formatter formatter = new Formatter();
    for (byte b : hash)
    {
        formatter.format("%02x", b);
    }
    String result = formatter.toString();
    formatter.close();
    return result;
}
53 голосов
/ 04 ноября 2013

Использование Класс хеширования гуавы :

Hashing.sha1().hashString( "password", Charsets.UTF_8 ).toString()
30 голосов
/ 04 февраля 2011

SHA-1 (и все другие алгоритмы хеширования) возвращают двоичные данные. Это означает, что (в Java) они производят byte[]. Этот массив byte не представляет какие-либо конкретные символы, что означает, что вы не можете просто превратить его в String, как вы это сделали.

Если вам нужен String, то вам нужно отформатировать byte[] таким образом, чтобы его можно было представить в виде String (в противном случае просто оставьте byte[] рядом).

Двумя распространенными способами представления произвольных byte[] в качестве печатаемых символов являются BASE64 или простые шестнадцатеричные строки (т. Е. Каждая byte представляет две шестнадцатеричные цифры). Похоже, вы пытаетесь создать шестнадцатеричную строку.

Есть и еще один подводный камень: если вы хотите получить SHA-1 Java String, то вам нужно сначала преобразовать это String в byte[] (так как ввод SHA-1 - это byte[] тоже). Если вы просто используете myString.getBytes(), как вы показали, тогда он будет использовать кодировку платформы по умолчанию и, как таковой, будет зависеть от среды, в которой вы его запускаете (например, он может возвращать разные данные в зависимости от настроек языка / локали вашей ОС ).

Лучшее решение - указать кодировку, используемую для преобразования String -to- byte[], например: myString.getBytes("UTF-8"). Выбор UTF-8 (или другой кодировки, которая может представлять каждый символ Unicode) - самый безопасный выбор здесь.

26 голосов
/ 04 февраля 2011

Просто используйте библиотеку кодеков Apache Commons. У них есть служебный класс DigestUtils

Не нужно вдаваться в подробности.

23 голосов
/ 30 января 2014

Это простое решение, которое можно использовать при преобразовании строки в шестнадцатеричный формат:

private static String encryptPassword(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {

    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    crypt.reset();
    crypt.update(password.getBytes("UTF-8"));

    return new BigInteger(1, crypt.digest()).toString(16);
}
18 голосов
/ 13 мая 2014

Как упоминалось ранее, используйте кодек apache commons. Это также рекомендуется парнями из Spring (см. DigestUtils в Spring doc). E.g.:

DigestUtils.sha1Hex(b);

Определенно, здесь не будет ответа с самым высоким рейтингом.

4 голосов
/ 08 апреля 2017

Печать выполняется неправильно, поскольку вам необходимо использовать кодировку Base64.В Java 8 вы можете кодировать, используя Base64 класс кодировщика.

public static String toSHA1(byte[] convertme) {
    md = MessageDigest.getInstance("SHA-1");
    return Base64.getEncoder().encodeToString((md.digest(convertme));
}

Результат

Это даст ожидаемый результат 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

2 голосов
/ 23 ноября 2018

Дайджест сообщения (хеш) - это байт [] в байте [] out

Дайджест сообщения определяется как функция, которая принимает необработанный байтовый массив и возвращает необработанный байтовый массив (он же byte[]).Например, SHA-1 (алгоритм безопасного хеширования 1) имеет размер дайджеста 160 бит или 20 байт.Необработанные байтовые массивы обычно не могут интерпретироваться как кодировки символов , такие как UTF-8 , поскольку не каждый байт в каждом порядке является допустимой кодировкой.Таким образом, преобразование их в String с помощью:

new String(md.digest(subject), StandardCharsets.UTF_8)

может создать некоторые недопустимые последовательности или иметь указатели на неопределенные Unicode отображения:

[�a�ɹ??�%l�3~��.

Binary-текстовое кодирование

Для этого используется двоичное-текстовое кодирование.Для хэшей чаще всего используется кодировка HEX или Base16 .Как правило, байт может иметь значение от 0 до 255 (или от -128 до 127 со знаком), что эквивалентно HEX-представлению 0x00 - 0xFF.Таким образом, шестнадцатеричный код удвоит требуемую длину выходных данных, что означает, что 20-байтовый выход создаст шестнадцатеричную строку длиной 40 символов, например:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

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

Вы можете преобразовать байтовый массив в шестнадцатеричный с помощью только функций JDK:

new BigInteger(1, token).toString(16)

Обратите внимание, что BigInteger будет интерпретировать данный байтовый массив как число , а не как байтовую строку.Это означает, что начальные нули не будут выводиться, а результирующая строка может быть короче 40 символов.

Использование библиотек для кодирования в HEX

Теперь вы можете скопировать и вставить непроверенный байт-метод to-hex из Stack Overflow или использование массивных зависимостей, таких как Guava .

Чтобы получить решение для большинства проблем, связанных с байтами, я реализовал утилиту для обработки этих случаев: bytes-java (Github)

Чтобы преобразовать массив байтов дайджеста сообщения, вы можете просто сделать

String hex = Bytes.wrap(md.digest(subject)).encodeHex();

или использовать встроенную функцию хеширования

String hex =  Bytes.from(subject).hashSha1().encodeHex();
2 голосов
/ 18 января 2018

Base 64 Представление SHA1 Hash:

String hashedVal = Base64.getEncoder().encodeToString(DigestUtils.sha1(stringValue.getBytes(Charset.forName("UTF-8"))));
...