Remove trailing "=" when base64 encoding

Base64

Base64 Problem Overview


I am noticing that whenever I base64 encode a string, a "=" is appended at the end. Can I remove this character and then reliably decode it later by adding it back, or is this dangerous? In other words, is the "=" always appended, or only in certain cases?

I want my encoded string to be as short as possible, that's why I want to know if I can always remove the "=" character and just add it back before decoding.

Base64 Solutions


Solution 1 - Base64

The = is padding.

Wikipedia says

> An additional pad character is > allocated which may be used to force > the encoded output into an integer > multiple of 4 characters (or > equivalently when the unencoded binary > text is not a multiple of 3 bytes) ; > these padding characters must then be > discarded when decoding but still > allow the calculation of the effective > length of the unencoded text, when its > input binary length would not be a > multiple of 3 bytes (the last non-pad > character is normally encoded so that > the last 6-bit block it represents > will be zero-padded on its least > significant bits, at most two pad > characters may occur at the end of the > encoded stream).

If you control the other end, you could remove it when in transport, then re-insert it (by checking the string length) before decoding.
Note that the data will not be valid Base64 in transport.

Also, Another user pointed out (relevant to PHP users): >Note that in PHP base64_decode will accept strings without padding, hence if you remove it to process it later in PHP it's not necessary to add it back. – Mahn Oct 16 '14 at 16:33

So if your destination is PHP, you can safely strip the padding and decode without fancy calculations.

Solution 2 - Base64

I wrote part of Apache's commons-codec-1.4.jar Base64 decoder, and in that logic we are fine without padding characters. End-of-file and End-of-stream are just as good indicators that the Base64 message is finished as any number of '=' characters!

The URL-Safe variant we introduced in commons-codec-1.4 omits the padding characters on purpose to keep things smaller!

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

I guess a safer answer is, "depends on your decoder implementation," but logically it is not hard to write a decoder that doesn't need padding.

Solution 3 - Base64

In JavaScript you could do something like this:

// 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, '/');

See also this Fiddle: http://jsfiddle.net/7bjaT/66/

Solution 4 - Base64

= is added for padding. The lenght of a base64 string should be multiple of 4, so 1 or 2 = are added as necessary.

Read: No, you shouldn't remove it.

Solution 5 - Base64

On Android I am using this:

Global

String CHARSET_NAME ="UTF-8";

Encode

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);

equals this on Java:

Encode

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);
}

I had never problems with trailing "=" and I am using Bouncycastle as well

Solution 6 - Base64

If you're encoding bytes (at fixed bit length), then the padding is redundant. This is the case for most people.

Base64 consumes 6 bits at a time and produces a byte of 8 bits that only uses six bits worth of combinations.

If your string is 1 byte (8 bits), you'll have an output of 12 bits as the smallest multiple of 6 that 8 will fit into, with 4 bits extra. If your string is 2 bytes, you have to output 18 bits, with two bits extra. For multiples of six against multiple of 8 you can have a remainder of either 0, 2 or 4 bits.

The padding says to ignore those extra four (==) or two (=) bits. The padding is there tell the decoder about your padding.

The padding isn't really needed when you're encoding bytes. A base64 encoder can simply ignore left over bits that total less than 8 bits. In this case, you're best off removing it.

The padding might be of some use for streaming and arbitrary length bit sequences as long as they're a multiple of two. It might also be used for cases where people want to only send the last 4 bits when more bits are remaining if the remaining bits are all zero. Some people might want to use it to detect incomplete sequences though it's hardly reliable for that. I've never seen this optimisation in practice. People rarely have these situations, most people use base64 for discrete byte sequences.

If you see answers suggesting to leave it on, that's not a good encouragement if you're simply encoding bytes, it's enabling a feature for a set of circumstances you don't have. The only reason to have it on in that case might be to add tolerance to decoders that don't work without the padding. If you control both ends, that's a non-concern.

Solution 7 - Base64

If you're using PHP the following function will revert the stripped string to its original format with proper padding:

<?php

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

echo $str, "\n";

Solution 8 - Base64

Using Python you can remove base64 padding and add it back like this:

from math import ceil

stripped = original.rstrip('=')

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

Solution 9 - Base64

Yes, there are valid use cases where padding is omitted from a Base 64 encoding.

The JSON Web Signature (JWS) standard (RFC 7515) requires Base 64 encoded data to omit padding. It expects:

> Base64 encoding [...] with all trailing '=' characters omitted (as permitted by Section 3.2) and without the inclusion of any line breaks, whitespace, or other additional characters. Note that the base64url encoding of the empty octet sequence is the empty string. (See Appendix C for notes on implementing base64url encoding without padding.)

The same applies to the JSON Web Token (JWT) standard (RFC 7519).

In addition, Julius Musseau's answer has indicated that Apache's Base 64 decoder doesn't require padding to be present in Base 64 encoded data.

Solution 10 - Base64

I do something like this with java8+

private static String getBase64StringWithoutPadding(String data) {
	if(data == null) {
		return "";
	}
	Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
	return encoder.encodeToString(data.getBytes());
}

This method gets an encoder which leaves out padding.

As mentioned in other answers already padding can be added after calculations if you need to decode it back.

Solution 11 - Base64

For Android You may have trouble if You want to use android.util.base64 class, since that don't let you perform UnitTest others that integration test - those uses Adnroid environment.

In other hand if You will use java.util.base64, compiler warns You that You sdk may to to low (below 26) to use it.

So I suggest Android developers to use

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

Encoding object

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
}

Decoding to Object

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)
}

Of course You may omit Gson parsing and put straight away into method Your String transformed to ByteArray

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteve NView Question on Stackoverflow
Solution 1 - Base64SLaksView Answer on Stackoverflow
Solution 2 - Base64Julius MusseauView Answer on Stackoverflow
Solution 3 - Base64magikMakerView Answer on Stackoverflow
Solution 4 - Base64Juan Pablo CalifanoView Answer on Stackoverflow
Solution 5 - Base64PwnstarView Answer on Stackoverflow
Solution 6 - Base64jgmjgmView Answer on Stackoverflow
Solution 7 - Base64supersanView Answer on Stackoverflow
Solution 8 - Base64sirexView Answer on Stackoverflow
Solution 9 - Base64EricView Answer on Stackoverflow
Solution 10 - Base64Vikas TawniyaView Answer on Stackoverflow
Solution 11 - Base64murtView Answer on Stackoverflow