Я работаю над проектом Python в 2,6, который также имеет будущую поддержку python 3, работать в. Конкретно я работаю над алгоритмом обзора-md5.
В python 2.6, не выполняя этот импорт:
from __future__ import unicode_literals
Я могу записать часть кода, такого как это:
a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest()
a1 = "%s:%s:%s" %(a1, challenge["nonce"], cnonce )
Без любых проблем хорошо работает моя аутентификация. То, когда я пробую ту же строку кода unicode_literals, импортировало, я получаю исключение:
UnicodeDecodeError: кодек 'utf8' не может декодировать байт 0xa8 в положении 0: неожиданный байт кода
Теперь я относительно плохо знаком с Python, таким образом, я немного застреваю в понимании этого. если я заменяю %s в строке форматирования как %r, я могу связать строку, но аутентификация не работает. Спецификация обзора-md5, которую я считал, говорит, что 16 двоичных обзоров октета должны быть добавлены к этим другим строкам.
Какие-либо мысли?
Причина наблюдаемого поведения заключается в том, что from __future__ import unicode_literals
переключает способ работы Python со строками:
unicode_literals
строки без префикса u являются строками Unicode, закодированными в UCS-2 или UCS-4 (в зависимости от на флаге компилятора, используемом при компиляции Python). Строки с префиксом b являются литералами для типа данных байтов
, которые очень похожи на строки, не относящиеся к Unicode до 3.x. В любой версии Python должны быть преобразованы байтовые строки и строки Unicode. Преобразование, выполняемое по умолчанию, зависит от кодировки вашей системы по умолчанию; в вашем случае это UTF-8 . Без каких-либо настроек, это должен быть ascii , который отклоняет все символы выше \ x7f.
Дайджест сообщения, возвращаемый hashlib.md5 (...). Digest (), представляет собой строку байтов, и я полагаю, вы хотите, чтобы результат всей операции также был строкой байтов. Если вы хотите этого, преобразуйте строки nonce и cnonce в строки байтов. :
a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest()
# note that UTF-8 may not be the encoding required by your counterpart, please check
a1 = b"%s:%s:%s" %(a1, challenge["nonce"].encode("UTF-8"), cnonce.encode("UTF-8") )
В качестве альтернативы вы можете преобразовать строку байтов, полученную в результате вызова функции digest ()
, в строку Unicode (не рекомендуемые).Поскольку младшие 8 бит UCS-2 эквивалентны ISO-8859-1, это может удовлетворить ваши потребности:
a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest()
a1 = "%s:%s:%s" %(a1.decode("ISO-8859-1"), challenge["nonce"], cnonce)
Проблема в том, что "% s:% s:% s" стало строкой Unicode после того, как вы импортировали unicode_literals. Результатом хэша является «обычная» строка. Python попытался декодировать обычную строку в строку Unicode и потерпел неудачу (как и ожидалось. Выходной хеш-код должен выглядеть как шум). Измените свой код на этот:
a1 = a1 + str(':') + str(challenge["nonce"]) + str(':') + str(cnonce)
Я предполагаю, что cnonce
и challenge ["nonce"]
являются обычными строками. Чтобы иметь больший контроль над их преобразованием в строки (при необходимости), используйте:
a1 += str(':') + challenge["nonce"].encode('UTF-8') + str(':') + cnonce.encode('UTF-8')