0

Как хешировать строку в Android?

25

Я разрабатываю приложение для Android и у меня есть несколько строк, которые я хотел бы зашифровать перед отправкой в базу данных. Мне нужно что-то безопасное, простое в реализации, что будет генерировать один и тот же результат каждый раз, когда передаются одни и те же данные. Желательно, чтобы результат был строкой фиксированной длины, независимо от объема передаваемой информации. Возможно, я ищу функцию хеширования.

5 ответ(ов)

0

Этот фрагмент кода рассчитывает MD5 хеш для заданной строки:

public String md5(String s) {
    try {
        // Создаем MD5 хеш
        MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        // Создаем шестнадцатеричную строку
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < messageDigest.length; i++)
            hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Этот метод md5 принимает строку s, генерирует для неё MD5 хеш и возвращает его в виде шестнадцатеричной строки. Если возникает ошибка при получении экземпляра алгоритма, она будет выведена в консоль.

Надеюсь, это будет полезно для вас!

0

Проблема в вашем методе md5 заключается в неверной конвертации байтов в шестнадцатеричную строку и в использовании недвойного формата вывода. Давайте разберем ваш код и сравним его с работающим примером.

В вашем неверном методе:

public static String md5(String s) {
    try {
        MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < messageDigest.length; i++)
            hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Вы используете Integer.toHexString, что может привести к тому, что одинокие байты (значения от 0 до 15) будут представлены в виде одной шестнадцатеричной цифры (например, 0x0, 0x1 и т.д.), а не в виде двух цифр, как требуется для корректного представления MD5, поэтому результирующая строка получается короче и неверной.

В рабочем методе:

public static final String md5(final String toEncrypt) {
    try {
        final MessageDigest digest = MessageDigest.getInstance("md5");
        digest.update(toEncrypt.getBytes());
        final byte[] bytes = digest.digest();
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(String.format("%02X", bytes[i]));
        }
        return sb.toString().toLowerCase();
    } catch (Exception exc) {
        return ""; // Impossibru!
    }
}

Используется String.format("%02X", bytes[i]), что гарантирует, что каждый байт будет представлен как две цифры в шестнадцатеричном формате (например, 0x0 будет представлено как 00). Дополнительно, toLowerCase() делает все буквы строчными, что также является стандартом для представления строки MD5.

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

StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
    hexString.append(String.format("%02x", b));
}

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

public static String md5(String s) {
    try {
        MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Теперь ваш метод должен генерировать корректную строку MD5 длиной 32 символа.

0

Ваш код предназначен для хеширования строки с использованием алгоритма MD5 и преобразования результата в шестнадцатеричную строку. Давайте разберем его шаги:

  1. Hex-таблица: Создается массив символов hextable, который содержит шестнадцатеричные цифры от '0' до '9' и от 'a' до 'f'. Этот массив используется для преобразования байтов в их шестнадцатеричное представление.

  2. Метод byteArrayToHex: Этот метод принимает массив байтов и превращает его в шестнадцатеричную строку. Он проходит по каждому байту, делает его беззнаковым (используя побитовые операции) и получает соответствующие шестнадцатеричные символы из hextable.

    int di = (array[i] + 256) & 0xFF; // Приводим байт к беззнаковому виду
    s = s + hextable[(di >> 4) & 0xF] + hextable[di & 0xF];
    
  3. Метод digest: Этот метод принимает строку и алгоритм хеширования в виде строки. Он создает экземпляр MessageDigest для указанного алгоритма (например, MD5). Если алгоритм не поддерживается, он выводит стек ошибки и возвращает исходную строку. После этого строка передается в месседж дайджест, который хешируется.

    m.update(s.getBytes(), 0, s.length());
    
  4. Метод md5: Этот метод является удобным оберткой для вызова метода digest с конкретным алгоритмом MD5. Он просто передает строку s в метод digest и возвращает результат.

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

String hashed = md5("your_string_here");

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

0

Если вы используете решение от @Donut и работаете с символами, закодированными в UTF-8 (например, é), вам нужно использовать метод getBytes("UTF-8"). Вот моя доработка метода digest:

private static char[] hextable = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

public static String byteArrayToHex(byte[] array) {
    String s = "";
    for (int i = 0; i < array.length; ++i) {
        int di = (array[i] + 256) & 0xFF; // Делаем байт беззнаковым
        s += hextable[(di >> 4) & 0xF] + hextable[di & 0xF];
    }
    return s;
}

public static String digest(String s, String algorithm) {
    MessageDigest m = null;
    try {
        m = MessageDigest.getInstance(algorithm);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return s;
    }

    try {
        m.update(s.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        m.update(s.getBytes());
    }
    return byteArrayToHex(m.digest());
}

public static String md5(String s) {
    return digest(s, "MD5");
}

Таким образом, при использовании этой реализации метод digest будет корректно обрабатывать строки, содержащие UTF-8 символы. Не забывайте всегда обрабатывать возможные исключения, что и сделано в данном коде.

0

Ответ выше почти на 100% правильный, однако он может не обработать строки в кодировке Unicode корректно.

MessageDigest digest;
try {
    digest = MessageDigest.getInstance("MD5");
    byte utf8_bytes[] = tag_xml.getBytes("UTF-8"); // Указываем явно кодировку UTF-8
    digest.update(utf8_bytes, 0, utf8_bytes.length);
    hash = new BigInteger(1, digest.digest()).toString(16);
} 
catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} 
catch (UnsupportedEncodingException e) {
    e.printStackTrace(); // Обработка исключения для кодировки
}

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

Также настоящий вопрос касается длины байтового массива, а не строки. Как правило, для работы с длиной используется свойство length массива байтов, как указано в коде выше.

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