Почему кодировка base64 требует заполнения, если входная длина не делится на 3?



Какова цель заполнения в кодировке base64. Ниже приводится выдержка из Википедии:



" выделяется дополнительный символ pad, который может быть использован для принудительного преобразования закодированного вывода в целое число, кратное 4 символам (или, что эквивалентно, когда некодированный двоичный текст не кратен 3 байтам) ; эти символы заполнения должны быть отброшены при декодировании, но все же позволяют вычислить эффективную длину некодированного текста, когда его входная двоичная длина не было бы не кратным 3 байтам (последний не-pad символ обычно кодируется так, что последний 6-битный блок, который он представляет, будет заполнен нулем на его наименее значимых битах, не более двух pad символов может произойти в конце кодируемого потока)."



Я написал программу, которая могла бы кодировать любую строку base64 и декодировать любую строку, закодированную base64. Какую проблему решает прокладка?
640   3  

3 ответов:

Ваше заключение о том, что обивка не нужна, правильно. Всегда можно однозначно определить длину входного сигнала по длине кодируемой последовательности.

Однако заполнение полезно в ситуациях, когда кодированные строки base64 объединяются таким образом, что длины отдельных последовательностей теряются, как это может произойти, например, в очень простом сетевом протоколе.

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

Правка: Иллюстрация

Предположим, у нас есть программа, которая base64-кодирует слова, связывает их и отправляет по сети. Он кодирует "I", " AM " и "TJM", объединяет результаты без заполнения и передает их.
  • I кодирует в SQ (SQ== с прокладкой)
  • AM кодирует в QU0 (QU0= с прокладкой)
  • TJM кодирует в VEpN (VEpN с прокладкой)
Таким образом, передаваемые данные являются SQQU0VEpN. Приемник base64-декодирует это как I\x04\x14\xd1Q) вместо предполагаемого IAMTJM. Результат-нонсенс, потому что отправитель уничтожил информацию о том, где заканчивается каждое слово в кодированной последовательности. Если отправитель послал SQ==QU0=VEpN вместо этого, получатель можно было бы декодировать это как три отдельные последовательности base64, которые сцепились бы, чтобы дать IAMTJM.

Зачем утруждать себя прокладкой?

Почему бы просто не разработать протокол для префикса каждого слова с целой длиной? Тогда приемник сможет правильно декодировать поток,и не будет необходимости в прокладке.

Это отличная идея, пока мы знаем длину данных, которые мы кодируем, прежде чем начнем их кодировать. Но что, если вместо слов мы будем кодировать куски видео с живой камеры? Мы можем не знать заранее длину каждого куска.

Если бы протокол использовал заполнение, не было бы никакой необходимости передавать длину вообще. Данные можно было закодировать так, как они поступали с камеры, каждый фрагмент заканчивался заполнением, и приемник мог правильно декодировать поток.

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

Что такое символы заполнения?

Символы заполнения помогают удовлетворять требованиям к длине и не несут никакого смысла.

Десятичный Пример заполнения: Учитывая произвольное требование, чтобы все строки имели длину 8 символов, число 640 может удовлетворять этому требованию, используя предшествующие 0 в качестве символов заполнения, поскольку они не несут никакого значения, "00000640".

Двоичное Кодирование

Парадигма байта: байт является де-факто стандартной единицей измерения и любой схема кодирования должна относиться обратно к байтам.

Base256 точно вписывается в эту парадигму. Один байт равен одному символу в base256.

Base16 , шестнадцатеричный или шестнадцатеричный, использует 4 бита для каждого символа. Один байт может представлять два символа base16.

Base64 не вписывается равномерно в байтовую парадигму, в отличие от base256 и base16. Все символы base64 могут быть представлены в 6 битах, на 2 бита меньше полного байта.

Мы можем представлять кодирование base64 в сравнении с байтовой парадигмой в виде дроби: 6 бит на символ над 8 битами на байт. Уменьшенная эта доля составляет 3 байта на 4 символа.

Это соотношение, 3 байта на каждые 4 символа base64, является правилом, которому мы хотим следовать при кодировании base64. Кодирование Base64 может обещать только равномерное измерение с 3-байтовыми связками, в отличие от base16 и base256, где каждый байт может стоять сам по себе.

Итак, Почему рекомендуется заполнение, даже если кодирование может ли работать просто отлично без заполнения символов? Заполняющие символы явно сообщают, что эти дополнительные места должны быть пустыми и исключают любую двусмысленность или потенциально неприятные ошибки. Заполнение позволяет нам декодировать кодировку base64 с обещанием отсутствия потерянных битов. Без заполнения больше нет явного подтверждения измерения в трехбайтовых пакетах, и мы больше не можем гарантировать точное воспроизведение исходного кодирования без дополнительной информации.

Примеры

Вот пример формы RFC 4648 (http://tools.ietf.org/html/rfc4648#section-8 )

Каждый символ внутри функции BASE64 использует один байт (base256). Затем мы переводим это на base64.

BASE64("")       = ""           (No bytes used. 0%3=0.)
BASE64("f")      = "Zg=="       (One byte used. 1%3=1.)
BASE64("fo")     = "Zm8="       (Two bytes. 2%3=2.)
BASE64("foo")    = "Zm9v"       (Three bytes. 3%3=0.)
BASE64("foob")   = "Zm9vYg=="   (Four bytes. 4%3=1.)
BASE64("fooba")  = "Zm9vYmE="   (Five bytes. 5%3=2.)
BASE64("foobar") = "Zm9vYmFy"   (Six bytes. 6%3=0.)

Вот кодер, с которым вы можете поиграть: http://www.motobit.com/util/base64-decoder-encoder.asp

Это только моя теория, и я не могу предоставить никаких источников, но я думаю, что символ(ы) заполнения только служит для того, чтобы сделать Некоторые реализации алгоритма декодирования самым крошечным битом проще. В частности, если алгоритм помещает кодированную строку во что-то вроде int[], то конечное значение иногда будет слишком длинным.

Если заполнение уже присутствует во входных данных, то ничего больше не нужно делать-алгоритм может просто прочитать и декодировать вход.

Если алгоритм не допускает наличия заполнения, однако, и он использует int[]-подобную структуру данных, тогда ему нужно вручную заполнить последнее целое число перед декодированием или сделать некоторый дополнительный учет исходной длины входного сигнала.

Лично я не думаю, что заполнение служит какой-либо цели вообще больше, но в те времена, когда процессор и оперативная память были не так обильны, как сейчас, эта небольшая оптимизация, возможно, имела значение. Сомневаюсь, что это имело значение. хотя и много... хорошая реализация все равно должна была бы сделать что-то разумное, когда подаваемые входные данные были усечены случайным образом, и это, ИМО, дало бы возможность обрабатывать неупакованные входные данные без каких-либо дополнительных затрат.

Comments

    Ничего не найдено.