2010-07-01 18 views
8

Estoy trabajando en un proyecto python en 2.6 que también tiene soporte futuro para python 3 en el que se está trabajando. Específicamente, estoy trabajando en un algoritmo digest-md5.Python: concatenando bytes con una cadena

en Python 2.6, sin correr esta importación:

from __future__ import unicode_literals 

soy capaz de escribir una pieza de código como este:

a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest() 
a1 = "%s:%s:%s" %(a1, challenge["nonce"], cnonce) 

sin ningún problema, mi autenticación funciona bien. Cuando trato de la misma línea de código con los unicode_literals importados consigo una excepción:

UnicodeDecodeError: códec 'utf8' no puede decodificar 0xa8 byte en la posición 0: byte de código inesperada

Ahora estoy relativamente nuevo a Python, así que estoy un poco atrapado en resolver esto. si reemplazo el% s en la cadena de formato como% r, puedo concatenar la cadena, pero la autenticación no funciona. La especificación de digest-md5 que leí dice que el resumen binario de 16 octetos debe adjuntarse a estas otras cadenas.

¿Alguna idea?

+1

Python 3.x separa claramente las cadenas de las matrices de bytes. Dependiendo de sus necesidades, * podría * trabajar para anteponer los patrones '"% s:% s:% s "' con 'b' para obtener una matriz de bytes, pero eso bien podría dar los resultados incorrectos. ¿Cuál es el propósito de este código de todos modos? – Philipp

+0

Este es un fragmento de un código más grande que se utiliza para un algoritmo de digest-md5 que estoy utilizando para autenticar contra un servidor xmpp, y esta es la pieza específica de código que me está causando algunos problemas. Pendiente de la cadena de formato con b sigue causando el mismo problema. Aquí hay más información sobre cómo crear un digest-md5 http://web.archive.org/web/20050224191820/http://cataclysm.cx/wip/digest-md5-crash.html – Macdiesel

Respuesta

5

La razón de la conducta que ha observado es que from __future__ import unicode_literals cambia la forma en Python funciona con cadenas:

  • En la 2 .x series, las cadenas sin el prefijo u se tratan como secuencias de bytes, cada una de las cuales puede estar en el rango \ x00- \ xff (inclusive). Las cadenas con el prefijo u son secuencias unicode codificadas ucs-2.
  • En Python 3.x -, así como en el futuro unicode_literals, cadenas sin el prefijo u son cadenas Unicode codificados en cualquiera UCS-2 o UCS-4 (depende de la bandera compilador utilizado al compilar Python). Las cadenas con el prefijo b son literales para el tipo de datos bytes que son bastante similares a las cadenas pre-3.x no unicode.

En cualquier versión de Python, se deben convertir cadenas de bytes y unicode. La conversión realizada por defecto depende del juego de caracteres predeterminado de su sistema; en su caso, esto es UTF-8. Sin configurar nada, debe ser ascii, que rechaza todos los caracteres por encima de \ x7f.

El resumen del mensaje devuelto por hashlib.md5 (...). Digest() es una cadena de bytes, y supongo que también quiere que el resultado de toda la operación sea una cadena de bytes.Si usted quiere eso, convertir el valor de uso único y cnonce-secuencias de bytes cuerdas .:

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")) 

Alternativamente, puede convertir el byte de cadena procedente de la llamada a digest() a una cadena Unicode (no recomendado). Como los 8 bits inferiores de UCS-2 son equivalentes a ISO-8859-1, esto podría satisfacer sus necesidades:

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) 
+0

La primera solución funcionó con el código. Gracias por tu respuesta perspicaz. – Macdiesel

1

El problema es que "% s:% s:% s" se convirtió en una cadena Unicode una vez que importó unicode_literals. La salida del hash es una cadena "normal". Python intentó decodificar la cadena regular en una cadena Unicode y falló (como se esperaba. Se supone que la salida de hash se parece al ruido). cambiar el código para esto:

a1 = a1 + str(':') + str(challenge["nonce"]) + str(':') + str(cnonce) 

Estoy asumiendo cnonce y challenge["nonce"] son cadenas regulares. Para tener más control sobre su conversión a cadenas (si es necesario), utilice:

a1 += str(':') + challenge["nonce"].encode('UTF-8') + str(':') + cnonce.encode('UTF-8') 
+0

Esta solución y explicación también trabajos. Gracias. – Macdiesel

Cuestiones relacionadas