Как кодировать и декодировать Z85
- Вставьте байты в hex в поле Ввод · Hex. Пробелы, двоеточия и префиксы
0xдопускаются, так что hex-дамп можно вставить как есть. - Z85 появится в поле Результат · Z85 (ZeroMQ).
- Если число байтов не кратно 4, появится ошибка с этим числом. Включайте Разрешить неполный последний блок (нестандартно), только если обе стороны договорились об этом расширении.
- Для декодирования нажмите Z85 (ZeroMQ) → Hex в переключателе направления и вставьте строку Z85. В списке В выберите Base64 или Текст, чтобы увидеть данные иначе, или нажмите Сохранить байты, чтобы получить бинарный файл.
Тестовые векторы из спецификации
Спецификация Z85 от ZeroMQ (RFC 32 в серии ZeroMQ RFC) приводит два тестовых значения. Этот инструмент воспроизводит оба:
| Hex | Z85 |
|---|---|
86 4F D2 6F B5 59 F7 5B | HelloWorld |
8E 0B DD 69 76 28 B9 1D 8F 24 55 87 EE 95 C5 B0 4D 48 96 3F 79 25 98 77 B4 9C D9 06 3A EA D3 B7 | JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6 |
Первый показывает блочную структуру: 8 байт, два блока, десять символов. Второй содержит 32-байтовый ключ и его 40-символьную запись, именно такие встречаются в конфигурации CurveZMQ.
Несколько граничных значений: четыре нулевых байта дают 00000, четыре байта ff дают %nSc0. Сокращения для нулевых блоков в Z85 нет, так что серия нулей занимает те же пять символов на блок.
Зачем ZeroMQ понадобился Z85
Ключи CurveZMQ состоят из 32 случайных байтов. ZeroMQ нужен был способ записывать их обычными строками в конфигах, командной строке и исходном коде. Z85 сделан именно для этого:
- Он на 25% больше исходных байтов против 33% у Base64, так что 32-байтовый ключ занимает 40 символов, а не 44.
- В его алфавите нет
",',\и обратной кавычки, поэтому ключ можно вставить в строковый литерал C, Python или shell без экранирования. Нет в нём и,с;. - Сначала идут цифры и буквы (
0-9 a-z A-Z), затем 23 знака препинания:.-:+=^!/*?&<>()[]{}@%$#.
При этом в нём есть <, > и &, так что внутри XML или HTML Z85 нужно экранировать. В JSON экранировать не нужно.
Z85 в Python
У Z85 и b85encode из Python общая арифметика, а различаются они только алфавитом, так что одно в другое переводится заменой символов:
import base64
B85 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
Z85 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"
TO_Z85 = str.maketrans(B85, Z85)
FROM_Z85 = str.maketrans(Z85, B85)
def z85encode(data: bytes) -> str:
if len(data) % 4:
raise ValueError("Z85 needs a multiple of 4 bytes")
return base64.b85encode(data).decode().translate(TO_Z85)
def z85decode(text: str) -> bytes:
return base64.b85decode(text.translate(FROM_Z85))
z85encode(bytes.fromhex("864FD26FB559F75B")) # 'HelloWorld'
Если проект уже зависит от PyZMQ, то же самое делают zmq.utils.z85.encode и decode. В C у libzmq есть zmq_z85_encode и zmq_z85_decode. Байты в Python подробнее разобраны на странице про Python.
Частые проблемы
- «Z85 кодирует блоки по 4 байта, а в данных N байт». Ввод не выровнен по блокам. Проверьте, что ключ скопирован целиком: если 32-байтовый ключ показывает 31 байт, потерялась пара hex-цифр.
- «Z85 требует групп по 5 символов, а лишних осталось N». Строка Z85 обрезана или в ней лишние символы. В ключе CurveZMQ ровно 40 символов.
- Строка декодируется, но ключ не работает. Возможно, это Ascii85 или Base85 из Git: правила длины у них те же, а алфавит другой, так что те же символы дают другие байты. Попробуйте на странице Base85, выбрав в Из другой вариант.
Вопросы и ответы
Почему Z85 требует длину, кратную 4 байтам?
Спецификация определяет Z85 только для целых блоков по 4 байта, чтобы декодер мог рассчитывать, что каждые 5 символов дают 4 байта. Данные другой длины приложение должно само дополнить или обернуть. Включите Разрешить неполный последний блок (нестандартно), чтобы всё же закодировать хвост в стиле Ascii85.
Какой длины ключ CurveZMQ в Z85?
40 символов. Открытый и секретный ключи CurveZMQ – по 32 байта, а 32 / 4 × 5 = 40. Именно такую длину возвращает zmq_curve_keypair(), плюс завершающий ноль в C.
Z85 – это то же самое, что Ascii85?
Арифметика та же, алфавит другой. Оба записывают 4 байта пятью цифрами по основанию 85, но в Z85 сначала идут цифры и буквы, нет кавычек и обратной косой черты, нет сокращения z и разделителей <~ ~>.
Как закодировать Z85 в Python?
В стандартной библиотеке Z85 нет, но base64.b85encode использует ту же арифметику, так что достаточно перевести алфавит его вывода. Это и делает пример на этой странице. Ещё в PyZMQ есть zmq.utils.z85.