在base64编码时删除尾随“=”

时间:2010-12-20 18:01:30

标签: base64

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

我希望我的编码字符串尽可能短,这就是为什么我想知道我是否可以随时删除“=”字符并在解码前将其添加回来。

11 个答案:

答案 0 :(得分:58)

=是填充。

Wikipedia

  

另一个填充字符是   分配可用于强迫   编码输出为整数   4个字符的倍数(或   当未编码的二进制文件时等效   text不是3个字节的倍数);   这些填充字符必须是   解码时丢弃但仍然丢弃   允许计算有效   未编码文本的长度,当它的时候   输入二进制长度不是a   3个字节的倍数(最后一个非填充   字符通常编码,以便   它代表的最后一个6位块   至少是零填充   有效位,最多两个pad   字符可能出现在结尾处   编码流)。

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

答案 1 :(得分:22)

我编写了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

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

答案 2 :(得分:21)

在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/

答案 3 :(得分:8)

为填充添加了

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

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

答案 4 :(得分:3)

在Android上我使用的是:

全局

plot(t_in,DSB,'g')

<强>编码

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

在Java上等于这个:

<强>编码

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

<强>解码

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

我从来没有遇到跟踪问题&#34; =&#34;我也在使用Bouncycastle

答案 5 :(得分:1)

如果您使用的是PHP,则以下函数将使用适当的填充将剥离的字符串恢复为其原始格式:

<?php

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

echo $str, "\n";

答案 6 :(得分:0)

使用Python,您可以删除base64填充并像这样将其重新添加:

from math import ceil

stripped = original.rstrip('=')

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

答案 7 :(得分:0)

如果您要编码字节(以固定位长),则填充是多余的。大多数人就是这种情况。

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

如果您的字符串是1字节(8位),您将输出12位,这是8可以容纳的6的最小倍数,另外还有4位。如果您的字符串是2个字节,则必须输出18位,并多输出两位。对于6的倍数对8的倍数,您可以保留0、2或4位的余数。

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

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

只要是2的倍数,填充对于流和任意长度的位序列可能会有一些用处。它也可以用于以下情况:如果剩余的位都为零,则当剩余的位更多时,人们只希望发送最后的4位。某些人可能想用它来检测不完整的序列,尽管这样做并不可靠。在实践中我从未见过这种优化。人们很少遇到这种情况,大多数人将base64用于离散字节序列。

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

答案 8 :(得分:0)

对于Android,如果您想使用android.util.base64类,可能会遇到麻烦,因为那不能让您执行集成测试的其他单元测试-使用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解析,直接放入将您的String转换为ByteArray的方法中

答案 9 :(得分:0)

,有一些有效的用例,其中从 Base 64 编码中省略了填充。

The JSON Web Signature (JWS) standard (RFC 7515) 需要 Base 64 编码数据以省略 填充。它期望:

<块引用>

Base64 编码 [...] 带有所有尾随 '=' 省略的字符(如第 3.2 节所允许)且没有 包含任何换行符、空格或其他额外的 人物。注意空八位字节的base64url编码 序列是空字符串。 (有关注释,请参见附录 C 实现无填充的 base64url 编码。)

这同样适用于 JSON Web Token (JWT) standard (RFC 7519)。

此外,Julius Musseau's answer 表示 Apache 的 Base 64 解码器不需要在 Base 64 编码数据中存在填充。

答案 10 :(得分:0)

我用 java8+ 做这样的事情

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

有一种方法可以得到一个忽略填充的编码器。 正如其他答案中提到的,如果您需要将其解码回来,可以在计算后添加填充。