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

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

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

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

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

Однако заполнение полезно в ситуациях, когда кодированные строки 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 .

Зачем беспокоиться о заполнении?

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

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

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

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

Что такое простыни?

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

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

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

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

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

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

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

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

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

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

Примеры

Вот пример формы 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[] -подобную структуру данных, тогда перед декодированием необходимо вручную поместить окончательное целое число или сделать некоторую дополнительную учетную запись на исходной длине ввода.

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

  • Что такое Unicode, UTF-8, UTF-16?
  • Как найти кодировку по умолчанию или кодировку в Java?
  • Как определить кодировку символов текстового файла?
  • C # Преобразование строки из UTF-8 в ISO-8859-1 (Latin1) H
  • Как поддерживать кодировку UTF-8 в Eclipse
  • Как преобразовать строки в и из массивов байтов UTF8 в Java
  • request.getQueryString (), похоже, нуждается в некоторой кодировке
  • В чем разница между кодировками utf8mb4 и utf8 в mysql?
  • Проблема с кодировкой Java FileReader
  • Проблема кодирования экспорта ASP.NET Excel
  • Ruby on Rails 3, несовместимые кодировки символов: UTF-8 и ASCII-8BIT с i18n
  • Interesting Posts
    Давайте будем гением компьютера.