Загрузить файл
  1. base64hub
  2. Статьи о Base64
  3. Base64 и другие кодировки
Разбор

Base64, Hex, Base32, Base58 и Base85: сравнение

Любая кодировка двоичных данных в текст выбирает между размером, читаемостью и набором допустимых символов. Ниже показан один и тот же ввод в девяти кодировках и цифры, от которых зависит выбор.

Сравнительная таблица

Все эти кодировки превращают произвольные байты в печатный текст и обратно без потерь. Различаются они количеством символов, самими символами и тем, насколько вырастает результат.

КодировкаАлфавитРазмер результатаРегистр важенБезопасна для URLГде применяется
Hex (Base16)0-9 a-f200%НетДаХеши, MAC-адреса, дампы байтов, коды цветов
Base32 (RFC 4648)A-Z 2-7, дополнение =160%Нет (по спецификации заглавные)Да, без =Секреты TOTP, onion-адреса Tor, DNSSEC (base32hex)
Base58 (Bitcoin)1-9 A-Z a-z без 0 O I lоколо 137%ДаДаАдреса Bitcoin, IPFS CIDv0 (Qm…), ключи Solana
Base64A-Z a-z 0-9 + /, дополнение =133%ДаНетПочтовые вложения, data URI, PEM, данные в JSON
Base64URLA-Z a-z 0-9 - _133%ДаДаJWT, токены в URL, имена файлов
Ascii85от ! до u, плюс z125%ДаНетПотоки PDF и PostScript
Z8585 символов, включая .-:+=^!/*?&<>()[]{}@%$#125%ДаНетКлючи CURVE в ZeroMQ
Base45 (RFC 9285)0-9 A-Z, пробел, $%*+-./:150%Нет (только заглавные)НетQR-коды, EU Digital COVID Certificate

«Размер результата» означает длину закодированных данных в процентах от длины исходных для больших объёмов. Base64 тратит 4 символа на 3 байта, Base32 – 8 на 5, Base85 – 5 на 4, Base45 – 3 на 2. У Base58 нет фиксированного блока, поэтому его коэффициент равен log(256) / log(58), примерно 1,366. Точные цифры для конкретного ввода сразу по всем кодировкам показывает калькулятор размера.

Один и тот же ввод в каждой кодировке

Вот 12-байтная ASCII-строка Hello world!, закодированная девятью способами. Двенадцать кратно и 3, и 4, поэтому Base64 и вариантам Base85 дополнение не нужно.

КодировкаРезультатДлина
Hex48656c6c6f20776f726c642124
Base32JBSWY3DPEB3W64TMMQQQ====24 (20 без дополнения)
Base32hex91IMOR3F41RMUSJCCGGG====24
Base58 (алфавит Bitcoin)2NEpo7TZRhna7vSvL17
Base64SGVsbG8gd29ybGQh16
Base45%69 VD82EK4F.KESTC18
Ascii8587cURD]j7BEbo8015
Z85nm=QNzY<mxA+]nf15
Base85 (RFC 1924 / git)NM&qnZy<MXa%^NF15

Base64URL здесь совпадает с Base64, потому что в результате нет + и /. Разница проявляется только на определённых байтах: fb ef be в Base64 даёт ++++, а в Base64URL ----.

Стандартная библиотека Python покрывает большую часть таблицы. z85encode появился в Python 3.13:

import base64

data = b"Hello world!"
print(data.hex())                           # 48656c6c6f20776f726c6421
print(base64.b32encode(data).decode())      # JBSWY3DPEB3W64TMMQQQ====
print(base64.b64encode(data).decode())      # SGVsbG8gd29ybGQh
print(base64.a85encode(data).decode())      # 87cURD]j7BEbo80
print(base64.b85encode(data).decode())      # NM&qnZy<MXa%^NF
print(base64.z85encode(data).decode())      # nm=QNzY<mxA+]nf

Base58 в стандартной библиотеке нет, но он укладывается в несколько строк, потому что это обычный перевод одного большого целого числа в другую систему счисления:

B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def b58encode(data: bytes) -> str:
    n = int.from_bytes(data, "big")
    out = ""
    while n:
        n, r = divmod(n, 58)
        out = B58[r] + out
    zeros = len(data) - len(data.lstrip(b"\0"))
    return "1" * zeros + out

print(b58encode(b"Hello world!"))   # 2NEpo7TZRhna7vSvL
print(b58encode(b"\0\0\x01"))       # 112

Каждый ведущий нулевой байт превращается в литерал 1, потому что большое целое число не может запомнить ведущие нули. Поэтому все классические адреса Bitcoin с нулевым байтом версии начинаются с 1.

Где применяется каждая кодировка

Hex

Hex тратит по два символа на байт, поэтому из всех вариантов он самый объёмный и самый читаемый. Каждый символ соответствует ровно 4 битам, так что байт со смещением n всегда занимает символы 2n и 2n+1. Именно поэтому хеши, контрольные суммы и отладочные дампы почти всегда пишут в hex. Декодеры принимают и DEADBEEF, и deadbeef. Конвертировать помогут Base64 в hex и hex в Base64.

Base32

Base32 использует только заглавные буквы и цифры от 2 до 7. Он выживает в системах, которые не различают регистр (доменные имена, некоторые файловые системы, люди, вводящие код в телефон), и обходится без 0, 1 и 8, похожих на O, I и B. Приложения-аутентификаторы хранят секреты TOTP в Base32, а onion-адреса Tor v3 состоят из 56 строчных символов Base32. RFC 4648 определяет и base32hex (0-9 A-V), который сохраняет порядок сортировки исходных байтов. Попробуйте кодировщик Base32.

Base58

Base58 появился вместе с Bitcoin. В нём нет 0, O, I и l (их легко спутать), а также + и / (они ломают выделение двойным щелчком и URL). Адреса Bitcoin добавляют сверху байт версии и 4-байтную контрольную сумму; такой формат называется Base58Check. Хеши IPFS CIDv0 тоже записаны в Base58; они начинаются с байтов multihash 12 20, поэтому в Base58 всегда начинаются с Qm. Весь ввод обрабатывается как одно число, поэтому время конвертации растёт квадратично с длиной, и Base58 используют для ключей и хешей, а не для файлов. Попробуйте кодировщик Base58.

Ascii85, Z85 и Base85 из git

Семейство Base85 упаковывает 4 байта в 5 символов, это самая плотная из широко поддерживаемых кодировок. Подвох в алфавите: среди 85 печатных символов, смотря по варианту, есть кавычки, обратная косая черта, <, > или &.

  • Ascii85 (Adobe) использует символы от ! до u, обрамляет результат в <~ и ~> и записывает четыре нулевых байта одним символом z. Его используют PostScript и PDF (фильтр ASCII85Decode).
  • Z85 (ZeroMQ) берёт символы, безопасные внутри строковых литералов C и JSON, без кавычек и обратной косой черты. Длина ввода должна быть кратна 4. 32-байтный ключ CURVE занимает 40 символов.
  • Base85 по RFC 1924 был первоапрельским предложением для записи адресов IPv6. Его алфавит живёт в бинарных патчах git и в b85encode из Python.

Инструмент Base85 работает со всеми тремя; у Z85 есть отдельная страница.

Base45

Base45 создан для QR-кодов. Алфавитно-цифровой режим QR-кода хранит ровно 45 символов (цифры, заглавные буквы, пробел и $%*+-./:) по 5,5 бита на символ, тогда как в байтовом режиме на символ уходит 8 бит. Base45 превращает 2 байта в 3 таких символа, что внутри QR-кода обходится примерно в 3%. Текст Base64 вынужден использовать байтовый режим, и рост составляет 33%. EU Digital COVID Certificate использовал Base45 именно поэтому. Попробуйте кодировщик Base45.

Как выбрать

Берите ту кодировку, которую ждёт принимающая сторона. Библиотеке JWT нужен Base64URL, приложению-аутентификатору Base32, Bitcoin-кошельку Base58Check. Если обе стороны под вашим контролем, работают такие эмпирические правила:

  • Байты внутри JSON, XML, письма или тела HTTP: Base64. В каждом языке есть быстрая встроенная реализация, а рост на 33% приемлем.
  • Внутри URL, cookie или имени файла: Base64URL без дополнения.
  • Значение будут читать, набирать или сравнивать люди: hex для коротких хешей, Base32, если регистр может потеряться, Base58, если результат должен выглядеть компактно и не содержать похожих символов.
  • Важен каждый байт, а декодер ваш: Z85 или Ascii85.
  • QR-коды: Base45.

Компромисс всегда один и тот же: чем больше алфавит, тем короче результат и тем больше символов, которые где-нибудь придётся экранировать. Почему Base64 вырастает на треть, объясняет статья о росте размера в Base64. URL-safe вариант разобран в статье Base64 и Base64URL.

Вопросы и ответы

Какая кодировка двоичных данных в текст самая компактная?

Из распространённых самая компактная Base85 (Ascii85 и Z85) с ростом на 25%, следом идёт Base64 с 33%. basE91 может чуть лучше, но поддерживается редко. Если он нужен, есть инструмент Base91.

Почему в Bitcoin Base58, а не Base64?

В Base58 нет 0, O, I, l, + и /, поэтому адрес проще прочитать вслух, переписать вручную и выделить двойным щелчком в текстовом поле. Платой становится медленное преобразование большого числа, но для 25-байтных адресов это неважно.

Важен ли регистр в Base32 и Base58?

Алфавит RFC 4648 состоит из заглавных букв, и строгие декодеры отклоняют строчные. Многие принимают оба регистра; в Python для этого нужен casefold=True. Base58 чувствителен к регистру: a и A в нём разные цифры. Hex практически во всех декодерах регистронезависим.

Можно ли напрямую перевести Base64 в Base58 или Base32?

Да: декодировать в байты и закодировать заново. Конвертеры Base64 в Base58 и Base64 в Base32 делают оба шага локально в браузере.

Читайте также