Может ли кто-нибудь проверить правильность получения хеша md5 с помощью этого метода? - PullRequest
1 голос
/ 12 апреля 2011
        MessageDigest m=MessageDigest.getInstance("MD5");
        StringBuffer sb = new StringBuffer();
        if(nodeName!=null) sb.append(nodeName);
        if(nodeParentName!=null) sb.append(nodeParentName);
        if(nodeParentFieldName!=null) sb.append(nodeParentFieldName);
        if(nodeRelationName!=null) sb.append(nodeRelationName);
        if(nodeViewName!=null) sb.append(nodeViewName);
        if(treeName!=null) sb.append(treeName);
        if(nodeValue!=null && nodeValue.trim().length()>0) sb.append(nodeValue);
        if(considerParentHash) sb.append(parentHash);
        m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());
        BigInteger i = new BigInteger(1,m.digest());
        hash = String.format("%1$032X", i);

Идея этих строк кода заключается в том, что мы добавляем все значения класса / модели в StringBuilder, а затем возвращаем заполненный хеш этого (реализация Java возвращает хеш md5 длиной 30 или 31,поэтому последняя строка форматирует хеш, добавляемый в 0).

Я могу убедиться, что это работает, но у меня есть ощущение, что в какой-то момент происходит сбой (наше приложение дает сбой, и я считаю, что это вероятная причина).

Может кто-нибудь увидеть причину, почему это не сработает?Существуют ли обходные пути, позволяющие сделать этот код менее подверженным ошибкам (например, устранение необходимости в строках с UTF-8).

Ответы [ 2 ]

1 голос
/ 12 апреля 2011

В вашем коде есть несколько странных вещей.

Кодировка UTF-8 символа может использовать более одного байта. Поэтому вам не следует использовать длину string в качестве конечного параметра для вызова update(), но длину массива байтов, который getBytes() фактически вернул. Как предложил Paŭlo, используйте метод update(), который принимает в качестве параметра один byte[].

Вывод MD5 представляет собой последовательность из 16 байтов с совершенно произвольными значениями. Если вы интерпретируете его как целое число (это то, что вы делаете со своим вызовом BigInteger()), тогда вы получите числовое значение, которое будет меньше 2 160 , возможно, намного меньше. При преобразовании обратно в шестнадцатеричные цифры вы можете получить 32, 31, 30 ... или менее 30 символов. Вы используете строку слева в формате "%032X" с достаточным количеством нулей, так что ваш код работает, но он является косвенным (вывод MD5 никогда не был целым числом с самого начала).

Вы собираете элементы ввода хэша с необработанной конкатенацией. Это может вызвать проблемы. Например, если modeName равен "foo", а modeParentName равен "barqux", то ввод MD5 начнется с (кодировка UTF-8) "foobarqux". Если modeName равен "foobar", а modeParentName равен "qux", то вход MD5 будет также начинаться с "foobarqux". Вы не говорите, почему вы хотите использовать хеш-функцию, но обычно, когда кто-то использует хеш-функцию, она должна иметь уникальный след некоторого фрагмента данных; два разных элемента данных должны давать разные входные данные хеш-функции.

При обработке nodeValue вы вызываете trim(), что означает, что эта строка может начинаться и / или заканчиваться пробелом, и вы не хотите включать этот пробел в хэш-ввод - но вы делаете включите его, так как вы добавляете nodeValue, а не nodeValue.trim().

Если то, что вы пытаетесь сделать, имеет какое-либо отношение к безопасности, то вам не следует использовать MD5, который криптографически нарушен. Вместо этого используйте SHA-256.

Хэширование XML-элемента обычно выполняется посредством канонизации (которая обрабатывает пробелы, порядок атрибутов, представление текста и т. Д.). См. этот вопрос по теме канонизации данных XML с помощью Java.

0 голосов
/ 12 апреля 2011

Одна из возможных проблем здесь:

m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());

Как сказал Робинг Грин, кодировка UTF-8 может дать byte[], который длиннее вашей исходной строки (это будет сделано именно тогда, когда строка содержит не-ASCII символы). В этом случае вы хэшируете только начало своей строки.

Лучше напишите это так:

m.update(sb.toString().getBytes("UTF-8"));

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

...