Java вычисляет шестнадцатеричное представление SHA-1 дайджеста строки

Я храню пароль пользователя на db как хэш файл 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

Ответ 1

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

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

String password = new String(Hex.encodeHex(cript.digest()),
                             CharSet.forName("UTF-8"));

Ответ 2

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

DigestUtils.sha1Hex("aff")

Результат: 0c05aa56405c447e6678b7f3127febde5c3a9238

Что это:)

Ответ 3

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

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

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

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

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

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

Ответ 4

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

MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(message.getBytes("utf8"));
byte[] digestBytes = digest.digest();
String digestStr = javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes);

Ответ 5

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

Чтобы безопасно преобразовать байты в hex, используйте это:

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

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

/*
 * 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

Ответ 6

С 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());

Ответ 7

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

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("SHA-1");
String hash = encoder.encodePassword(password, "salt goes here");

Ответ 8

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

  • Сделайте несколько раундов, чтобы атаки грубой силы замедлялись.
  • Используйте "соль" для каждой записи для ввода хеш-алгоритма, кроме пароля, чтобы сделать попытки словаря менее осуществимыми и избежать столкновений с выводами.
  • Используйте "перец", настройку конфигурации приложения как входной сигнал в хэш-алгоритм, чтобы сделать украденный сбой базы данных с неизвестным "перцем" бесполезным.
  • Вставьте вкладку, чтобы избежать слабых мест в некоторых хэш-алгоритмах, например. где вы можете добавить символ к паролю, не зная пароля, изменив хэш.

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

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

Ответ 9

Чтобы использовать UTF-8, сделайте следующее:

userPass.getBytes("UTF-8");

И чтобы получить строку Base64 из дайджеста, вы можете сделать что-то вроде этого:

this.password = new BASE64Encoder().encode(cript.digest());

Забастовкa >

Так как MessageDigest.digest() возвращает массив байтов, вы можете преобразовать его в String, используя Apache Hex Encoding (проще).

например.

this.password = Hex.encodeHexString(cript.digest());

Ответ 10

digest() возвращает массив байтов, который вы конвертируете в строку с использованием кодировки по умолчанию. Что вы хотите сделать, это base64 encode it.

Ответ 11

Как насчет преобразования байта [] в строку base64?

    byte[] chkSumBytArr = digest.digest();
    BASE64Encoder encoder = new BASE64Encoder();
    String base64CheckSum = encoder.encode(chkSumBytArr);

Ответ 12

вы также можете использовать этот код (от crackstation.net):

private static String toHex(byte[] array) { BigInteger bi = new BigInteger(1, array); String hex = bi.toString(16); int paddingLength = (array.length * 2) - hex.length(); if(paddingLength > 0) return String.format("%0" + paddingLength + "d", 0) + hex; else return hex; }

Ответ 13

        MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
        messageDigest.reset();
        messageDigest.update(password.getBytes("UTF-8"));
        String sha1String = new BigInteger(1, messageDigest.digest()).toString(16);

Ответ 14

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

Ответ 15

Сначала вам нужно сначала закодировать результат. MessageDigest возвращает "сырой" хеш, а не читаемый человеком.

Edit:

@thejh предоставил ссылку на код, который должен работать. Лично я бы предложил использовать Bouncycastle или Apache Commons Codec выполнить эту работу. Bouncycastle был бы хорош, если вы хотите выполнять любые другие операции, связанные с криптографией.