Tenho alguns dados codificados em base64 que desejo converter de volta para binário, mesmo que haja um erro de preenchimento. Se eu usar
base64.decodestring(b64_string)
isso gera um erro de 'Preenchimento incorreto'. Existe outra maneira?
ATUALIZAÇÃO: Obrigado por todos os comentários. Para ser honesto, todos os métodos mencionados pareciam um tanto imprevisíveis, então decidi tentar o openssl. O seguinte comando funcionou muito bem:
openssl enc -d -base64 -in b64string -out binary_data
base64.b64decode(strg, '-_')
? Isso é a priori, sem você se preocupar em fornecer nenhum dado de amostra, a solução Python mais provável para o seu problema. Os “métodos” propostos foram sugestões de DEBUG, NECESSARIAMENTE “acertos e erros” dada a escassez de informações fornecidas.base64.urlsafe_b64decode(s)
sorted(list(set(b64_string)))
por favor? Sem revelar nada de confidencial da empresa, isso deve revelar quais caracteres foram usados para codificar os dados originais, o que, por sua vez, pode fornecer informações suficientes para fornecer uma solução que não acertar ou errar.Respostas:
Como dito em outras respostas, existem várias maneiras em que os dados base64 podem ser corrompidos.
No entanto, como diz a Wikipedia , remover o preenchimento (os caracteres '=' no final dos dados codificados em base64) é "sem perdas":
Portanto, se essa for realmente a única coisa "errada" com seus dados base64, o preenchimento pode ser apenas adicionado de volta. Eu criei isso para ser capaz de analisar URLs de "dados" no WeasyPrint, alguns dos quais eram base64 sem preenchimento:
Testes para esta função: weasyprint / tests / test_css.py # L68
fonte
str(data)
base64.decodestring
foi descontinuadobase64.decodebytes
no Py3, mas para compatibilidade de versão é melhor usarbase64.b64decode
.base64
módulo ignora caracteres não-base64 inválidos na entrada, primeiro é necessário normalizar os dados. Remova tudo o que não seja uma letra, dígito/
ou+
e, em seguida, adicione o preenchimento.Basta adicionar preenchimento conforme necessário. Preste atenção ao aviso de Michael, no entanto.
fonte
===
sempre funciona. Quaisquer=
caracteres extras são aparentemente descartados com segurança pelo Python.Parece que você só precisa adicionar preenchimento aos bytes antes da decodificação. Existem muitas outras respostas para essa pergunta, mas quero salientar que (pelo menos no Python 3.x)
base64.b64decode
truncará qualquer preenchimento extra, desde que haja o suficiente em primeiro lugar.Então, algo como:
b'abc='
funciona tão bem quantob'abc=='
(como fazb'abc====='
).O que isso significa é que você pode apenas adicionar o número máximo de caracteres de preenchimento que você precisa - que é três (
b'==='
) - e a base64 truncará quaisquer caracteres desnecessários.Isso permite que você escreva:
que é mais simples do que:
fonte
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4
. Obrigado por apontar isso!"Preenchimento incorreto" pode significar não apenas "preenchimento ausente", mas também (acredite ou não) "preenchimento incorreto".
Se os métodos de "adição de preenchimento" sugeridos não funcionarem, tente remover alguns bytes finais:
Atualização: Qualquer tentativa de adicionar preenchimento ou remover bytes possivelmente danificados do final deve ser feito APÓS a remoção de qualquer espaço em branco, caso contrário, os cálculos de comprimento serão alterados.
Seria uma boa ideia se você nos mostrasse uma amostra (curta) dos dados que você precisa recuperar. Edite sua pergunta e copie / cole o resultado de
print repr(sample)
.Atualização 2: é possível que a codificação tenha sido feita de maneira segura para url. Se for esse o caso, você será capaz de ver os caracteres de subtração e sublinhado em seus dados e deverá ser capaz de decodificá-los usando
base64.b64decode(strg, '-_')
Se você não consegue ver os caracteres de subtração e sublinhado em seus dados, mas consegue ver os caracteres de mais e barra, então você tem outro problema e pode precisar dos truques de adicionar preenchimento ou remover cruft.
Se você não consegue ver nenhum de menos, sublinhado, mais e barra em seus dados, então você precisa determinar os dois caracteres alternativos; eles serão aqueles que não estão em [A-Za-z0-9]. Então você precisará experimentar para ver em qual ordem eles precisam ser usados no segundo argumento de
base64.b64decode()
Atualização 3 : Se seus dados são "confidenciais da empresa":
(a) você deve dizer isso antecipadamente
(b) podemos explorar outros caminhos para a compreensão do problema, que é altamente provável que esteja relacionado a quais caracteres são usados em vez de
+
e/
em o alfabeto de codificação, ou por outra formatação ou caracteres estranhos.Uma dessas vias seria examinar quais caracteres não "padrão" estão em seus dados, por exemplo
fonte
Usar
O crédito vai para um comentário em algum lugar aqui.
fonte
Se houver um erro de preenchimento, provavelmente significa que sua string está corrompida; As strings codificadas em base64 devem ter um comprimento múltiplo de quatro. Você pode tentar adicionar o caractere de preenchimento (
=
) para tornar a string um múltiplo de quatro, mas já deve ter isso a menos que algo esteja erradofonte
Verifique a documentação da fonte de dados que você está tentando decodificar. É possível que você quisesse usar em
base64.urlsafe_b64decode(s)
vez debase64.b64decode(s)
? Esse é um dos motivos pelos quais você pode ter visto essa mensagem de erro.Este é, por exemplo, o caso de várias APIs do Google, como o Identity Toolkit do Google e cargas úteis do Gmail.
fonte
urlsafe_b64decode
também requer preenchimento.base64.urlsafe_b64decode
.Adicionar o preenchimento é bastante ... complicado. Aqui está a função que escrevi com a ajuda dos comentários neste tópico, bem como a página wiki para base64 (é surpreendentemente útil) https://en.wikipedia.org/wiki/Base64#Padding .
fonte
Você pode simplesmente usar
base64.urlsafe_b64decode(data)
se estiver tentando decodificar uma imagem da web. Ele cuidará automaticamente do enchimento.fonte
Existem duas maneiras de corrigir os dados de entrada descritos aqui ou, mais especificamente e em linha com o OP, para tornar o método b64decode do módulo Python base64 capaz de processar os dados de entrada para algo sem gerar uma exceção não detectada:
Se isso gerar uma exceção, então
Eu. Pegue-o via try / except,
ii. (R?) Retire quaisquer = caracteres dos dados de entrada (NB, pode não ser necessário),
iii. Anexe A == aos dados de entrada (A == a P == funcionará),
iv. Chame base64.b64decode (...) com aqueles A == - dados de entrada anexados
O resultado do item 1. ou item 2. acima produzirá o resultado desejado.
Ressalvas
Isso não garante que o resultado decodificado será o que foi originalmente codificado, mas (às vezes?) Dará ao OP o suficiente para trabalhar:
Veja o que sabemos e suposições abaixo.
TL; DR
De alguns testes rápidos de base64.b64decode (...)
parece que ele ignora caracteres não- [A-Za-z0-9 + /]; isso inclui ignorar = s, a menos que sejam os últimos caracteres em um grupo analisado de quatro, caso em que = s encerram a decodificação (a = b = c = d = dá o mesmo resultado que abc =, e a = = b == c == dá o mesmo resultado que ab ==).
Também parece que todos os caracteres acrescentados são ignorados após o ponto onde base64.b64decode (...) termina a decodificação, por exemplo, de an = como o quarto em um grupo.
Conforme observado em vários comentários acima, há zero, ou um, ou dois, = s de preenchimento necessário no final dos dados de entrada para quando o valor de [número de caracteres analisados até aquele ponto módulo 4] for 0 ou 3, ou 2, respectivamente. Portanto, a partir dos itens 3. e 4. acima, anexar dois ou mais = s aos dados de entrada corrigirá quaisquer problemas de [preenchimento incorreto] nesses casos.
NO ENTANTO, a decodificação não pode lidar com o caso onde o [número total de caracteres analisados módulo 4] é 1, porque são necessários pelo menos dois caracteres codificados para representar o primeiro byte decodificado em um grupo de três bytes decodificados. Em dados de entrada codificados não corrompidos, este [N módulo 4] = 1 caso nunca acontece, mas como o OP afirmou que caracteres podem estar faltando, isso pode acontecer aqui. É por isso que simplesmente anexar = s nem sempre funcionará, e por que anexar A == irá funcionar quando anexar == não. NB Usar [A] é quase arbitrário: ele adiciona apenas bits apagados (zero) ao decodificado, o que pode ou não ser correto, mas então o objeto aqui não é a correção, mas a conclusão por base64.b64decode (...) sem exceções .
O que sabemos do OP e especialmente dos comentários subsequentes é
openssl enc ...
funciona.Premissas
Github
Aqui está um wrapper para implementar esta solução:
https://github.com/drbitboy/missing_b64
fonte
O erro de preenchimento incorreto é causado porque às vezes os metadados também estão presentes na string codificada. Se sua string for algo como: 'data: image / png; base64, ... base 64 stuff ....' então você precisa remover o primeiro parte antes de decodificá-lo.
Digamos que você tenha uma string codificada em base64 de imagem e tente o snippet abaixo.
fonte
Basta adicionar caracteres adicionais como "=" ou qualquer outro e torná-lo um múltiplo de 4 antes de tentar decodificar o valor da string de destino. Algo como;
fonte
Caso este erro venha de um servidor web: tente codificar url seu valor post. Eu estava fazendo um POST via "curl" e descobri que não estava codificando com url meu valor base64, então caracteres como "+" não eram escapados, de modo que a lógica de decodificação de url do servidor web executava decodificação de url automaticamente e convertia + em espaços.
"+" é um caractere base64 válido e talvez o único caractere que é mutilado por uma decodificação de url inesperada.
fonte
No meu caso, encontrei esse erro ao analisar um e-mail. Peguei o anexo como string base64 e extraí-o por meio de re.search. Eventualmente, havia uma substring adicional estranha no final.
Quando eu apaguei
--_=ic0008m4wtZ4TqBFd+sXC8--
e retirei a string, a análise foi corrigida.Portanto, meu conselho é ter certeza de que você está decodificando uma string base64 correta.
fonte
Você deveria usar
Por padrão, os altchars são
'+/'
.fonte
Também encontrei este problema e nada funcionou. Finalmente consegui encontrar a solução que funciona para mim. Eu havia compactado o conteúdo em base64 e isso aconteceu com 1 em um milhão de registros ...
Esta é uma versão da solução sugerida por Simon Sapin.
Caso falte 3 caracteres no preenchimento, removo os 3 últimos caracteres.
Em vez de "0gA1RD5L / 9AUGtH9MzAwAAA =="
Obtemos "0gA1RD5L / 9AUGtH9MzAwAA"
De acordo com esta resposta, Trailing As em base64 o motivo são nulos. Mas ainda não tenho ideia de por que o codificador bagunçou isso ...
fonte