Mam pewne dane zakodowane w base64, które chcę przekonwertować z powrotem na binarne, nawet jeśli występuje w nich błąd wypełnienia. Jeśli używam
base64.decodestring(b64_string)
zgłasza błąd „Nieprawidłowe wypełnienie”. Czy jest inny sposób?
AKTUALIZACJA: Dzięki za wszystkie opinie. Szczerze mówiąc, wszystkie wspomniane metody brzmiały na chybił trafił, więc zdecydowałem się wypróbować openssl. Następujące polecenie działało świetnie:
openssl enc -d -base64 -in b64string -out binary_data
base64.b64decode(strg, '-_')
? To jest a priori, bez zadawania sobie trudu dostarczenia jakichkolwiek przykładowych danych, najbardziej prawdopodobnego rozwiązania Twojego problemu w Pythonie. Zaproponowane „metody” to sugestie DEBUGOWANIA, KONIECZNIE „trafienie i chybienie”, biorąc pod uwagę niedostatek dostarczonych informacji.base64.urlsafe_b64decode(s)
sorted(list(set(b64_string)))
proszę? Nie ujawniając niczego poufnego dla firmy, powinno to ujawnić, które znaki zostały użyte do zakodowania oryginalnych danych, które z kolei mogą dostarczyć wystarczających informacji, aby zapewnić rozwiązanie, którego nie można przegapić.Odpowiedzi:
Jak wspomniano w innych odpowiedziach, istnieją różne sposoby uszkodzenia danych base64.
Jednak, jak mówi Wikipedia , usunięcie dopełnienia (znaków „=” na końcu danych zakodowanych w base64) jest „bezstratne”:
Więc jeśli to naprawdę jedyna „nieprawidłowa” rzecz z danymi base64, wypełnienie można po prostu dodać z powrotem. Wymyśliłem to, aby móc analizować adresy URL „danych” w WeasyPrint, z których niektóre były base64 bez dopełnienia:
Testy dla tej funkcji: weasyprint / tests / test_css.py # L68
źródło
str(data)
base64.decodestring
został uznany za przestarzałybase64.decodebytes
w Py3, ale ze względu na lepszą zgodność wersjibase64.b64decode
.base64
moduł ignoruje nieprawidłowe znaki inne niż base64 w danych wejściowych, najpierw należy znormalizować dane. Usuń wszystko, co nie jest literą, cyfrą/
ani+
, a następnie dodaj wypełnienie.Po prostu dodaj wypełnienie zgodnie z wymaganiami. Uważajcie jednak na ostrzeżenie Michaela.
źródło
===
zawsze działa. Wszystkie dodatkowe=
znaki są pozornie bezpiecznie odrzucane przez Pythona.Wygląda na to, że przed dekodowaniem wystarczy dodać dopełnienie do swoich bajtów. Istnieje wiele innych odpowiedzi na to pytanie, ale chcę zwrócić uwagę, że (przynajmniej w Pythonie 3.x)
base64.b64decode
obcina dodatkowe wypełnienie, pod warunkiem, że jest wystarczająco dużo.Więc coś takiego:
b'abc='
działa równie dobrzeb'abc=='
(jakb'abc====='
).Oznacza to, że możesz po prostu dodać maksymalną liczbę znaków wypełniających, których kiedykolwiek będziesz potrzebować - czyli trzy (
b'==='
) - a base64 obetnie wszystkie niepotrzebne.Dzięki temu możesz napisać:
co jest prostsze niż:
źródło
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4
. Dziękuję za zwrócenie uwagi!„Nieprawidłowe wypełnienie” może oznaczać nie tylko „brakujące wypełnienie”, ale także (wierz lub nie) „nieprawidłowe wypełnienie”.
Jeśli sugerowane metody „dodawania dopełnienia” nie działają, spróbuj usunąć niektóre bajty końcowe:
Aktualizacja: Wszelkie manipulacje przy dodawaniu wypełnienia lub usuwaniu prawdopodobnie złych bajtów z końca powinny być wykonywane PO usunięciu jakichkolwiek białych znaków, w przeciwnym razie obliczenia długości będą zakłócone.
Byłoby dobrze, gdybyś pokazał nam (krótką) próbkę danych, które musisz odzyskać. Edytuj swoje pytanie i skopiuj / wklej wynik
print repr(sample)
.Aktualizacja 2: Możliwe, że kodowanie zostało wykonane w sposób bezpieczny dla adresów URL. W takim przypadku będziesz mógł zobaczyć znaki minus i podkreślenia w swoich danych i powinieneś być w stanie je zdekodować za pomocą
base64.b64decode(strg, '-_')
Jeśli nie widzisz znaków minus i podkreślenia w swoich danych, ale widzisz znaki plus i ukośnik, to masz inny problem i możesz potrzebować sztuczek add-padding lub remove-cruft.
Jeśli w danych nie widać żadnego znaku minus, podkreślenia, plusa i ukośnika, musisz określić dwa alternatywne znaki; będą tymi, których nie ma w [A-Za-z0-9]. Następnie musisz poeksperymentować, aby zobaczyć, w jakiej kolejności należy ich użyć w drugim argumencie
base64.b64decode()
Aktualizacja 3 : Jeśli Twoje dane są „poufne dla firmy”:
(a) powinieneś to powiedzieć z góry
(b) możemy zbadać inne sposoby zrozumienia problemu, który z dużym prawdopodobieństwem ma związek z tym, jakie znaki są używane zamiast
+
i/
w alfabet kodowania lub inne formatowanie lub obce znaki.Jedną z takich możliwości byłoby zbadanie, jakie niestandardowe znaki znajdują się w Twoich danych, np
źródło
Posługiwać się
Zasługa komentarza gdzieś tutaj.
źródło
Jeśli wystąpi błąd wypełnienia, prawdopodobnie oznacza to, że ciąg jest uszkodzony; Ciągi zakodowane w base64 powinny mieć wielokrotność czterech długości. Możesz spróbować
=
samodzielnie dodać znak wypełniający ( ), aby ciąg był wielokrotnością czterech, ale powinien już mieć to, chyba że coś jest nie takźródło
Sprawdź dokumentację źródła danych, które próbujesz zdekodować. Czy to możliwe, że zamierzałeś użyć
base64.urlsafe_b64decode(s)
zamiastbase64.b64decode(s)
? To jeden z powodów, dla których mogłeś zobaczyć ten komunikat o błędzie.Dzieje się tak na przykład w przypadku różnych interfejsów API Google, takich jak Google Identity Toolkit i ładunki Gmaila.
źródło
urlsafe_b64decode
wymaga również wypełnienia.base64.urlsafe_b64decode
.Dodanie wypełnienia jest raczej ... kłopotliwe. Oto funkcja, którą napisałem z pomocą komentarzy w tym wątku, a także strony wiki dla base64 (jest to zaskakująco pomocne) https://en.wikipedia.org/wiki/Base64#Padding .
źródło
Możesz po prostu użyć,
base64.urlsafe_b64decode(data)
jeśli próbujesz zdekodować obraz internetowy. Automatycznie zajmie się wyściółką.źródło
Istnieją dwa sposoby poprawienia opisanych tutaj danych wejściowych lub, dokładniej i zgodnie z OP, aby metoda b64decode modułu Pythona base64 mogła przetwarzać dane wejściowe na coś bez wywoływania niezauważonego wyjątku:
Jeśli to powoduje wyjątek, to
ja. Złap to przez try / z wyjątkiem,
ii. (R?) Usuń dowolne = znaki z danych wejściowych (uwaga: może to nie być konieczne),
iii. Dołącz A == do danych wejściowych (będą działać od A == do P ==),
iv. Wywołaj base64.b64decode (...) z tymi A == - dołączonymi danymi wejściowymi
Wynik z punktu 1. lub punktu 2. powyżej da pożądany rezultat.
Ostrzeżenia
Nie gwarantuje to, że zdekodowany wynik będzie taki, jaki był pierwotnie zakodowany, ale (czasami?) Zapewni OP wystarczający do pracy z:
Zobacz co wiemy i Założenia poniżej.
TL; DR
Z kilku szybkich testów base64.b64decode (...)
wygląda na to, że ignoruje znaki inne niż [A-Za-z0-9 + /]; co obejmuje ignorowanie = s, chyba że są to ostatnie znaki w przeanalizowanej grupie czterech, w którym to przypadku = s przerywa dekodowanie (a = b = c = d = daje taki sam wynik jak abc = i a = = b == c == daje taki sam wynik jak ab ==).
Okazuje się również, że wszystkie dołączane znaki są ignorowane po punkcie, w którym base64.b64decode (...) kończy dekodowanie np. Od an = jako czwarty w grupie.
Jak zauważono w kilku komentarzach powyżej, na końcu danych wejściowych wymagane jest albo zero, albo jeden lub dwa = s wypełnienia, gdy wartość [liczba przeanalizowanych znaków do tego punktu modulo 4] wynosi 0 lub 3, lub 2, odpowiednio. Tak więc, począwszy od pozycji 3. i 4. powyżej, dołączenie dwóch lub więcej = s do danych wejściowych, poprawi wszelkie problemy [Nieprawidłowe wypełnienie] w tych przypadkach.
JEDNAK, dekodowanie nie może obsłużyć przypadku, w którym [całkowita liczba przeanalizowanych znaków modulo 4] wynosi 1, ponieważ wymaga co najmniej dwóch zakodowanych znaków, aby reprezentować pierwszy zdekodowany bajt w grupie trzech zdekodowanych bajtów. W un uszkodzony zakodowane dane wejściowe, to [N modulo 4] = 1 przypadek nie dzieje, ale jak PO stwierdził, że znaki mogą być niedostępne, może się zdarzyć tutaj. Dlatego samo dołączanie = s nie zawsze będzie działać i dlaczego dołączanie A == będzie działać, gdy dołączanie == nie. NB Użycie [A] jest prawie dowolne: dodaje tylko wyczyszczone (zerowe) bity do zdekodowanych, które mogą być poprawne lub nie, ale wtedy przedmiotem tutaj nie jest poprawność, ale uzupełnienie przez base64.b64decode (...) bez wyjątków .
To, co wiemy z PO, a zwłaszcza z kolejnych komentarzy, to
openssl enc ...
działa.Założenia
Github
Oto opakowanie umożliwiające wdrożenie tego rozwiązania:
https://github.com/drbitboy/missing_b64
źródło
Niepoprawny błąd dopełniania jest spowodowany czasami metadane są również obecne w zakodowanym ciągu Jeśli twój ciąg wygląda mniej więcej tak: 'data: image / png; base64, ... base 64 stuff ....', musisz usunąć pierwszy część przed odkodowaniem.
Powiedz, że masz ciąg znaków zakodowany w formacie base64, a następnie wypróbuj poniższy fragment.
źródło
Po prostu dodaj dodatkowe znaki, takie jak „=” lub inne, i ustaw je jako wielokrotność 4, zanim spróbujesz zdekodować docelową wartość ciągu. Coś jak;
źródło
W przypadku, gdy ten błąd pochodzi z serwera internetowego: spróbuj zakodować adres URL swojej wartości postu. Wysyłałem POST przez "curl" i odkryłem, że nie koduję url mojej wartości base64, więc znaki takie jak "+" nie były zmieniane, więc logika dekodowania adresu URL serwera WWW automatycznie wykonywała dekodowanie url i + zamieniła na spacje.
„+” to prawidłowy znak base64 i być może jedyny znak, który zostaje zniekształcony przez nieoczekiwane dekodowanie adresu URL.
źródło
W moim przypadku napotkałem ten błąd podczas analizowania wiadomości e-mail. Mam załącznik jako ciąg base64 i wyodrębniam go przez re.search. Ostatecznie na końcu pojawił się dziwny dodatkowy podciąg.
Kiedy usunąłem
--_=ic0008m4wtZ4TqBFd+sXC8--
i usunąłem ciąg, parsowanie zostało naprawione.Dlatego radzę upewnić się, że dekodujesz poprawny ciąg base64.
źródło
Powinieneś użyć
Domyślnie ołtarze to
'+/'
.źródło
Napotkałem również ten problem i nic nie działało. W końcu udało mi się znaleźć rozwiązanie, które działa na mnie. Spakowałem zawartość w base64 i stało się to 1 na milion rekordów ...
To jest wersja rozwiązania zaproponowana przez Simona Sapina.
W przypadku braku dopełnienia 3, usuwam ostatnie 3 znaki.
Zamiast „0gA1RD5L / 9AUGtH9MzAwAAA ==”
Otrzymujemy „0gA1RD5L / 9AUGtH9MzAwAA”
Zgodnie z tą odpowiedzią Trailing As w base64 powodem jest zero. Ale nadal nie mam pojęcia, dlaczego koder to psuje ...
źródło