Повторное использование hashlib.md5 вычисляет разные значения для одинаковых строк - PullRequest
0 голосов
/ 25 мая 2018

Это мой первый тестовый код:

   import hashlib
   md5Hash = hashlib.md5()
   md5Hash.update('Coconuts')
   print md5Hash.hexdigest()

   md5Hash.update('Apples')
   print md5Hash.hexdigest()

   md5Hash.update('Oranges')
   print md5Hash.hexdigest()

И это мой второй кусок кода:

    import hashlib
    md5Hash = hashlib.md5()
    md5Hash.update('Coconuts')
    print md5Hash.hexdigest()

    md5Hash.update('Bananas')
    print md5Hash.hexdigest()

    md5Hash.update('Oranges')
    print md5Hash.hexdigest()

Но вывод для 1-го кода:

    0e8f7761bb8cd94c83e15ea7e720852a
    217f2e2059306ab14286d8808f687abb
    4ce7cfed2e8cb204baeba9c471d48f07

А для второго кода:

   0e8f7761bb8cd94c83e15ea7e720852a
   a82bf69bf25207f2846c015654ae68d1
   47dba619e1f3eaa8e8a01ab93c79781e

Я заменил вторую строку с «Яблоки» на «Бананы», а третья строка остается прежней.Но все же я получаю другой результат для третьей строки.Хэширование должно иметь одинаковый результат каждый раз.Я что-то упустил?

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

hashlib.md5.update() добавляет данные в хеш.Он не заменяет существующие значения;если вы хотите хэшировать новое значение, вам нужно инициализировать новый hashlib.md5 объект.

Значения, которые вы хэшируете:

"Coconuts"               -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsApples"         -> 217f2e2059306ab14286d8808f687abb
"CoconutsApplesOranges"  -> 4ce7cfed2e8cb204baeba9c471d48f07

"Coconuts"               -> 0e8f7761bb8cd94c83e15ea7e720852a
"CoconutsBananas"        -> a82bf69bf25207f2846c015654ae68d1
"CoconutsBananasOranges" -> 47dba619e1f3eaa8e8a01ab93c79781e
0 голосов
/ 28 мая 2018

Ожидаемый результат

То, что вы ожидаете, обычно является тем, чего вы должны ожидать от обычных криптографических библиотек.В большинстве криптографических библиотек хеш-объект сбрасывается после вызова метода, который завершает вычисление , например hexdigest.Кажется, что hashlib.md5 использует альтернативное поведение.

Результат по hashlib.md5

MD5 требует, чтобы вход был дополнен 1 битом, нулем или более 0 битами идлина ввода в битах.Затем вычисляется окончательное значение хеша.hashlib.md5 внутренне, кажется, выполняет окончательное вычисление, используя отдельные переменные, сохраняя состояние после хэширования каждой строки без этого окончательного заполнения.

Таким образом, результатом ваших хэшей является объединение более ранних строк с данной строкой,с последующим правильным заполнением, как duskwulf указал в своем ответе .

Это правильно задокументировано hashlib:

hash.digest()

Возвращает дайджест строк, переданных в метод update() до сих пор .Это строка из digest_size байтов, которая может содержать не-ASCII-символы, включая нулевые байты.

и

hash.hexdigest()

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

Решение для hashlib.md5

Поскольку там не кажетсячтобы быть reset() методом , вы должны создать новый объект md5 для каждого отдельного хеш-значения, которое вы хотите создать.К счастью, сами хеш-объекты относительно легки (даже если само хеширование не выполняется), поэтому это не потребляет много ресурсов ЦП или памяти.

Обсуждение различий

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

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

Как указано, я считаю, что это плохой дизайн API авторами hashlib.Для криптографов это, конечно, не следует правилу наименьшего удивления.

0 голосов
/ 25 мая 2018

Поскольку вы используете метод update, объект md5Hash повторно используется для 3 строк.Таким образом, это в основном хэш трех строк, соединенных вместе.Таким образом, изменение второй строки также меняет результат для 3-го отпечатка.

Вам необходимо объявить отдельный объект md5 для каждой строки.Используйте цикл (и Python 3-совместимый код требует байтовый префикс BTW, а также работает в Python 2):

import hashlib
for s in (b'Coconuts',b'Bananas',b'Oranges'):
    md5Hash = hashlib.md5(s)  # no need for update, pass data at construction
    print(md5Hash.hexdigest())

результат:

0e8f7761bb8cd94c83e15ea7e720852a
1ee31b77d0697c36914b99d1428f7f32
62f2b77089fea4c595e895901b63c10b

обратите внимание, что значения теперь разные, но по крайней мере это MD5 каждой строки, вычисляемой независимо.

...