El módulo binascii de Python reúne operaciones rápidas y de bajo nivel para convertir bytes a representaciones ASCII como hexadecimal, Base64, quoted-printable y uuencode. También incluye cálculos CRC utilizados para detectar cambios accidentales en archivos y mensajes de protocolos. Aunque la mayoría de las aplicaciones usan módulos de nivel superior, conocer binascii permite controlar mejor la validación, los errores, los buffers y los formatos binarios.
En esta guía aprenderás cuándo usar el módulo, cómo separar texto y bytes, cómo validar Base64 de forma estricta, cómo inspeccionar valores binarios en hexadecimal y por qué un CRC no equivale a un hash criptográfico. Todos los ejemplos utilizan la biblioteca estándar y son útiles en diagnósticos, procesamiento de archivos, protocolos de red e integraciones.
Qué es binascii
El nombre significa “binary to ASCII”. El módulo contiene primitivas implementadas en C para transformar datos binarios en codificaciones imprimibles y realizar la conversión inversa. Módulos de nivel superior como base64 y quopri usan estas funciones internamente.
Para código cotidiano conviene preferir las APIs superiores porque expresan mejor el estándar correspondiente. Usa binascii cuando necesites decodificación estricta, acceso directo a CRC, captura específica de excepciones o trabajo eficiente con objetos que implementan el protocolo de buffer.
Es fundamental distinguir str de bytes. Una cadena representa texto Unicode, mientras que los bytes representan octetos. Pasar de uno a otro requiere un encoding explícito, normalmente UTF-8. Puedes reforzar estos conceptos con la guía de estructuras y listas en Python y el artículo sobre slicing en Python.
Hexadecimal con hexlify y unhexlify
El formato hexadecimal resulta útil para depurar protocolos, mostrar identificadores binarios, revisar hashes y registrar campos técnicos. Cada byte produce dos dígitos hexadecimales, por lo que la salida ocupa el doble que la entrada.
import binascii
data = b"Python\x00\xff"
hex_data = binascii.hexlify(data)
print(hex_data) # b'507974686f6e00ff'
print(binascii.unhexlify(hex_data))
b2a_hex() es un alias de hexlify(), y a2b_hex() es un alias de unhexlify(). Los nombres largos suelen ser más fáciles de entender durante una revisión de código.
También puedes insertar separadores:
direccion = b"\xaa\xbb\xcc\xdd\xee\xff"
print(binascii.hexlify(direccion, sep=b":"))
# b'aa:bb:cc:dd:ee:ff'
El método bytes.hex() devuelve texto y bytes.fromhex() tolera espacios entre grupos. unhexlify() es más estricto: exige un número par de dígitos válidos. Esa rigidez es útil cuando un campo de protocolo debe cumplir una gramática exacta.
try:
valor = binascii.unhexlify("abc")
except binascii.Error as error:
print(f"Hexadecimal inválido: {error}")
Conversión Base64 de bajo nivel
b2a_base64() codifica bytes en Base64. Por defecto añade un salto de línea final, siguiendo formatos tradicionales orientados por líneas. Usa newline=False para JSON, bases de datos, logs compactos o valores HTTP.
payload = b"datos binarios\x00\x01"
encoded = binascii.b2a_base64(payload, newline=False)
decoded = binascii.a2b_base64(encoded)
assert decoded == payload
print(encoded)
Base64 no cifra los datos. Cualquier persona que reciba el valor puede recuperar los bytes originales. Su objetivo es transportar binario por sistemas textuales. La guía de Base64 en Python explica además Base64 URL-safe, Base32 y Base85.
Validación estricta de Base64
La decodificación tolerante puede descartar caracteres ajenos al alfabeto. Eso es práctico en MIME con saltos de línea, pero puede ocultar una entrada malformada en una API. Desde Python 3.11, a2b_base64() admite strict_mode=True.
def decode_base64_strict(value: str) -> bytes:
try:
return binascii.a2b_base64(value, strict_mode=True)
except binascii.Error as error:
raise ValueError("Base64 inválido") from error
print(decode_base64_strict("UHl0aG9u"))
El modo estricto rechaza caracteres externos, padding inicial, padding excesivo y datos después del padding. Aun así, debes limitar el tamaño antes de decodificar. Una entrada controlada por un atacante puede consumir memoria y CPU sin necesidad.
Quoted-printable
Quoted-printable conserva legible gran parte del texto ASCII y representa otros bytes con secuencias como =C3=B1. Es común en cuerpos de correo MIME y algunas integraciones antiguas.
texto = "acción e información".encode("utf-8")
encoded = binascii.b2a_qp(texto)
decoded = binascii.a2b_qp(encoded)
print(encoded)
print(decoded.decode("utf-8"))
Las opciones header, quotetabs e istext modifican el tratamiento de espacios, tabulaciones y saltos de línea. Para correos completos usa el paquete email, que comprende cabeceras, límites MIME y políticas. Utiliza binascii cuando ya conoces exactamente el formato del campo.
CRC-32 para detectar corrupción accidental
crc32() calcula un checksum de 32 bits compatible con el utilizado en ZIP. Puede detectar alteraciones accidentales durante almacenamiento, copia o transmisión.
from pathlib import Path
import binascii
def crc32_file(path: Path, chunk_size: int = 64 * 1024) -> int:
crc = 0
with path.open("rb") as file:
while chunk := file.read(chunk_size):
crc = binascii.crc32(chunk, crc)
return crc
result = crc32_file(Path("datos.bin"))
print(f"{result:08x}")
Procesar por bloques evita cargar un archivo grande completo en memoria. Es el mismo patrón explicado en la guía para leer archivos gigantes con Python.
CRC no sirve para contraseñas, firmas de API, tokens o protección frente a manipulación intencional. Un atacante puede cambiar el contenido y recalcular el CRC. Usa hashlib para resúmenes criptográficos y HMAC para mensajes autenticados. Las contraseñas requieren algoritmos especializados; consulta el artículo sobre hash seguro de contraseñas.
CRC-HQX en protocolos heredados
crc_hqx() implementa CRC-CCITT de 16 bits y aparece en dispositivos y formatos antiguos. El valor inicial debe coincidir con la especificación:
data = b"mensaje"
crc = binascii.crc_hqx(data, 0xffff)
print(f"{crc:04x}")
No elijas el valor inicial por intuición. Dos sistemas con el mismo polinomio pueden diferir en inicialización, reflexión de bits, orden de bytes y XOR final.
Buffers y menos copias
Las funciones aceptan objetos bytes-like, incluidos bytes, bytearray y objetos que exponen el protocolo de buffer. Un memoryview permite seleccionar una parte sin construir primero otro objeto de bytes.
buffer = bytearray(b"ABCDEF")
view = memoryview(buffer)[1:5]
print(binascii.hexlify(view)) # b'42434445'
En procesamiento incremental, un bloque puede terminar en medio de una unidad codificada. Algunas operaciones pueden lanzar binascii.Incomplete. Conserva los bytes sobrantes y añádelos al siguiente bloque en lugar de considerar toda entrada incompleta como corrupción permanente.
Manejo seguro de errores
Las entradas externas deben tratarse como no confiables. Valida tamaño y tipo antes de convertir, elige el decodificador que corresponde al formato esperado y transforma las excepciones internas en errores claros de la aplicación.
def parse_hex_field(value: str, max_chars: int = 128) -> bytes:
if len(value) > max_chars:
raise ValueError("Campo hexadecimal demasiado grande")
if len(value) % 2:
raise ValueError("Campo hexadecimal con longitud impar")
try:
return binascii.unhexlify(value)
except (binascii.Error, ValueError) as error:
raise ValueError("Campo hexadecimal inválido") from error
Evita registrar tokens, credenciales o payloads completos. Registra la operación, la longitud, la clase de error y un identificador de correlación. Así puedes diagnosticar el problema sin exponer información sensible.
Cuándo usar módulos de nivel superior
Usa base64 para Base16, Base32, Base64, Base85 y variantes URL-safe. Usa quopri o email para MIME. Usa bytes.hex() si solo necesitas una cadena sencilla. Elige binascii para primitivas de bajo nivel, CRC, validación estricta o integración eficiente con buffers.
Buenas prácticas
Documenta si una función recibe texto o bytes. Aplica límites antes de decodificar. Usa validación estricta en campos Base64 canónicos. Nunca trates un CRC como mecanismo de seguridad. Procesa archivos por bloques y captura binascii.Error en la frontera de entrada, conservando la excepción original como causa.
Conclusión
binascii es un módulo pequeño y rápido para los detalles de la conversión binaria. Sus utilidades hexadecimales, el modo Base64 estricto, quoted-printable y los CRC resultan útiles cuando una API superior no ofrece suficiente control. La clave consiste en elegir la abstracción correcta y validar explícitamente todo dato externo.
Consulta la documentación oficial de binascii y el RFC 4648 para las definiciones formales de Base16, Base32 y Base64.







