在base64编码时删除尾随"="

Ste*_*e N 43 base64

我注意到每当我对base64进行编码时,最后会附加一个"=".我可以删除这个字符然后通过添加它来可靠地解码它,或者这是危险的吗?换句话说,是否总是附加"=" ,或仅在某些情况下?

我希望我的编码字符串尽可能短,这就是为什么我想知道我是否总能删除"="字符并在解码之前将其添加回来.

SLa*_*aks 61

=是填充.

维基百科

分配一个额外的填充字符,可用于强制编码输出为4个字符的整数倍(或等效地,当未编码的二进制文本不是3个字节的倍数时); 这些填充字符必须在解码时丢弃,但仍允许计算未编码文本的有效长度,当其输入二进制长度不是3字节的倍数时(最后一个非填充字符通常编码为最后一个)它表示的6位块将在其最低有效位上进行零填充,在编码流的末尾最多可能出现两个填充字符.

如果您控制另一端,则可以在传输时将其删除,然后在解码之前重新插入(通过检查字符串长度).
请注意,数据在传输中不是有效的Base64.

  • @Steve:如果长度不是4个字符的倍数,则添加`=`字符,直到它为止.在.NET中,如果`(!str.Length%4 = 0)STR + =新的字符串( '=',4 - str.Length%4)` (43认同)
  • 请注意,在PHP中,`base64_decode`将接受字符串*而不使用*padding,因此如果您将其删除以便稍后在PHP中处理它,则无需将其添加回来. (14认同)
  • 就像@Mahn提到的那样,即使Javascript的atob()函数也不需要填充来成功解码base64编码的字符串 (3认同)

Jul*_*eau 24

我编写了Apache的commons-codec-1.4.jar Base64解码器的一部分,在那个逻辑中我们没有填充字符.文件结束和流结束就像Base64消息完成任意数量的'='字符一样好!

我们在commons-codec-1.4中引入的URL-Safe变体省略了填充字符以保持较小的内容!

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

我想一个更安全的答案是"取决于你的解码器实现",但从逻辑上讲,编写一个不需要填充的解码器并不困难.


mag*_*ker 23

在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, '/');
Run Code Online (Sandbox Code Playgroud)

另见这个小提琴:http://jsfiddle.net/7bjaT/66/


Jua*_*ano 9

=添加用于填充.base64字符串的长度应为4的倍数,因此=根据需要添加1或2 .

阅读:不,你不应该删除它.


Spe*_*ius 5

在Android上我使用这个:

全球的

String CHARSET_NAME ="UTF-8";
Run Code Online (Sandbox Code Playgroud)

编码

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

解码

byte[] bytes = Base64.decode(base64String,
            Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP);
Run Code Online (Sandbox Code Playgroud)

在 Java 上等于这个:

编码

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

解码

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

我从来没有遇到过拖尾“=”的问题,而且我也在使用 Bouncycastle


jgm*_*jgm 5

如果您对字节进行编码(以固定位长度),则填充是多余的。大多数人都是这样。

Base64 一次消耗 6 位并生成 8 位的字节,仅使用 6 位的组合。

如果您的字符串是 1 字节(8 位),那么您将得到 12 位的输出,作为 6 的最小倍数,其中 8 可以容纳,另外还有 4 位。如果您的字符串是 2 个字节,则必须输出 18 位,并额外输出 2 位。对于 6 的倍数与 8 的倍数,您可以得到 0、2 或 4 位的余数。

填充表示忽略那些额外的四个 (==) 或两个 (=) 位。填充在那里告诉解码器你的填充。

当您对字节进行编码时,实际上并不需要填充。Base64 编码器可以简单地忽略总计少于 8 位的剩余位。在这种情况下,您最好将其删除。

填充对于流式传输和任意长度的位序列可能有一定用处,只要它们是 2 的倍数即可。它也可以用于这样的情况:当剩余位全部为零时,人们只想发送最后 4 位,而还有更多位。有些人可能想用它来检测不完整的序列,尽管它对此不太可靠。我在实践中从未见过这种优化。人们很少有这些情况,大多数人使用 base64 来表示离散字节序列。

如果您看到建议将其保留的答案,那么如果您只是对字节进行编码,那么这不是一个好的鼓励,它会为您没有的一组情况启用一项功能。在这种情况下启用它的唯一原因可能是增加对没有填充就无法工作的解码器的容忍度。如果你控制了两端,那就不用担心了。