Статьи
YouTube-канал

Вычисление MD5-хэша

13 февраля 2020

Тэги: Java 10 Spring алгоритмы

MD5 хэш (Message Digest 5) - это 128 битный алгоритм вычисления хэша от сообщения произвольной длины. Чаще всего хэш вычисляется от строки (для проверки паролей) и от файла (для контроля его целостности).

Следует сразу же заметить, что хранение паролей в виде md5-хэшей в настоящее время считается небезопасным, т.к. md5-хэш довольно сильно подвержен коллизиям. Коллизией называется ситуация, когда у двух исходных сообщений хэши равны. То есть для успешного прохождения проверки пароля, сохраняемого в виде md5-хэша, вам даже не обязательно знать именно этот пароль. Достаточно знать пароль, имеющий такой же хэш. Более того, хэши от простых паролей можно напрямую искать в Google.

Вычисление хэша от строки

Алгоритм хэширования MD5 является частью стандартной библиотеки Java, поэтому вычислить хэш от строки (например, от пароля) достаточно легко.

public String getMd5Hash(String source) {
    try {
        var md = MessageDigest.getInstance("MD5");
        md.update(source.getBytes());
        byte[] digest = md.digest();
        return bytesToHex(digest);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}

Тут мы используем стандартный класс MessageDigest, который по имени алгоритма возвращает его реализацию. Если алгоритм по имени не найден, то метод getInstance() кидает исключение NoSuchAlgorithmException. Поскольку мы передаём в него константу «MD5», то точно знаем, что такой ошибки не возникнет. Поэтому обрачиваем это проверяемое исключение в RuntimeException, которое является непроверяемым, чтобы не «портить» сигнатуру метода.

Затем преобразуем исходную строку, от которой требуется посчитать хэш, в массив байт. Затем передаём этот массив в метод update(). В результате он возвращает хэш также в виде массива байт. Для удобства отображения массива байт в виде строки, напишем вспомогательный метод bytesToHex().

private String bytesToHex(byte[] bytes) {
    var builder = new StringBuilder();
    for (var b : bytes) {
        builder.append(String.format("%02x", b & 0xff));
    }
    return builder.toString();
}

Тут мы каждый байт преобразуем в строку, выполняя побитовое объединение этого байта с байтом 0xff. Во избежания создания лишних экземпляров строк, конкатенацию результата делаем с помощью StringBuilder, который в конце преобразуем в строку.

Байты в виде строки представляются в шестнадцатеричной (hexadecimal) системе счисления, поэтому содержат цифры от 0 до 9 и буквы от a до f.

Теперь вычислим хэш:

public static void main(String[] args) {
    var example = new PasswordExample();
    var hash = example.getMd5Hash("P@$$w0rd");
    System.out.println(hash); // c53e479b03b3220d3d56da88c4cace20
}

Если вы используете Spring, то всё то же самое можно сделать в одну строчку с помощью метода DigestUtils.md5DigestAsHex().

Вычисление хэша от файла

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

public String getMd5HashForFile(String filename) throws IOException {
    try {
        var md = MessageDigest.getInstance("MD5");
        var buffer = new byte[8192];
        try (var is = Files.newInputStream(Paths.get(filename))) {
            int read;
            while ((read = is.read(buffer)) > 0) {
                md.update(buffer, 0, read);
            }
        }
        byte[] digest = md.digest();
        return bytesToHex(digest);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}

Для чтения файла создаём InputStream в конструкции try-with-resources, которая автоматически закроет этот поток по завершению работы с ним. Сам поток получаем с помощью метода Files.newInputStream(). Затем в цикле считываем данные в созданный нами буфер - массив байт фиксированного размера. На каждой итерации вызываем метод update() для вычисления нового хэша на основе данных из буфера и прошлого значения хэша. Затем аналогично предыдущему примеру получаем значение хэша в виде массива байт и выводим его в виде строки.

Теперь передав в метод полный путь до проверяемого файла вы можете быстро вычислить его хэш. Если у вас Linux, то для проверки значения хэша можете использовать утилиту md5sum.


Облако тэгов

Kotlin, Java, Java 16, Java 11, Java 10, Java 9, Java 8, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, Hibernate, Collections, Stream API, многопоточность, ввод-вывод, Apache, maven, gradle, JUnit, YouTube, новости, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml

Последние статьи


Комментарии

Добавить комментарий

×

devmark.ru