Java вычисляет шестнадцатеричное представление SHA-1 дайджеста строки - PullRequest
57 голосов
/ 09 декабря 2010

Я храню пароль пользователя на БД в виде хэша sha1.

К сожалению, я получаю странные ответы.

Я храню строку как это:

MessageDigest cript = MessageDigest.getInstance("SHA-1");
              cript.reset();
              cript.update(userPass.getBytes("utf8"));
              this.password = new String(cript.digest());

Я хотел что-то вроде этого ->

aff -> "0c05aa56405c447e6678b7f3127febde5c3a9238"

, а не

aff -> @V @ \ D ~ fx : 8

Ответы [ 15 ]

102 голосов
/ 15 июля 2011

Использование библиотеки общих кодеков apache:

DigestUtils.sha1Hex("aff")

Результат 0c05aa56405c447e6678b7f3127febde5c3a9238

Вот и все:)

40 голосов
/ 09 декабря 2010

Это происходит потому, что cript.digest () возвращает байтовый массив, который вы пытаетесь распечатать как символьную строку. Вы хотите преобразовать его в печатную шестнадцатеричную строку.

Простое решение: используйте библиотеку Apache commons-codec :

String password = new String(Hex.encodeHex(cript.digest()),
                             CharSet.forName("UTF-8"));
24 голосов
/ 09 декабря 2010

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

Кроме того, вы не продаете пароль. Это создает уязвимость для предварительно вычисленных словарей, таких как «радужные таблицы».

Вместо того, чтобы пытаться свернуть свой собственный код (или использовать какую-то отрывочную стороннюю программу-раздуватель) для правильной работы, вы можете использовать код, встроенный в среду выполнения Java. Подробнее см. этот ответ .

После правильного хеширования пароля у вас будет byte[]. Простой способ преобразовать это в шестнадцатеричное String с помощью класса BigInteger:

String passwordHash = new BigInteger(1, cript.digest()).toString(16);

Если вы хотите убедиться, что ваша строка всегда содержит 40 символов, вам может потребоваться выполнить некоторые отступы с нулями слева (вы можете сделать это с помощью String.format().)

10 голосов
/ 10 сентября 2014

Если вы не хотите добавлять какие-либо дополнительные зависимости в ваш проект, вы также можете использовать

MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(message.getBytes("utf8"));
byte[] digestBytes = digest.digest();
String digestStr = javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes);
5 голосов
/ 09 декабря 2010

Метод crypt.digest () возвращает байт []. Этот байтовый массив является правильной суммой SHA-1, но крипто-хэши обычно отображаются для людей в шестнадцатеричной форме. Каждый байт в вашем хэше будет содержать две шестнадцатеричные цифры.

Чтобы безопасно преобразовать байт в шестнадцатеричный код, используйте это:

// %1$ == arg 1
// 02  == pad with 0's
// x   == convert to hex
String hex = String.format("%1$02x", byteValue);

Этот фрагмент кода может использоваться для преобразования символа в гекс :

/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import java.io.*;

public class UnicodeFormatter  {

   static public String byteToHex(byte b) {
      // Returns hex String representation of byte b
      char hexDigit[] = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
      };
      char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
      return new String(array);
   }

   static public String charToHex(char c) {
      // Returns hex String representation of char c
      byte hi = (byte) (c >>> 8);
      byte lo = (byte) (c & 0xff);
      return byteToHex(hi) + byteToHex(lo);
   }
}

Обратите внимание, что работа с байтами в Java очень подвержена ошибкам. Я бы все перепроверил и проверил несколько странных случаев.

Также вам следует подумать об использовании чего-то более сильного, чем SHA-1. http://csrc.nist.gov/groups/ST/hash/statement.html

2 голосов
/ 10 июня 2016

Вы можете использовать Google Guava :

Maven:

<dependency>
   <artifactId>guava</artifactId>
   <groupId>com.google.guava</groupId>
   <version>14.0.1</version>
</dependency>

Образец:

HashCode hashCode = Hashing.sha1().newHasher()
   .putString(password, Charsets.UTF_8)
   .hash();            

String hash = BaseEncoding.base16().lowerCase().encode(hashCode.asBytes());
2 голосов
/ 02 апреля 2014

Существует не просто простые стандартные алгоритмы хеширования, используемые для хранения необратимых паролей.

  1. Выполнение нескольких раундов, чтобы замедлить атаки методом перебора
  2. Использование "соли" для каждой записив качестве входных данных для алгоритма хеширования, кроме пароля, чтобы сделать атаки по словарю менее осуществимыми и избежать выходных коллизий.
  3. Используйте «перец», параметр конфигурации приложения в качестве входных данных для алгоритма хеширования, чтобы сделать украденный дамп базы данныхс неизвестным «перцем», бесполезным.
  4. Дополните ввод, чтобы избежать слабых мест в некоторых алгоритмах хеширования, например, где вы можете добавить символ к паролю, не зная пароля, изменив хеш.

Для получения дополнительной информации см., Например,

Вы также можете использовать метод http://en.wikipedia.org/wiki/Password-authenticated_key_agreement, чтобы вообще не передавать пароль в виде открытого текста на сервер.

2 голосов
/ 04 сентября 2012

Если вы используете Spring, все довольно просто:

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("SHA-1");
String hash = encoder.encodePassword(password, "salt goes here");
1 голос
/ 03 июня 2019

echo -n "aff" |sha1sum выдает правильный вывод (по умолчанию echo вставляет новую строку)

1 голос
/ 24 января 2018
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
        messageDigest.reset();
        messageDigest.update(password.getBytes("UTF-8"));
        String sha1String = new BigInteger(1, messageDigest.digest()).toString(16);
...