Подтвердить что ты не робот

Удалять трейлинг "=" при кодировании base64

Я замечаю, что всякий раз, когда я кодирую строку в base64, в конце добавляется символ "=". Могу ли я удалить этот символ, а затем надежно расшифровать его, добавив обратно, или это опасно? Другими словами, всегда ли "=" добавляется или только в определенных случаях?

Я хочу, чтобы моя закодированная строка была как можно короче, поэтому я хочу знать, всегда ли я могу удалить символ "=" и просто добавить его обратно перед декодированием.

4b9b3361

Ответ 1

= - заполнение.

Wikipedia говорит

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

Если вы управляете другим концом, вы можете удалить его при транспортировке, а затем повторно вставить его (путем проверки длины строки) перед декодированием.
Обратите внимание, что данные не будут действительны Base64 в транспорте.

Ответ 2

Я написал часть Apache commons-codec-1.4.jar Base64-декодера, и в этой логике мы отлично справились без заполнения символов. Конец файла и конец потока также являются хорошими индикаторами, что сообщение Base64 завершено как любое число символов "="!

Вариант URL-Safe, введенный в Commons-кодек-1.4, пропускает символы заполнения для того, чтобы уменьшить количество вещей!

http://commons.apache.org/codec/apidocs/src-html/org/apache/commons/codec/binary/Base64.html#line.478

Я думаю, что более безопасный ответ: "зависит от вашей реализации декодера", но логически нетрудно написать декодер, который не нуждается в дополнении.

Ответ 3

В JavaScript вы можете сделать что-то вроде этого:

// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA=='; 

// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');

// reverse to original encoding
if (str.length % 4 != 0){
  str += ('===').slice(0, 4 - (str.length % 4));
}
str = str.replace(/-/g, '+').replace(/_/g, '/');

Смотрите также эту скрипку: http://jsfiddle.net/7bjaT/66/

Ответ 4

= добавляется для заполнения. Длина строки base64 должна быть кратной 4, поэтому при необходимости добавляется 1 или 2 =.

Читайте: Нет, его не следует удалять.

Ответ 5

На Android я использую это:

Global

String CHARSET_NAME ="UTF-8";

Кодировать

String base64 = new String(
            Base64.encode(byteArray, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP),
            CHARSET_NAME);
return base64.trim();

Decode

byte[] bytes = Base64.decode(base64String,
            Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP);

равно этому на Java:

Кодировать

private static String base64UrlEncode(byte[] input)
{
    Base64 encoder = new Base64(true);
    byte[] encodedBytes = encoder.encode(input);
    return StringUtils.newStringUtf8(encodedBytes).trim();
}

Decode

private static byte[] base64UrlDecode(String input) {
    byte[] originalValue = StringUtils.getBytesUtf8(input);
    Base64 decoder = new Base64(true);
    return decoder.decode(originalValue);
}

У меня никогда не было проблем с трейлингом "=", и я также использую Bouncycastle

Ответ 6

Если вы используете PHP, следующая функция вернет вырезанную строку в ее исходный формат с правильным заполнением:

<?php

$str = 'base64 encoded string without equal signs stripped';
$str = str_pad($str, strlen($str) + (4 - ((strlen($str) % 4) ?: 4)), '=');

echo $str, "\n";

Ответ 7

Если вы кодируете байты (с фиксированной длиной битов), то заполнение избыточно. Это касается большинства людей.

Base64 потребляет 6 битов за раз и создает байт из 8 битов, который использует только комбинации из шести битов.

Если ваша строка имеет длину 1 байт (8 бит), вы получите выходной бит 12 бит, как наименьшее кратное 6, в которое поместится 8, с дополнительными 4 битами. Если ваша строка составляет 2 байта, вы должны вывести 18 битов, с дополнительными двумя битами. Для кратных шести против кратных 8 вы можете иметь остаток 0, 2 или 4 бита.

Заполнение говорит, что игнорировать эти дополнительные четыре (==) или два (=) бита. Заполнение там сообщит декодеру о ваших дополнениях.

Заполнение на самом деле не нужно, когда вы кодируете байты. Кодер base64 может просто игнорировать оставшиеся биты, которые составляют менее 8 бит. В этом случае лучше удалить его.

Заполнение может быть полезно для потоковой передачи и битовых последовательностей произвольной длины, если они кратны двум. Это также может быть использовано для случаев, когда люди хотят отправлять только последние 4 бита, когда осталось больше битов, если все оставшиеся биты равны нулю. Некоторые люди могут захотеть использовать его для обнаружения неполных последовательностей, хотя это вряд ли надежно для этого. Я никогда не видел эту оптимизацию на практике. Люди редко сталкиваются с такими ситуациями, большинство людей используют base64 для дискретных последовательностей байтов.

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

Ответ 8

Используя Python, вы можете удалить заполнение base64 и добавить его обратно так:

from math import ceil

stripped = original.rstrip('=')

original = stripped.ljust(ceil(len(stripped) / 4) * 4, '=')

Ответ 9

Для Android У вас могут возникнуть проблемы, если вы хотите использовать класс android.util.base64, так как это не позволяет вам выполнять UnitTest другим тестам интеграции - те, которые используют среду Adnroid.

С другой стороны, если вы будете использовать java.util.base64, компилятор предупредит вас, что вы можете использовать sdk на низком уровне (ниже 26).

Поэтому я предлагаю разработчикам Android использовать

implementation "commons-codec:commons-codec:1.13"

Кодировка объекта

fun encodeObjectToBase64(objectToEncode: Any): String{
    val objectJson = Gson().toJson(objectToEncode).toString()
    return encodeStringToBase64(objectJson.toByteArray(Charsets.UTF_8))
}

fun encodeStringToBase64(byteArray: ByteArray): String{
    return Base64.encodeBase64URLSafeString(byteArray).toString() // encode with no padding
}

Декодирование на объект

fun <T> decodeBase64Object(encodedMessage: String, encodeToClass: Class<T>): T{
    val decodedBytes = Base64.decodeBase64(encodedMessage)
    val messageString = String(decodedBytes, StandardCharsets.UTF_8)
    return Gson().fromJson(messageString, encodeToClass)
}

Конечно, вы можете пропустить синтаксический анализ Gson и сразу же включить метод Your String, преобразованный в ByteArray.