Base64
Сертификат в файле .pem, ключ в JSON, картинка внутри HTML — всё это двоичные данные, записанные Base64. Кодирование простое: по 6 бит на печатный символ, но детали — дополнение, переводы строк, вариант для URL — регулярно ломают совместимость.
Обновлено Редакция GAW
Base64 — способ записать произвольные двоичные данные 64 печатными символами US-ASCII, по 6 бит на символ. Его определяет RFC 4648 (разд. 4): входные байты берутся группами по три — 24 бита, — и каждая группа превращается в четыре символа. Так двоичные данные проходят через каналы, рассчитанные на текст: заголовки HTTP, JSON, почту, файлы .pem с сертификатами X.509.
Алфавит и дополнение
| Значение | Символы | Значение | Символы |
|---|---|---|---|
| 0–25 | A–Z | 52–61 | 0–9 |
| 26–51 | a–z | 62, 63 | «+», «/» (base64url: «-», «_») |
| — | дополнение «=» |
Если длина данных не кратна трём, последняя группа неполная. Остался один байт — его 8 бит дополняются нулями до 12, выдаются два символа и два знака «=»; осталось два байта — 16 бит дают три символа и один «=». Неиспользуемые биты последнего символа обязаны быть нулями (разд. 3.5), иначе одна и та же двоичная строка имела бы несколько записей. Примеры из RFC 4648: 0x14fb9c03d97e → FPucA9l+, 0x14fb9c03d9 → FPucA9k=, 0x14fb9c03 → FPucAw==; для текста: «f» → Zg==, «foo» → Zm9v, «foobar» → Zm9vYmFy. Как выделять 6-битные группы сдвигами и масками, показано в статье «Битовые операции» и калькуляторе битовых масок.
Объём растёт на треть: n байт дают 4·⌈n/3⌉ символов (наш расчёт). Поэтому пересылать прошивку или снимок с камеры в Base64 внутри JSON дорого: двоичное тело в MQTT или HTTP на треть короче.
Что ломает совместимость
- Переводы строк. Кодер не должен вставлять их сам (разд. 3.1); это делают форматы: MIME режет строки по 76 символов, PEM — по 64. Декодер, не ожидающий переводов строк, отвергнет такой файл.
- Символы вне алфавита. По умолчанию декодер обязан отвергнуть данные с посторонними символами (разд. 3.3), если протокол не разрешил их игнорировать. Это защита от скрытых каналов и переполнений.
- Дополнение. Оно обязательно, если спецификация не говорит иного (разд. 3.2), а некоторые протоколы его отменяют. Декодер должен знать, чего ждать.
- base64url. Вариант из разд. 5 заменяет «+» и «/» на «-» и «_», потому что первые два имеют особый смысл в URL и именах файлов (разд. 3.4); знак «=» в URI пришлось бы кодировать как
%3D, поэтому при известной длине дополнение опускают. RFC запрещает называть этот вариант просто «base64».
На микроконтроллере
Base64 не сжимает и не шифрует — это только перекодировка, и секреты в ней видны как на ладони; целостность и подлинность дают HMAC, а конфиденциальность — TLS. В ESP-IDF функции Base64 входят в mbedTLS (CONFIG_MBEDTLS_BASE64_C, включены по умолчанию) — без них не разобрать сертификаты в формате PEM. Тот же кодер нужен веб-серверу esp_http_server для ключа рукопожатия WebSocket через esp_crypto_base64_encode(). Идентификаторы устройств, в том числе UUID, обычно записывают шестнадцатеричным текстом, а не Base64: читаемость важнее экономии нескольких байт. Разбор полей в бинарных и текстовых кадрах, где Base64 встречается рядом с CRC и длинами, описан в статье «Реализация протоколов».
Частые вопросы
Почему строка Base64 иногда заканчивается на «=» или «==»?
Кодер берёт входные байты группами по три (24 бита) и выдаёт по четыре символа. Если в конце остался один байт (8 бит), получаются два символа и два знака «=», если два байта (16 бит) — три символа и один «=». По RFC 4648 дополнение обязательно, если протокол явно не отменяет его; так декодер знает точную длину данных. Примеры из RFC: «f» → Zg==, «fo» → Zm8=, «foo» → Zm9v.
Насколько Base64 увеличивает объём данных?
Каждые 3 байта превращаются в 4 символа, то есть объём растёт на треть, плюс дополнение до кратного четырём в конце (наш расчёт по RFC 4648, разд. 4). Прошивка в 1 МиБ займёт в Base64 около 1,33 МиБ, а переводы строк, которые добавляет формат PEM каждые 64 символа, увеличат её ещё примерно на 1,6 % (наш расчёт). Для передачи по MQTT или HTTP двоичное тело экономнее.
Чем base64url отличается от обычного Base64?
Только двумя символами: вместо «+» и «/» для значений 62 и 63 используются «-» и «_», потому что «+» и «/» имеют особый смысл в URL и именах файлов (RFC 4648, разд. 3.4 и 5). Дополнение «=» в URL обычно пришлось бы кодировать как %3D, поэтому при известной длине его разрешено опускать. RFC требует не называть этот вариант просто «base64»: декодер одного алфавита отвергнет строку другого.
Источники
- IETF. RFC 4648 The Base16, Base32, and Base64 Data Encodings. S. Josefsson, October 2006 — разд. 3.1: кодеры не должны добавлять переводы строк, если этого не требует ссылающаяся спецификация; MIME ограничивает строку 76 символами, PEM — 64; разд. 3.2: дополнение «=» обязательно, если спецификация не говорит иного; разд. 3.3: символы вне алфавита должны отвергаться, если спецификация не разрешает их игнорировать; разд. 3.4: «+» и «/» неудобны в именах файлов и URL; разд. 3.5: неиспользуемые биты последнего символа обязаны быть нулями, иначе нет канонического представления; разд. 4: 65 символов US-ASCII, 6 бит на символ, 24-битная группа из 3 октетов даёт 4 символа; таблица 1 — A–Z (0–25), a–z (26–51), 0–9 (52–61), «+» (62), «/» (63), дополнение «=»; остаток 8 бит → 2 символа и «==», остаток 16 бит → 3 символа и «=»; разд. 5: base64url — те же правила, но 62 → «-», 63 → «_», при известной длине дополнение можно опустить, «=» в URI обычно требует процентного кодирования, base64url нельзя называть просто base64; разд. 9: 0x14fb9c03d97e → FPucA9l+, 0x14fb9c03d9 → FPucA9k=, 0x14fb9c03 → FPucAw==; разд. 10: BASE64(«f») = Zg==, BASE64(«fo») = Zm8=, BASE64(«foo») = Zm9v, BASE64(«foobar») = Zm9vYmFy
- Espressif. ESP-IDF Programming Guide v6.1, ESP32: Configuration Options Reference (Component config > mbedTLS); ESP-TLS — CONFIG_MBEDTLS_BASE64_C — функции кодирования и декодирования Base64 в mbedTLS, включены по умолчанию, необходимы для поддержки PEM; страница ESP-TLS: обратный вызов crypto_base64_encode пользовательского стека обслуживает API esp_crypto_base64_encode(), который нужен компоненту esp_http_server для кодирования ключа WebSocket
Нашли ошибку? ·
Смотрите также
- Сертификат X.509Структура сертификата по RFC 5280, цепочка и якорь доверия, срок действия, проверка на МК
- HMACКод аутентификации сообщения на хеш-функции и общем ключе: формула, ключ, усечение, аппаратный блок
- UUIDУниверсальный уникальный идентификатор: формат, variant и version, случайный v4, упорядоченный v7, UUID в BLE
- TLSШифрованный канал поверх TCP: рукопожатие, сертификаты, буферы и время на МК
- MQTTПротокол издатель — подписчик через брокер: топики, QoS, retain, Last Will
- Битовые операции в CМаски, сдвиги, установка и проверка битов, ловушки стандарта C
- Реализация протокола обменаКадры по паузе, длине и разделителю, COBS, CRC-16, таймауты, разбор потока
- Битовые маскиПоле регистра: маска, сдвиг, чтение и запись, код на C