2010-07-01 6 views
8

Je travaille sur un projet python dans 2.6 qui a aussi un support pour le fonctionnement de python 3. Je travaille spécifiquement sur un algorithme digest-md5.Python: concaténation d'octets avec une chaîne

En Python 2.6 sans courir cette importation:

from __future__ import unicode_literals 

Je suis capable d'écrire un morceau de code tel que ceci:

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

sans aucun problème, mon authentification fonctionne très bien. Lorsque je tente la même ligne de code avec les unicode_literals Importé je reçois une exception:

UnicodeDecodeError: « utf8 » codec ne peut pas décoder 0xA8 octet en position 0: le code inattendu octet

Maintenant, je suis relativement nouveau à python, donc je suis un peu coincé à comprendre cela. si je remplace le% s dans la chaîne de formatage par% r, je suis capable de concaténer la chaîne, mais l'authentification ne fonctionne pas. La spécification digest-md5 que j'avais lue indique que le condensé binaire de 16 octets doit être ajouté à ces autres chaînes.

Des pensées?

+1

Python 3.x sépare clairement les chaînes des tableaux d'octets. En fonction de vos besoins, il peut être utile de rajouter les motifs '"% s:% s:% s "' avec 'b' pour obtenir un tableau d'octets, mais cela risque de donner de mauvais résultats. Quel est le but de ce code de toute façon? – Philipp

+0

Ceci est un extrait d'un plus gros morceau de code qui est utilisé pour un algorithme digest-md5 que j'utilise pour s'authentifier auprès d'un serveur xmpp, et c'est le morceau de code spécifique qui me cause quelques problèmes. En attente de la chaîne de formatage avec b provoque toujours le même problème. Voici quelques informations sur la création d'un digest-md5 http://web.archive.org/web/20050224191820/http://cataclysm.cx/wip/digest-md5-crash.html – Macdiesel

Répondre

5

La raison du comportement que vous avez observé que from __future__ import unicode_literals commute la façon dont Python fonctionne avec des cordes:

  • Dans le 2 Série .x, les chaînes sans le préfixe u sont traitées comme des suites d'octets, dont chacune peut être comprise entre \ x00- \ xff (inclus). Les chaînes avec le préfixe u sont des séquences unicode codées ucs-2.
  • En Python 3.x - ainsi que dans l'avenir unicode_literals, chaînes sans le préfixe u sont des chaînes unicode codées dans les deux UCS-2 ou UCS-4 (en fonction du drapeau du compilateur utilisé lors de la compilation Python). Les chaînes avec le préfixe b sont des littéraux pour le type de données bytes qui sont plutôt similaires aux chaînes non-unicode antérieures à 3.x.

Dans les deux versions de Python, les chaînes d'octets et les chaînes unicode doivent être converties. La conversion effectuée par défaut dépend du jeu de caractères par défaut de votre système; dans votre cas, il s'agit de UTF-8. Sans rien régler, il doit être ascii, qui rejette tous les caractères au-dessus de \ x7f. Le résumé du message retourné par hashlib.md5 (...). Digest() est une chaîne d'octets, et je suppose que vous voulez aussi que le résultat de l'opération soit une chaîne d'octets.Si vous voulez que, convertir le nonce et les chaînes de cnonce à octet cordes .:

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

Vous pouvez convertir l'entrée-chaîne d'octets de l'appel à digest() à une chaîne de caractères Unicode (non recommandé). Comme les 8 bits inférieurs d'UCS-2 sont équivalents à ISO-8859-1, cela peut répondre à vos besoins:

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 première solution a fonctionné avec le code. Merci pour votre réponse perspicace. – Macdiesel

1

Le problème est que "% s:% s:% s" est devenu une chaîne unicode une fois que vous avez importé unicode_literals. La sortie du hachage est une chaîne "régulière". Python a essayé de décoder la chaîne normale en une chaîne unicode et a échoué (comme prévu, la sortie du hachage est supposée ressembler à du bruit). Changer votre code à ceci:

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

Je suppose cnonce et challenge["nonce"] sont des chaînes régulières. Pour avoir plus de contrôle sur leur conversion en chaînes (si nécessaire), utilisez:

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

Cette solution et explication aussi travaux. Je vous remercie. – Macdiesel