Python’s binascii module converts between binary data and various ASCII text encodings. import binascii. hexlify: binascii.hexlify(data) → bytes of hex digits; binascii.hexlify(b'\xde\xad', sep=':', bytes_per_sep=1) → b'de:ad' (Python 3.8+). unhexlify: binascii.unhexlify("deadbeef") → bytes; accepts str or bytes. b2a_hex / a2b_hex: aliases for hexlify / unhexlify. b2a_base64: binascii.b2a_base64(data) → base64-encoded bytes with a trailing newline; pass newline=False (Python 3.6+) to suppress. a2b_base64: binascii.a2b_base64(data) → decoded bytes; ignores whitespace. crc32: binascii.crc32(data) → signed int; binascii.crc32(data, value) to chain. crc_hqx: BinHex CRC-CCITT checksum. b2a_qp: binascii.b2a_qp(data) → quoted-printable bytes. a2b_qp: decode quoted-printable. Error: binascii.Error — raised on bad encoding. Incomplete: binascii.Incomplete — raised when data is incomplete but valid so far. Note: for most Base64 work prefer the base64 module (which wraps binascii); use binascii directly for hex conversion, checksums, and low-level binary protocol work. Claude Code generates binary protocol parsers, hex dump utilities, checksum verifiers, and network packet inspectors.
CLAUDE.md for binascii
## binascii Stack
- Stdlib: import binascii
- Hex: binascii.hexlify(data).decode() # bytes → hex str
- binascii.unhexlify("deadbeef") # hex str → bytes
- B64: binascii.b2a_base64(data, newline=False)
- binascii.a2b_base64(encoded)
- CRC: binascii.crc32(data) & 0xFFFFFFFF # unsigned 32-bit
- Sep: binascii.hexlify(mac, sep=':', bytes_per_sep=1)
binascii Binary Encoding Pipeline
# app/binautil.py — hex, base64, checksums, hex dump, protocol helpers
from __future__ import annotations
import binascii
import struct
from dataclasses import dataclass
from typing import Iterable
# ─────────────────────────────────────────────────────────────────────────────
# 1. Hex encoding/decoding helpers
# ─────────────────────────────────────────────────────────────────────────────
def to_hex(data: bytes, sep: str = "", bytes_per_sep: int = 1) -> str:
"""
Encode bytes to lowercase hex string.
Example:
to_hex(b'\\xde\\xad\\xbe\\xef') # "deadbeef"
to_hex(b'\\xde\\xad\\xbe\\xef', sep=':') # "de:ad:be:ef"
to_hex(b'\\x08\\x00', sep=' ', bytes_per_sep=2) # "0800"
"""
if sep:
raw = binascii.hexlify(data, sep.encode(), bytes_per_sep)
else:
raw = binascii.hexlify(data)
return raw.decode("ascii")
def from_hex(hex_str: str) -> bytes:
"""
Decode a hex string to bytes (whitespace, colons, and dashes are stripped).
Example:
from_hex("de:ad:be:ef") # b'\\xde\\xad\\xbe\\xef'
from_hex("DE AD BE EF") # b'\\xde\\xad\\xbe\\xef'
"""
clean = hex_str.replace(":", "").replace("-", "").replace(" ", "").strip()
return binascii.unhexlify(clean)
def hex_to_int(hex_str: str, big_endian: bool = True) -> int:
"""
Convert a hex string to an integer.
Example:
hex_to_int("deadbeef") # 3735928559
hex_to_int("efbeadde", False) # 3735928559 (little-endian)
"""
data = from_hex(hex_str)
if not big_endian:
data = data[::-1]
return int.from_bytes(data, "big")
def int_to_hex(n: int, width_bytes: int = 4, big_endian: bool = True) -> str:
"""
Convert an integer to a fixed-width hex string.
Example:
int_to_hex(255, 2) # "00ff"
int_to_hex(255, 2, False) # "ff00"
"""
order = "big" if big_endian else "little"
return to_hex(n.to_bytes(width_bytes, order))
def safe_unhex(hex_str: str) -> bytes | None:
"""
Decode hex string; return None on invalid input rather than raising.
Example:
safe_unhex("deadbeef") # b'\\xde\\xad\\xbe\\xef'
safe_unhex("nothex!!") # None
"""
try:
return from_hex(hex_str)
except (binascii.Error, ValueError):
return None
# ─────────────────────────────────────────────────────────────────────────────
# 2. Base64 helpers (via binascii)
# ─────────────────────────────────────────────────────────────────────────────
def to_b64(data: bytes) -> str:
"""
Encode bytes to base64 string (no newline).
Example:
to_b64(b"hello") # "aGVsbG8="
"""
return binascii.b2a_base64(data, newline=False).decode("ascii")
def from_b64(encoded: str | bytes) -> bytes:
"""
Decode a base64 string to bytes (tolerates whitespace).
Example:
from_b64("aGVsbG8=") # b"hello"
"""
return binascii.a2b_base64(encoded)
def b64_chunks(data: bytes, chunk_size: int = 57) -> list[str]:
"""
Encode data as a list of base64 lines (57 bytes → 76 chars per line per RFC 2045).
Example:
lines = b64_chunks(large_data)
email_body = "\\n".join(lines)
"""
lines = []
for i in range(0, len(data), chunk_size):
chunk = data[i : i + chunk_size]
line = binascii.b2a_base64(chunk).decode("ascii").rstrip("\\n")
lines.append(line)
return lines
# ─────────────────────────────────────────────────────────────────────────────
# 3. Checksum utilities
# ─────────────────────────────────────────────────────────────────────────────
def crc32(data: bytes) -> int:
"""
Return the unsigned 32-bit CRC-32 checksum of data.
Example:
crc32(b"hello") # 907060870
"""
return binascii.crc32(data) & 0xFFFFFFFF
def crc32_stream(chunks: Iterable[bytes]) -> int:
"""
Compute CRC-32 incrementally over an iterable of byte chunks.
Example:
with open("file.bin", "rb") as f:
checksum = crc32_stream(iter(lambda: f.read(8192), b""))
"""
value = 0
for chunk in chunks:
value = binascii.crc32(chunk, value)
return value & 0xFFFFFFFF
def crc32_file(path: str) -> int:
"""
Compute CRC-32 of a file by streaming its content.
Example:
checksum = crc32_file("/data/archive.zip")
"""
import pathlib
with open(path, "rb") as f:
return crc32_stream(iter(lambda: f.read(65536), b""))
def verify_crc32(data: bytes, expected: int) -> bool:
"""
Return True if CRC-32 of data matches expected (unsigned 32-bit int).
Example:
verify_crc32(frame_payload, header_checksum)
"""
return crc32(data) == (expected & 0xFFFFFFFF)
# ─────────────────────────────────────────────────────────────────────────────
# 4. Hex dump
# ─────────────────────────────────────────────────────────────────────────────
def hexdump(data: bytes, width: int = 16, offset: int = 0) -> str:
"""
Return a classic hex dump string with offset, hex bytes, and ASCII preview.
Example:
print(hexdump(b"Hello, World! 12345"))
# 00000000 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 20 31 32 |Hello, World! 12|
# 00000010 33 34 35 |345 |
"""
lines = []
for i in range(0, len(data), width):
chunk = data[i : i + width]
hex_part = " ".join(f"{b:02x}" for b in chunk)
# Split into two groups for readability
left = " ".join(f"{b:02x}" for b in chunk[:width//2])
right = " ".join(f"{b:02x}" for b in chunk[width//2:])
hex_cols = f"{left:<{width//2*3-1}} {right:<{width//2*3-1}}"
ascii_part = "".join(chr(b) if 32 <= b < 127 else "." for b in chunk)
lines.append(f"{offset + i:08x} {hex_cols} |{ascii_part:<{width}}|")
return "\n".join(lines)
def diff_hexdump(a: bytes, b: bytes, width: int = 16) -> str:
"""
Return a hex dump showing which bytes differ between a and b.
Differing positions are marked with '!!' in the hex output.
Example:
print(diff_hexdump(b"Hello, World!", b"Hello, Peter!"))
"""
lines = []
max_len = max(len(a), len(b))
a_pad = a.ljust(max_len, b"\\x00")
b_pad = b.ljust(max_len, b"\\x00")
for i in range(0, max_len, width):
chunk_a = a_pad[i : i + width]
chunk_b = b_pad[i : i + width]
hex_a = " ".join(f"!{ba:02x}" if ba != bb else f"{ba:02x}" for ba, bb in zip(chunk_a, chunk_b))
ascii_a = "".join(chr(c) if 32 <= c < 127 else "." for c in chunk_a)
ascii_b = "".join(chr(c) if 32 <= c < 127 else "." for c in chunk_b)
lines.append(f"{i:08x} {hex_a}")
if ascii_a != ascii_b:
lines.append(f" A: |{ascii_a}|")
lines.append(f" B: |{ascii_b}|")
return "\n".join(lines)
# ─────────────────────────────────────────────────────────────────────────────
# 5. Binary protocol frame helpers
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class Frame:
"""
Simple binary frame: [4-byte length][payload][4-byte CRC32]
Example:
frame = Frame.encode(b"hello world")
payload, ok = Frame.decode(frame)
assert ok and payload == b"hello world"
"""
HEADER = struct.Struct(">I") # 4-byte big-endian unsigned int
TRAILER = struct.Struct(">I") # 4-byte CRC
@classmethod
def encode(cls, payload: bytes) -> bytes:
header = cls.HEADER.pack(len(payload))
checksum = cls.TRAILER.pack(crc32(payload))
return header + payload + checksum
@classmethod
def decode(cls, data: bytes) -> tuple[bytes, bool]:
"""Return (payload, crc_ok). Returns (b'', False) on malformed input."""
hdr_size = cls.HEADER.size
tlr_size = cls.TRAILER.size
if len(data) < hdr_size + tlr_size:
return b"", False
(length,) = cls.HEADER.unpack(data[:hdr_size])
if len(data) < hdr_size + length + tlr_size:
return b"", False
payload = data[hdr_size : hdr_size + length]
(expected_crc,) = cls.TRAILER.unpack(data[hdr_size + length : hdr_size + length + tlr_size])
return payload, verify_crc32(payload, expected_crc)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== binascii demo ===")
print("\n--- hex encoding ---")
data = bytes(range(16))
print(f" to_hex(bytes 0-15) : {to_hex(data)}")
print(f" to_hex with sep ':' : {to_hex(data, sep=':', bytes_per_sep=1)}")
print(f" from_hex round-trip : {from_hex(to_hex(data)) == data}")
print(f" hex_to_int('deadbeef'): {hex_to_int('deadbeef')}")
print(f" int_to_hex(255, 2) : {int_to_hex(255, 2)}")
print("\n--- base64 ---")
msg = b"Hello, binary world!"
enc = to_b64(msg)
print(f" to_b64({msg}) : {enc}")
print(f" from_b64 round-trip : {from_b64(enc) == msg}")
chunks = b64_chunks(b"A" * 200)
print(f" b64_chunks({200} bytes): {len(chunks)} lines, first={chunks[0][:20]!r}...")
print("\n--- CRC-32 ---")
payload = b"test payload"
cs = crc32(payload)
print(f" crc32(b'test payload') = {cs:#010x}")
print(f" verify_crc32: {verify_crc32(payload, cs)}")
print(f" verify_crc32 (tampered): {verify_crc32(b'tampered!', cs)}")
print("\n--- hexdump ---")
print(hexdump(b"Hello, World! 1234567890abcdef"))
print("\n--- Frame encode/decode ---")
frame = Frame.encode(b"sensor data: 42.5C")
print(f" frame length: {len(frame)} bytes hex: {to_hex(frame, sep=' ', bytes_per_sep=1)[:40]}...")
payload, ok = Frame.decode(frame)
print(f" decoded: {payload} CRC ok: {ok}")
# Tamper with one byte
tampered = bytearray(frame)
tampered[8] ^= 0xFF
_, ok_tampered = Frame.decode(bytes(tampered))
print(f" tampered CRC ok: {ok_tampered}")
print("\n--- safe_unhex ---")
print(f" safe_unhex('deadbeef') : {safe_unhex('deadbeef')}")
print(f" safe_unhex('nothex!!') : {safe_unhex('nothex!!')}")
print("\n=== done ===")
For the base64 alternative — the base64 module provides higher-level Base64 encoding including URL-safe variants (b64encode, urlsafe_b64encode), Base85 (b85encode), Base32, and Base16; it wraps binascii.b2a_base64 internally — use base64 for all standard Base64 encoding tasks in application code; use binascii directly for hex conversion (hexlify/unhexlify), CRC-32 checksums, and binary protocol work where you need the low-level primitives. For the hashlib / zlib alternative — hashlib provides cryptographic hash functions (SHA-256, SHA-3, BLAKE2) that are far stronger than CRC-32 for data integrity; zlib.crc32 and zlib.adler32 also compute checksums; binascii.crc32 and zlib.crc32 use the same algorithm but zlib.crc32 returns a consistent unsigned int across Python versions — use hashlib for security-relevant integrity verification (signatures, content-addressed storage); use binascii.crc32 or zlib.crc32 for non-security checksums in binary protocols, ZIP metadata, and error detection where speed matters over collision resistance. The Claude Skills 360 bundle includes binascii skill sets covering to_hex()/from_hex()/hex_to_int()/int_to_hex()/safe_unhex() hex helpers, to_b64()/from_b64()/b64_chunks() base64 utilities, crc32()/crc32_stream()/crc32_file()/verify_crc32() checksum tools, hexdump()/diff_hexdump() display helpers, and Frame dataclass for binary protocol framing. Start with the free tier to try binary encoding patterns and binascii pipeline code generation.