Source code for tet.util.base64

"""
Base64 and Crockford Base32 encoding utilities.

This module provides encoding utilities including standard Base64 and
Crockford's Base32, which is human-friendly (avoids ambiguous characters
like 0/O and 1/I/L).

Example
-------

Using standard Base64::

    from tet.util.base64 import Base64

    encoded = Base64.encode(b"hello")
    decoded = Base64.decode(encoded)

    # Generate random Base64 characters
    random_str = Base64.generate_characters(16)

Using Crockford Base32::

    from tet.util.base64 import CrockfordBase32

    encoded = CrockfordBase32.encode(b"hello")
    decoded = CrockfordBase32.decode(encoded)

    # Crockford Base32 is case-insensitive and handles ambiguous chars
    CrockfordBase32.decode("O1L")  # Treated as "011"
"""
import base64
import random
import string

maketrans = bytes.maketrans


[docs] class BaseCodec(object): """Base class for encoding codecs."""
[docs] @classmethod def generate_characters(cls, length): """Generate random characters from the codec's character set.""" randomizer = random.SystemRandom() max_num = len(cls.chars) - 1 return b"".join( cls.chars[randomizer.randint(0, max_num)] for i in range(length) ).decode()
[docs] class Base64(BaseCodec): """Standard Base64 encoding.""" chars = (string.ascii_letters + string.digits + "+/").encode() padding = True
[docs] @classmethod def encode(cls, string): """Encode bytes to Base64.""" return base64.b64encode(string)
[docs] @classmethod def normalize(cls, string): """Normalize input (no-op for standard Base64).""" return string
[docs] @classmethod def decode(cls, string): """Decode Base64 to bytes.""" return base64.b64decode(string)
_std_b32_to_crockford_b32 = maketrans( b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", b"0123456789ABCDEFGHJKMNPQRSTVWXYZ" ) _crockford_b32_to_std_b32 = maketrans( b"0OI1L23456789ABCDEFGHJKMNPQRSTVWXYZ", b"AABBBCDEFGHIJKLMNOPQRSTUVWXYZ234567" ) _normalize_crockford_b32 = maketrans( b"OIL" + string.ascii_lowercase.encode(), b"011" + string.ascii_uppercase.encode() )
[docs] class CrockfordBase32(BaseCodec): """ Crockford's Base32 encoding. Human-friendly encoding that avoids ambiguous characters (0/O, 1/I/L). Case-insensitive and handles common transcription errors. """ chars = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" padding = False
[docs] @classmethod def encode(cls, string, normalize=True, validate=False): """Encode bytes to Crockford Base32.""" if isinstance(string, str): string = string.decode() return base64.b32encode(string).translate( _std_b32_to_crockford_b32, b"=" ).decode()
[docs] @classmethod def decode(cls, string, normalize=True, validate=False): """Decode Crockford Base32 to bytes.""" if normalize: string = cls.normalize(string) if isinstance(string, str): string = string.encode() # Ensure the mandatory padding is correct: b32 = string.upper() b32 += b"=" * ((8 - len(b32) % 8) % 8) return base64.b32decode(b32.translate(_crockford_b32_to_std_b32))
[docs] @classmethod def normalize(cls, string): """Normalize input by handling ambiguous characters (O->0, I/L->1).""" if isinstance(string, str): string = string.encode() string = string.translate(_normalize_crockford_b32) return string.decode()