Python: конкатенация байтов со строкой

Я работаю над проектом 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 двоичных обзоров октета должны быть добавлены к этим другим строкам.

Какие-либо мысли?

10
задан Macdiesel 1 July 2010 в 12:36
поделиться

2 ответа

Причина наблюдаемого поведения заключается в том, что from __future__ import unicode_literals переключает способ работы Python со строками:

  • В серии 2.x строки без u префикс обрабатываются как последовательности байтов, каждый из которых может находиться в диапазоне \ x00- \ xff (включительно). Строки с префиксом u представляют собой последовательности Unicode в кодировке ucs-2.
  • В Python 3.x, а также в будущем 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)
8
ответ дан 4 December 2019 в 00:59
поделиться

Проблема в том, что "% 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')
3
ответ дан 4 December 2019 в 00:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: