2010-07-01 20 views
8

Pracuję nad projektem Pythona w wersji 2.6, który również ma przyszłe wsparcie dla pracy Pythona 3. W szczególności pracuję nad algorytmem digest-md5.Python: konkatenowanie bajtów za pomocą ciągu znaków

W Pythonie 2.6 działa bez tego importu:

from __future__ import unicode_literals 

jestem w stanie napisać kawałek kodu, takich jak to:

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

bez żadnych problemów, mój uwierzytelnianie działa prawidłowo. Kiedy próbuję tej samej linii kodu z unicode_literals importowane uzyskać wyjątek:

UnicodeDecodeError: „utf8” kodek nie potrafi dekodować bajtowy 0xa8 w pozycji 0: Kod nieoczekiwany bajt

Teraz jestem stosunkowo nowy pytonowi, więc utknąłem w tym. jeśli zastąpię% s w ciągu formatowania jako% r, mogę połączyć ciąg znaków, ale uwierzytelnianie nie działa. Specyfikacja digest-md5, którą przeczytałem, mówi, że 16-oktetowa ścieżka binarna musi być dołączona do tych innych ciągów.

Jakieś myśli?

+1

Python 3.x wyraźnie oddziela struny od tablic bajtowych. W zależności od twoich potrzeb * może * pracować, aby poprzedzić wzorce ''% s:% s:% s "' z 'b', aby uzyskać tablicę bajtów, ale może to również dać złe wyniki. Jaki jest cel tego kodu? – Philipp

+0

To jest fragment większego fragmentu kodu, który jest używany do algorytmu digest-md5, którego używam do uwierzytelniania na serwerze xmpp, i jest to specyficzny fragment kodu, który powoduje mi pewne problemy. Zawieszanie łańcucha formatowania za pomocą przycisku b wciąż powoduje ten sam problem. Oto niektóre informacje na temat tworzenia digest-md5 http://web.archive.org/web/20050224191820/http://cataclysm.cx/wip/digest-md5-crash.html – Macdiesel

Odpowiedz

5

Powodem zachowań zaobserwowanych że from __future__ import unicode_literals przełącza sposób Python działa z ciągów:

  • W 2 Serie .x, ciągi bez prefiksu u są traktowane jako ciągi bajtów, z których każdy może być w zakresie \ x00- \ xff (włącznie). Ciągi z prefiksem u są kodowanymi w Ucs-2 sekwencjami Unicode.
  • Pythona 3.x - a także w przyszłości unicode_literals ciągi bez przedrostka U są unicode ciągi kodowanych w jednej UCS-2 lub UCS-4 (w zależności od stosowanego flaga kompilator podczas kompilacji Pyton). Łańcuchy z prefiksem b są literałami dla typu danych bytes, które są raczej podobne do ciągów nie-unicode sprzed 3.x.

W obu wersjach Pythona, ciągi bajtów i ciągi znaków Unicode muszą zostać przekonwertowane. Konwersja wykonywana domyślnie zależy od domyślnego zestawu znaków twojego systemu; w twoim przypadku jest to UTF-8. Bez ustawiania czegokolwiek, powinno to być ascii, które odrzuca wszystkie znaki powyżej \ x7f.

Esencja wiadomości zwrócona przez hashlib.md5 (...). Digest() to ciąg znaków w bajtach, a przypuszczam, że wynik całej operacji ma być również ciągiem bajtów.Jeśli chcesz, że konwersja nonce i cnonce-ciągów bajtów ciągów .:

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

Alternatywnie, można przekonwertować ciąg bajtów pochodzących z wywołaniu digest() na ciąg Unicode (nie zalecane). Ponieważ dolny 8 bit UCS-2 jest równoważny z ISO-8859-1, może to służyć twoim potrzebom:

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

Pierwsze rozwiązanie działało z kodem. Dziękuję za twoją wnikliwą odpowiedź. – Macdiesel

1

Problem polega na tym, że "% s:% s:% s" stał się ciągiem unicode po zaimportowaniu unicode_literals. Dane wyjściowe skrótu to ciąg "zwykły". Python próbował odszyfrować zwykły ciąg znaków w łańcuchu Unicode i nie powiodło się (zgodnie z oczekiwaniami. Wynik skrótu powinien wyglądać jak szum). Zmień swój kod do tego:

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

Jestem zakładając cnonce i challenge["nonce"] regularne ciągi. Aby mieć większą kontrolę nad ich konwersji na ciągi znaków (w razie potrzeby), zastosowanie:

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

To rozwiązanie i objaśnienie również Prace. Dziękuję Ci. – Macdiesel

Powiązane problemy