The binascii module provides low-level functions for converting between binary data and ASCII representations. It's the engine behind higher-level modules like base64.
What binascii Does
binascii handles conversions that are common in network protocols and file formats:
- Binary to hexadecimal (and back)
- Binary to base64 (and back)
- CRC checksums
It works at the byte level, giving you precise control over encoding.
hexlify and unhexlify
Convert bytes to hex strings and back:
import binascii
# Binary to hex
data = b'Hello'
hex_data = binascii.hexlify(data)
print(hex_data) # b'48656c6c6f'
# Hex to binary
original = binascii.unhexlify(hex_data)
print(original) # b'Hello'With a separator (Python 3.8+):
import binascii
data = b'\xde\xad\xbe\xef'
hex_sep = binascii.hexlify(data, sep=':')
print(hex_sep) # b'de:ad:be:ef'
# Or use a different separator
hex_space = binascii.hexlify(data, sep=' ', bytes_per_sep=2)
print(hex_space) # b'dead beef'b2a_base64 and a2b_base64
Base64 encoding at the byte level:
import binascii
# Binary to base64
data = b'Hello, World!'
b64 = binascii.b2a_base64(data)
print(b64) # b'SGVsbG8sIFdvcmxkIQ==\n'
# Note the newline - remove it if needed
b64_clean = binascii.b2a_base64(data, newline=False)
print(b64_clean) # b'SGVsbG8sIFdvcmxkIQ=='
# Base64 to binary
original = binascii.a2b_base64(b64)
print(original) # b'Hello, World!'crc32: Checksums
Calculate CRC32 checksums for data integrity:
import binascii
data = b'Hello, World!'
checksum = binascii.crc32(data)
print(f"CRC32: {checksum}") # CRC32: 3964322768
print(f"Hex: {checksum:08x}") # Hex: ec4ac3d0Incremental CRC for large data:
import binascii
def crc32_file(filepath):
"""Calculate CRC32 of a file in chunks."""
crc = 0
with open(filepath, 'rb') as f:
while chunk := f.read(8192):
crc = binascii.crc32(chunk, crc)
return crc & 0xffffffff # Ensure unsigned
# Verify file integrity
crc = crc32_file('data.bin')
print(f"File CRC32: {crc:08x}")Practical Examples
Debugging Binary Data
import binascii
def hexdump(data, width=16):
"""Create a hex dump of binary data."""
lines = []
for i in range(0, len(data), width):
chunk = data[i:i+width]
hex_part = binascii.hexlify(chunk, sep=' ').decode()
ascii_part = ''.join(
chr(b) if 32 <= b < 127 else '.'
for b in chunk
)
lines.append(f"{i:08x} {hex_part:<{width*3}} {ascii_part}")
return '\n'.join(lines)
data = b'Hello, World!\x00\x01\x02Binary data'
print(hexdump(data))
# 00000000 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 00 01 02 Hello, World!...
# 00000010 42 69 6e 61 72 79 20 64 61 74 61 Binary dataValidating Hex Input
import binascii
def parse_hex(hex_string):
"""Parse hex string, handling various formats."""
# Remove common separators
cleaned = hex_string.replace(':', '').replace(' ', '').replace('-', '')
try:
return binascii.unhexlify(cleaned)
except binascii.Error as e:
raise ValueError(f"Invalid hex string: {e}")
# All these work
print(parse_hex('deadbeef')) # b'\xde\xad\xbe\xef'
print(parse_hex('de:ad:be:ef')) # b'\xde\xad\xbe\xef'
print(parse_hex('de ad be ef')) # b'\xde\xad\xbe\xef'
print(parse_hex('DE-AD-BE-EF')) # b'\xde\xad\xbe\xef'Simple Data Integrity Check
import binascii
def add_checksum(data):
"""Append CRC32 checksum to data."""
crc = binascii.crc32(data) & 0xffffffff
return data + crc.to_bytes(4, 'big')
def verify_checksum(data_with_crc):
"""Verify and extract data."""
data = data_with_crc[:-4]
stored_crc = int.from_bytes(data_with_crc[-4:], 'big')
computed_crc = binascii.crc32(data) & 0xffffffff
if stored_crc != computed_crc:
raise ValueError("Checksum mismatch - data corrupted")
return data
# Usage
original = b'Important data'
with_crc = add_checksum(original)
verified = verify_checksum(with_crc)
print(verified) # b'Important data'MAC Address Formatting
import binascii
def format_mac(mac_bytes):
"""Format 6-byte MAC address."""
return binascii.hexlify(mac_bytes, sep=':').decode().upper()
def parse_mac(mac_string):
"""Parse MAC address string to bytes."""
cleaned = mac_string.replace(':', '').replace('-', '')
return binascii.unhexlify(cleaned)
mac = b'\x00\x1a\x2b\x3c\x4d\x5e'
print(format_mac(mac)) # 00:1A:2B:3C:4D:5E
parsed = parse_mac('00:1A:2B:3C:4D:5E')
print(parsed) # b'\x00\x1a+<M^'binascii vs base64 Module
When to use binascii:
- You need low-level byte control
- Working with legacy protocols requiring specific formatting
- You want the newline parameter for base64
- Calculating CRC32 checksums
When to use base64:
- URL-safe encoding (
urlsafe_b64encode) - Base32, Base16, ASCII85 encoding
- Higher-level, more readable API
- Working with strings (automatic encoding handling)
import binascii
import base64
data = b'test'
# binascii - byte-level, includes newline by default
print(binascii.b2a_base64(data)) # b'dGVzdA==\n'
# base64 - cleaner API, no newline
print(base64.b64encode(data)) # b'dGVzdA=='
# base64 has URL-safe variant
print(base64.urlsafe_b64encode(b'\xfb\xff')) # b'--8='
# binascii doesn'tError Handling
import binascii
# Invalid hex length
try:
binascii.unhexlify('abc') # Odd length
except binascii.Error as e:
print(f"Error: {e}") # Odd-length string
# Invalid hex characters
try:
binascii.unhexlify('xyz')
except binascii.Error as e:
print(f"Error: {e}") # Non-hexadecimal digit
# Invalid base64
try:
binascii.a2b_base64('not valid base64!!!')
except binascii.Error as e:
print(f"Error: {e}") # Invalid base64Quick Reference
| Function | Purpose |
|---|---|
hexlify(data) | Bytes → hex string |
unhexlify(hex) | Hex string → bytes |
b2a_base64(data) | Bytes → base64 |
a2b_base64(b64) | Base64 → bytes |
crc32(data) | Calculate CRC32 checksum |
binascii is a workhorse module. It's not glamorous, but when you need precise control over binary-to-text conversions or quick checksums, it's exactly what you need.