Хеширование текста, MessageDigest

Хэширование - это процесс преобразования массива входных данных произвольной длины в битовую строку фиксированной длины соласно заданному алгоритму. Функция, реализующая алгоритм и выполняющая преобразование, называется «хэш-функцией». Исходные данные являются входным массивом или «сообщением». Результат преобразования называется «хэшом» или «хэш-кодом».

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

Существует множество алгоритмов хэширования, отличающихся различными свойствами :

  • разрядностью;
  • вычислительной сложностью;
  • криптостойкостью.

«Хорошая» хэш-функция должна удовлетворять двум свойствам : быстрое вычисление и минимальное количество «коллизий» (идеально - отсутствие коллизий). Выбор алгоритма получения «хэш-кода» определяется спецификой решаемой задачи. Простейшим примером хэш-функции может служить циклический избыточный код CRC (cyclic redundancy code).

Значение хэш-суммы необходимо для проверки целостности данных и их идентификации. Как правило, хэш-суммами заменяют данные, которые не хранят в явном виде (например, пароли, ответы на вопросы тестов и т.д.). Также алгоритмы хэширования используются для проверки целостности и подлинности файлов.

В качестве «хэш-кода» можно использовать дайджест сообщения, получаемый с помощью MessageDigest.

Дайджест сообщения MessageDigest

В Java-криптографии для получения хэш-суммы текста используют дайджест сообщения MessageDigest. В конструкторе класса MessageDigest необходимо указать один из алгоритмов MD5 (Message Digest), SHA-1 (Secure Hash Algorithm) или SHA-256 :

MessageDigest(String algorithm) 

Листинг функции получения MessageDigest

В функции getMessageDigest.java первоначально выполняется проверка нулевых значений алгоритма algo и сообщения text, после чего формируется MessageDigest. Методу update для формирования дайджеста необходимо передать в качестве параметра массив байт. Результатом выполнения функции является массив байт дайджеста сообщения, получаемый методом digest() класса MessageDigest.

byte[] getMessageDigest (final String algo, final String text)
{
    if ((algo == null) || (algo.trim().length() == 0) || (text == null))
        return null;
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance(algo);
        md.update(text.getBytes());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    if (md != null)
        return md.digest();
    else
        return null;
}

Пример использования MessageDigest

Рассмотрим пример MessageDigestExample.java, в котором для получения дайджеста сообщения MessageDigest будем использовать различные алгоритмы, определенные строкой ALGO. Текст сообщения, для которого определяется дайджест, читается из файла report.txt. После считывания файла в массив байт dataBytes для 3-х алгоритмов определяются дайджесты сообщений. Следует отметить, что размеры дайджестов для разных алгоритмов разные. Представление дайджеста сообщения выводится в консоль.

public class MDExample
{
    private  final  String[]         ALGO = {"MD5", "SHA-1", "SHA-256"};
    private  final  MessageDigest[]  MD   = {null, null, null};
    public void MessageDidgestTest()
    {
        try {
            // Инициализация объектов MessageDigest 
            for (int i = 0; i < ALGO.length; i++)
                MD[i] = MessageDigest.getInstance(ALGO[i]);
           // Чтение файла
            FileInputStream fis = new FileInputStream("report.txt");
            // Массив данных
            byte[] dataBytes = new byte[fis.available()];

            int nread = 0;
            while ((nread = fis.read(dataBytes)) != -1) {
                MD[0].update(dataBytes, 0, nread);
                MD[1].update(dataBytes, 0, nread);
                MD[2].update(dataBytes, 0, nread);
            }
            fis.close();

            for (int i = 0; i < MD.length; i++) {
                byte[] mdbytes = MD[i].digest();
                StringBuffer sb = new StringBuffer();
                // convert the byte to hex format
                for (int j = 0; j < mdbytes.length; j++) {
                    String s = Integer.toHexString(0xff & mdbytes[j]);
                    s = (s.length() == 1) ? "0" + s : s;
                    sb.append(s);
                }
                System.out.println(String.format("  %s", sb.toString()));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        MDExample app = new MDExample();
		
        byte[] mdbytes = app.getMessageDigest("SHA-256", "length");
        StringBuffer sb = new StringBuffer();
        // convert the byte to hex format
        for (int j = 0; j < mdbytes.length; j++) {
            String s = Integer.toHexString(0xff & mdbytes[j]);
            s = (s.length() == 1) ? "0" + s : s;
            sb.append(s);
        }
        System.out.println(String.format("%s", sb.toString()));
        System.out.println("\n");
		
        app.MessageDidgestTest();

        System.exit(0);
    }
}

Результат выполнения программы в консоле будет иметь следующий вид :


0f82aca66af91493b1ff401de5f1f7e3e24e14560df3f6f7e465dbc915b9947d

MessageDigest MD5(32)
  2d42dab6607e2ffbf7f956a8fdd58259
MessageDigest SHA-1(40)
  9dcd9200616ac6f39c9b761f68cec7bf0bb7c154
MessageDigest SHA-256(64)
  79a2a06e22197eff4117c078aacfed2df7743559b40a86659fc712bb1457c5fe
 

Скачать пример

Исходный код рассмотренного примера в виде проекта Eclipse можно скачать здесь (5.26 Kб).

  Рейтинг@Mail.ru