Хэш-функция SHA дает отрицательный результат

Я пытаюсь реализовать алгоритм подписи DSA и столкнулся с проблемой. Я использую класс java.security MessageDigest, вот код:

MessageDigest md;
md = MessageDigest.getInstance("SHA-1");
md.update(text.getBytes());
return new BigInteger(md.digest());

Text — это случайный объект String. Проблема в том, что этот код дает мне отрицательные значения хеша, что не принимается алгоритмом. Я делаю что-то неправильно? Заранее спасибо.

P.S. Кстати, я тоже пытался реализовать DSA без использования BigInteger, возможно ли это? Я не нашел значений L и N меньше 1024 и 160, поэтому понятия не имею, какие значения брать и какую хеш-функцию использовать. Буду очень благодарен услышать ответы на эти вопросы.


person Egor    schedule 15.06.2011    source источник
comment
так что вы ожидаете? BigInteger — это просто byte[] с методами для работы. Внешнее представление byte[] MessageDigest и BigInteger не имеет точки соприкосновения.   -  person bestsss    schedule 15.06.2011
comment
@bestsss, так как преобразовать дайджест в BigInteger? И, возможно, какие-либо мысли о P.S. часть моего вопроса? Спасибо за ответ.   -  person Egor    schedule 15.06.2011
comment
почему вы повторно реализуете DSA? Обычно вы должны использовать системные функции; повторное внедрение криптографии опасно, так как может привести к незаметным ошибкам безопасности.   -  person crazyscot    schedule 15.06.2011
comment
@crazyscot Это моя домашняя работа в университете, мне сказали не использовать встроенные классы..   -  person Egor    schedule 15.06.2011
comment
если вам строго нужен положительный (или нулевой) вызов BigInteger abs(). В этом случае вы теряете один бит, в качестве альтернативы вы можете добавить абсолютно минимальное значение к результату, чтобы убедиться, что он всегда положительный. Я просто не вижу вашей проблемы: какова цель алгоритма, которому нужна какая-то случайная последовательность, затем хэшируется, а затем используется как целое число? Если вам просто нужно каким-то образом представить хеш-значение, есть лучшие варианты, чем BigInteger.   -  person bestsss    schedule 15.06.2011
comment
Я не поддерживаю ни один из приведенных выше комментариев. Единственная проблема с вашим кодом заключается в том, что вы должны были использовать new BigInteger(1, md.digest()).   -  person class stacker    schedule 22.12.2012


Ответы (4)


MessageDigest md;
md = MessageDigest.getInstance("SHA-1");
md.update(text.getBytes());
return new BigInteger(1, md.digest()); // use this 1 to tell it is positive.

Затем вы можете преобразовать свой хэш в строку, используя:

String hash = biginteger.toString(16);

Затем, необязательно, добавьте начальные нули.

String zeros = String.format("%032d", 0);
hash = zeros.substring(hash.length()) + hash;
person Martijn Courteaux    schedule 15.06.2011
comment
Во-первых, нет метода MessageDigest.toString(base), и я бы сказал, что в первую очередь это причина вопроса. Вместо этого во втором фрагменте кода выше следует использовать BigInteger.toString(16). Во-вторых, совсем не обязательно добавлять нули. Даже самая худшая функция дайджеста не вернет хеш-значение с четырьмя последовательными битами нулевого значения. - person class stacker; 22.12.2012
comment
Да, вы правы, я исправил. А про набивку я тоже в итоге написал. - person Martijn Courteaux; 22.12.2012
comment
@MartijnCourteaux Прошу прощения за вторую часть моего комментария. Хэши могут генерировать восемь последовательных нулей. Я был уверен, что они не тр, но оказались неправы. - person class stacker; 28.12.2012
comment
@ClassStacker: Ой, подождите. В конце концов значит в конце. Я хотел написать что-то вроде необязательно. - person Martijn Courteaux; 28.12.2012

Почему ты удивлен? MessageDigest#digest() возвращает равномерно распределенные 160 бит данных. Обычно они представляются в виде шестнадцатеричной строки, но если вы преобразуете их в целые числа, старший бит обозначает знак. Проверьте этот код:

System.out.println(new BigInteger(new byte[]{(byte) 255}));  //-1
person Tomasz Nurkiewicz    schedule 15.06.2011

Вы передаете возвращенные байты в BigInteger конструктор. Хотя типы совпадают, я не уверен, чего вы хотите здесь добиться. Из BigInteger JavaDoc:

Преобразует массив байтов, содержащий двоичное представление BigInteger с дополнением до двух.

person Waldheinz    schedule 15.06.2011

Не изобретайте велосипед, особенно для криптографии — используйте java.security.Signature или библиотеку более высокого уровня.

person jkraybill    schedule 15.06.2011