64 символа
Base64 читает входные данные по 3 байта (24 бита) и делит их на четыре 6-битных числа. Каждое число от 0 до 63 – это индекс в таблице ниже. Порядок закреплён в RFC 4648: заглавные буквы для 0–25, строчные для 26–51, цифры для 52–61, затем + и /. В последнем столбце указан ASCII-код символа: именно он в итоге хранится или передаётся.
| Индекс | 6 бит | Base64 | Base64URL | Код ASCII |
|---|---|---|---|---|
| 0 | 000000 | A | A | 0x41 |
| 1 | 000001 | B | B | 0x42 |
| 2 | 000010 | C | C | 0x43 |
| 3 | 000011 | D | D | 0x44 |
| 4 | 000100 | E | E | 0x45 |
| 5 | 000101 | F | F | 0x46 |
| 6 | 000110 | G | G | 0x47 |
| 7 | 000111 | H | H | 0x48 |
| 8 | 001000 | I | I | 0x49 |
| 9 | 001001 | J | J | 0x4A |
| 10 | 001010 | K | K | 0x4B |
| 11 | 001011 | L | L | 0x4C |
| 12 | 001100 | M | M | 0x4D |
| 13 | 001101 | N | N | 0x4E |
| 14 | 001110 | O | O | 0x4F |
| 15 | 001111 | P | P | 0x50 |
| 16 | 010000 | Q | Q | 0x51 |
| 17 | 010001 | R | R | 0x52 |
| 18 | 010010 | S | S | 0x53 |
| 19 | 010011 | T | T | 0x54 |
| 20 | 010100 | U | U | 0x55 |
| 21 | 010101 | V | V | 0x56 |
| 22 | 010110 | W | W | 0x57 |
| 23 | 010111 | X | X | 0x58 |
| 24 | 011000 | Y | Y | 0x59 |
| 25 | 011001 | Z | Z | 0x5A |
| 26 | 011010 | a | a | 0x61 |
| 27 | 011011 | b | b | 0x62 |
| 28 | 011100 | c | c | 0x63 |
| 29 | 011101 | d | d | 0x64 |
| 30 | 011110 | e | e | 0x65 |
| 31 | 011111 | f | f | 0x66 |
| 32 | 100000 | g | g | 0x67 |
| 33 | 100001 | h | h | 0x68 |
| 34 | 100010 | i | i | 0x69 |
| 35 | 100011 | j | j | 0x6A |
| 36 | 100100 | k | k | 0x6B |
| 37 | 100101 | l | l | 0x6C |
| 38 | 100110 | m | m | 0x6D |
| 39 | 100111 | n | n | 0x6E |
| 40 | 101000 | o | o | 0x6F |
| 41 | 101001 | p | p | 0x70 |
| 42 | 101010 | q | q | 0x71 |
| 43 | 101011 | r | r | 0x72 |
| 44 | 101100 | s | s | 0x73 |
| 45 | 101101 | t | t | 0x74 |
| 46 | 101110 | u | u | 0x75 |
| 47 | 101111 | v | v | 0x76 |
| 48 | 110000 | w | w | 0x77 |
| 49 | 110001 | x | x | 0x78 |
| 50 | 110010 | y | y | 0x79 |
| 51 | 110011 | z | z | 0x7A |
| 52 | 110100 | 0 | 0 | 0x30 |
| 53 | 110101 | 1 | 1 | 0x31 |
| 54 | 110110 | 2 | 2 | 0x32 |
| 55 | 110111 | 3 | 3 | 0x33 |
| 56 | 111000 | 4 | 4 | 0x34 |
| 57 | 111001 | 5 | 5 | 0x35 |
| 58 | 111010 | 6 | 6 | 0x36 |
| 59 | 111011 | 7 | 7 | 0x37 |
| 60 | 111100 | 8 | 8 | 0x38 |
| 61 | 111101 | 9 | 9 | 0x39 |
| 62 | 111110 | + | - | 0x2B |
| 63 | 111111 | / | _ | 0x2F |
| дополнение | – | = | обычно опускается | 0x3D |
Два диапазона стоит запомнить. Все символы от A до P (0–15) начинаются с битов 00, а все символы от w до / (48–63) – с 11. Этого хватает, чтобы разобрать символ в уме, когда проверяете префикс вручную. Подробный пример разбиения на биты есть в статье как работает Base64.
Порядок алфавита не совпадает с порядком ASCII. В ASCII сначала идут + и /, потом цифры, потом заглавные и строчные буквы. Поэтому сортировка строк Base64 не сортирует исходные байты: +A== (байт F8) окажется раньше AA== (байт 00). Если нужны закодированные значения, которые сортируются так же, как сырые байты, берите base32hex из RFC 4648 или обычный hex.
URL-safe алфавит
У + и / в URL особый смысл. В строке запроса и данных формы + декодируется в пробел, а / разделяет сегменты пути. Base64URL, описанный в разделе 5 RFC 4648, оставляет индексы 0–61 как есть и меняет два последних:
| Индекс | Base64 | Base64URL |
|---|---|---|
| 62 | + | - |
| 63 | / | _ |
Всё остальное, включая раскладку битов, совпадает, поэтому перевод из одного варианта в другой – это замена символов плюс добавление или удаление дополнения. Base64URL, обычно без =, используют JWT, многие API-токены и идентификаторы, которые должны годиться для имён файлов. Кодировщик Base64URL выдаёт его сразу. Полное сравнение приведено в статье Base64 и Base64URL.
Символ дополнения
= (ASCII 0x3D) не входит в алфавит из 64 символов и никогда не кодирует данные. Он только заполняет последнюю группу из 4 символов, когда длина входных данных не кратна 3:
- остался 1 байт: 2 символа данных плюс
==; - осталось 2 байта: 3 символа данных плюс
=; - лишних байтов нет: дополнения нет.
Поэтому длина строки с дополнением всегда кратна 4, а === не бывает. Без дополнения остаток от деления длины на 4 равен 0, 2 или 3, но никогда 1. Когда = можно опустить и как его восстановить, рассказано в статье про дополнение.
Какие символы где встречаются
Несколько закономерностей напрямую следуют из раскладки битов. Мы проверили их полным перебором всех нужных значений байтов.
Перед == бывают только A, Q, g или w. Когда остаётся один байт, второй символ несёт 2 бита данных и 4 нулевых бита, так что его индекс равен 0, 16, 32 или 48. Перед одиночным = у третьего символа в конце 2 нулевых бита, поэтому это один из 16 символов: A E I M Q U Y c g k o s w 0 4 8. Любой другой символ на этом месте означает неканоническую кодировку, и строгие декодеры такую строку отвергают.
Случайные байты используют все 64 символа поровну. Каждая 6-битная группа случайных данных распределена равномерно, поэтому у зашифрованных данных, ключей и сжатых файлов распределение символов плоское. Перекос в распределении подсказывает, что внутри текст или данные со структурой.
В ASCII-тексте первым символом группы не бывает строчных от g до z, цифр, + и /. Первый символ каждой 4-символьной группы содержит старшие 6 бит байта. У 7-битного ASCII старший бит равен 0, так что этот символ всегда лежит между A и f (индексы 0–31). В SGVsbG8gd29ybGQh (Hello world!) группы начинаются с S, b, d и b.
В Base64 от ASCII-текста + и / редки. Для байтов меньше 0x80 символ + может появиться только четвёртым в группе, когда третий байт – > или ~. / может стоять там же, только если этот байт – ? или управляющий символ DEL. Вот почему Hi?> кодируется в SGk/Pg==, а <b> – в PGI+.
Цепочки A – это нулевые байты, цепочки / – байты 0xFF. AAAA – три байта 00, //// – три байта FF. Длинные отрезки из A типичны для разреженных двоичных форматов, текста в UTF-16 (Hello – это SABlAGwAbABvAA==) и полей длины в начале SSH-ключей. Другие узнаваемые шаблоны собраны в статье частые префиксы Base64.
Другие алфавиты Base64
Некоторые системы сохранили идею 64 символов на 6 бит, но выбрали другие символы:
| Вариант | Алфавит в порядке индексов | Где встречается |
|---|---|---|
| Стандартный | A-Z a-z 0-9 + / | RFC 4648, MIME, PEM, большинство API |
| URL-safe | A-Z a-z 0-9 - _ | RFC 4648, раздел 5, JWT |
| Имена почтовых ящиков IMAP | A-Z a-z 0-9 + , | модифицированный UTF-7 из RFC 3501 |
| bcrypt | . / A-Z a-z 0-9 | хеши паролей $2a$, $2b$, $2y$ |
| crypt(3) | . / 0-9 A-Z a-z | MD5-crypt $1$, SHA-crypt $5$ и $6$, DES crypt |
| xxencode | + - 0-9 A-Z a-z | старая почта Unix и Usenet |
| uuencode | ASCII от 32 до 95 (от пробела до _), часто с ` для 0 | старая почта Unix и Usenet |
- IMAP заменяет
/на,, потому что/часто служит разделителем иерархии в именах ящиков. ПапкаEntwürfeхранится какEntw&APw-rfe. - bcrypt переносит
.и/в начало и ставит буквы перед цифрами. Его соли и хеши – это Base64 в таком алфавите без дополнения, поэтому стандартный декодер выдаёт для них не те байты. - crypt(3) использует
./0-9A-Za-z, то есть порядок ASCII. К тому же он упаковывает биты начиная с младших, так что даже с перекодированным алфавитом стандартный декодер не восстановит байты хеша. - uuencode и xxencode старше MIME. Инструменты uuencode и xxencode умеют и кодировать, и декодировать.
Про кодировки с алфавитами другого размера, такие как Base32, Base58 и Base85, читайте в статье Base64, hex, Base32, Base58 и Base85. Определения терминов с этой страницы – в глоссарии.
Вопросы и ответы
Сколько символов в алфавите Base64?
64 символа для данных: 26 заглавных латинских букв, 26 строчных, 10 цифр, + и /. Знак дополнения = – 65-й символ, который никогда не несёт данных.
Какое значение в Base64 у буквы A?
A – это индекс 0, в двоичном виде 000000. B – 1, Z – 25, a – 26, z – 51, 0 – 52, 9 – 61, + – 62, / – 63.
Какие символы меняет Base64URL?
Только два: + (индекс 62) превращается в -, а / (индекс 63) – в _. Дополнение обычно тоже отбрасывают. Перевести строку можно инструментом Base64 в Base64URL.