Tengo algunos datos codificados en base64 que quiero convertir de nuevo a binario incluso si hay un error de relleno en ellos. Si uso
base64.decodestring(b64_string)
genera un error de "relleno incorrecto". ¿Hay otra manera?
ACTUALIZACIÓN: Gracias por todos los comentarios. Para ser honesto, todos los métodos mencionados sonaban un poco impredecibles, así que decidí probar openssl. El siguiente comando funcionó de maravilla:
openssl enc -d -base64 -in b64string -out binary_data
base64.b64decode(strg, '-_')
? Eso es a priori, sin que se moleste en proporcionar ningún dato de muestra, la solución Python más probable para su problema. Los "métodos" propuestos fueron sugerencias DEBUG, NECESARIAMENTE "acertadas" dada la escasez de información suministrada.base64.urlsafe_b64decode(s)
sorted(list(set(b64_string)))
por favor? Sin revelar nada confidencial de la empresa, eso debería revelar qué caracteres se utilizaron para codificar los datos originales, que a su vez pueden proporcionar suficiente información para proporcionar una solución que no sea acertada o fallida.Respuestas:
Como se dijo en otras respuestas, hay varias formas en las que los datos base64 podrían corromperse.
Sin embargo, como dice Wikipedia , eliminar el relleno (los caracteres '=' al final de los datos codificados en base64) es "sin pérdidas":
Entonces, si esto es realmente lo único "incorrecto" con sus datos base64, el relleno se puede volver a agregar. Se me ocurrió esto para poder analizar las URL de "datos" en WeasyPrint, algunas de las cuales eran base64 sin relleno:
Pruebas para esta función: weasyprint / tests / test_css.py # L68
fuente
str(data)
base64.decodestring
se ha desaprobadobase64.decodebytes
en Py3, pero es mejor usarlo por compatibilidad de versionesbase64.b64decode
.base64
módulo ignora los caracteres no válidos que no son base64 en la entrada, primero debe normalizar los datos. Quite todo lo que no sea una letra, un dígito/
o+
y luego agregue el relleno.Simplemente agregue relleno según sea necesario. Sin embargo, preste atención a la advertencia de Michael.
fuente
===
siempre funciona.=
Python descarta aparentemente cualquier carácter adicional de forma segura.Parece que solo necesita agregar relleno a sus bytes antes de decodificar. Hay muchas otras respuestas a esta pregunta, pero quiero señalar que (al menos en Python 3.x)
base64.b64decode
truncará cualquier relleno adicional, siempre que haya suficiente en primer lugar.Entonces, algo como:
b'abc='
funciona tan bien comob'abc=='
(como lo haceb'abc====='
).Lo que esto significa es que puede agregar el número máximo de caracteres de relleno que necesitaría, que es tres (
b'==='
), y base64 truncará los que no sean necesarios.Esto te permite escribir:
que es más simple que:
fuente
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4
. ¡Gracias por señalar esto!"Relleno incorrecto" puede significar no sólo "relleno faltante" sino también (lo crea o no) "relleno incorrecto".
Si los métodos sugeridos de "agregar relleno" no funcionan, intente eliminar algunos bytes finales:
Actualización: Cualquier manipulación para agregar relleno o eliminar posibles bytes incorrectos del final debe hacerse DESPUÉS de eliminar cualquier espacio en blanco, de lo contrario, los cálculos de longitud se alterarán.
Sería una buena idea que nos mostrara una muestra (breve) de los datos que necesita recuperar. Edite su pregunta y copie / pegue el resultado de
print repr(sample)
.Actualización 2: Es posible que la codificación se haya realizado de manera segura para URL. Si este es el caso, podrá ver los caracteres menos y subrayados en sus datos, y debería poder decodificarlos usando
base64.b64decode(strg, '-_')
Si no puede ver los caracteres de menos y subrayado en sus datos, pero puede ver los caracteres de más y barra, entonces tiene algún otro problema y puede necesitar los trucos de agregar relleno o eliminar cruft.
Si no ve nada de menos, subrayado, más ni barra en sus datos, entonces necesita determinar los dos caracteres alternativos; serán los que no estén en [A-Za-z0-9]. Luego, deberá experimentar para ver qué orden deben usarse en el segundo argumento de
base64.b64decode()
Actualización 3 : si sus datos son "confidenciales de la empresa":
(a) debe decirlo desde el principio
(b) podemos explorar otras vías para comprender el problema, que es muy probable que esté relacionado con los caracteres que se utilizan en lugar de
+
y/
en el alfabeto de codificación, o por otro formato o caracteres extraños.Una de esas vías sería examinar qué caracteres no "estándar" hay en sus datos, p. Ej.
fuente
Utilizar
El crédito va a un comentario en algún lugar aquí.
fuente
Si hay un error de relleno, probablemente significa que su cadena está dañada; Las cadenas codificadas en base64 deben tener un múltiplo de cuatro de longitud. Puede intentar agregar el carácter de relleno (
=
) usted mismo para hacer que la cadena sea un múltiplo de cuatro, pero ya debería tener eso a menos que algo esté malfuente
Consulte la documentación de la fuente de datos que está intentando decodificar. ¿Es posible que tuvieras que usar en
base64.urlsafe_b64decode(s)
lugar debase64.b64decode(s)
? Esa es una de las razones por las que puede haber visto este mensaje de error.Este es, por ejemplo, el caso de varias API de Google, como el kit de herramientas de identidad de Google y las cargas útiles de Gmail.
fuente
urlsafe_b64decode
también requiere relleno.base64.urlsafe_b64decode
.Agregar el relleno es bastante ... complicado. Aquí está la función que escribí con la ayuda de los comentarios en este hilo, así como la página wiki para base64 (es sorprendentemente útil) https://en.wikipedia.org/wiki/Base64#Padding .
fuente
Puede usarlo simplemente
base64.urlsafe_b64decode(data)
si está intentando decodificar una imagen web. Se encargará automáticamente del acolchado.fuente
Hay dos formas de corregir los datos de entrada descritos aquí, o, más específicamente y en línea con el OP, hacer que el método b64decode del módulo Python base64 sea capaz de procesar los datos de entrada en algo sin generar una excepción no detectada:
Si eso genera una excepción, entonces
yo. Cógelo a través de try / except,
ii. (R?) Quite cualquier = carácter de los datos de entrada (NB, esto puede no ser necesario),
iii. Agregue A == a los datos de entrada (A == a P == funcionará),
iv. Llame a base64.b64decode (...) con esos A == - datos de entrada adjuntos
El resultado del elemento 1. o del elemento 2. anterior producirá el resultado deseado.
Advertencias
Esto no garantiza que el resultado decodificado sea el que se codificó originalmente, pero (¿a veces?) Le dará al OP lo suficiente para trabajar:
Vea lo que sabemos y las suposiciones a continuación.
TL; DR
De algunas pruebas rápidas de base64.b64decode (...)
parece que ignora los caracteres que no son [A-Za-z0-9 + /]; que incluye ignorar = s a menos que sean los últimos caracteres en un grupo analizado de cuatro, en cuyo caso = s terminan la decodificación (a = b = c = d = da el mismo resultado que abc =, y a = = b == c == da el mismo resultado que ab ==).
También parece que todos los caracteres añadidos se ignoran después del punto en el que base64.b64decode (...) termina la decodificación, por ejemplo, de an = como el cuarto de un grupo.
Como se señaló en varios comentarios anteriores, hay cero, uno o dos, = s de relleno requeridos al final de los datos de entrada para cuando el valor de [número de caracteres analizados hasta ese punto módulo 4] es 0 o 3, o 2, respectivamente. Por lo tanto, de los elementos 3. y 4. anteriores, agregar dos o más = s a los datos de entrada corregirá cualquier problema de [relleno incorrecto] en esos casos.
SIN EMBARGO, la decodificación no puede manejar el caso donde el [número total de caracteres analizados módulo 4] es 1, porque se necesitan al menos dos caracteres codificados para representar el primer byte decodificado en un grupo de tres bytes decodificados. En datos de entrada codificados no corruptos, este caso [N módulo 4] = 1 nunca ocurre, pero como el OP indicó que pueden faltar caracteres, podría suceder aquí. Es por eso que simplemente agregar = s no siempre funcionará, y por qué agregar A == funcionará cuando agregar == no. NB El uso de [A] es casi arbitrario: agrega solo bits borrados (cero) al decodificado, lo que puede ser correcto o no, pero entonces el objeto aquí no es la corrección sino la finalización por base64.b64decode (...) sin excepciones .
Lo que sabemos del OP y especialmente de los comentarios posteriores es
openssl enc ...
funciona.Supuestos
Github
Aquí hay un contenedor para implementar esta solución:
https://github.com/drbitboy/missing_b64
fuente
El error de relleno incorrecto se debe a que, a veces, los metadatos también están presentes en la cadena codificada.Si su cadena se parece a: 'data: image / png; base64, ... base 64 cosas ...', entonces debe eliminar la primera parte antes de decodificarlo.
Digamos que si tiene una cadena codificada en base64 de imagen, intente el siguiente fragmento.
fuente
Simplemente agregue caracteres adicionales como "=" o cualquier otro y conviértalo en múltiplo de 4 antes de intentar decodificar el valor de la cadena de destino. Algo como;
fuente
En caso de que este error provenga de un servidor web: intente codificar la URL de su valor de publicación. Estaba publicando a través de "curl" y descubrí que no estaba codificando url mi valor base64 por lo que los caracteres como "+" no se escaparon, por lo que la lógica de decodificación de URL del servidor web ejecutó automáticamente la decodificación de URL y convirtió + en espacios.
"+" es un carácter base64 válido y quizás el único carácter que se estropea por una decodificación de URL inesperada.
fuente
En mi caso, me enfrenté a ese error al analizar un correo electrónico. Obtuve el archivo adjunto como cadena base64 y lo extraje a través de re.search. Finalmente, hubo una extraña subcadena adicional al final.
Cuando eliminé
--_=ic0008m4wtZ4TqBFd+sXC8--
y eliminé la cadena, se solucionó el análisis.Entonces, mi consejo es asegurarse de que está decodificando una cadena base64 correcta.
fuente
Deberías usar
Por defecto, las altchars son
'+/'
.fuente
Me encontré con este problema también y nada funcionó. Finalmente logré encontrar la solución que funciona para mí. Tenía contenido comprimido en base64 y esto le sucedió a 1 de cada millón de registros ...
Esta es una versión de la solución sugerida por Simon Sapin.
En caso de que falten 3 en el relleno, elimino los últimos 3 caracteres.
En lugar de "0gA1RD5L / 9AUGtH9MzAwAAA =="
Obtenemos "0gA1RD5L / 9AUGtH9MzAwAA"
De acuerdo con esta respuesta Trailing As en base64, la razón es nula. Pero todavía no tengo idea de por qué el codificador estropea esto ...
fuente