代码之家  ›  专栏  ›  技术社区  ›  Anand Patel

如果输入长度不能被3整除,为什么base64编码需要填充?

  •  54
  • Anand Patel  · 技术社区  · 14 年前

    在base64编码中填充的目的是什么。以下是维基百科的摘录:

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

    我写了一个程序,可以base64编码任何字符串和解码任何base64编码字符串。填充可以解决什么问题?

    3 回复  |  直到 7 年前
        1
  •  180
  •   TJM    9 年前

    你认为填充是不必要的结论是正确的。总是可以从编码序列的长度中明确地确定输入的长度。

    然而,填充在base64编码的字符串以丢失单个序列长度的方式连接的情况下是有用的,例如,在非常简单的网络协议中可能会发生这种情况。

    如果 取消添加 字符串是串联的,不可能恢复原始数据,因为每个序列末尾奇数字节数的信息丢失。但是,如果使用填充序列,就不会产生歧义,而且整个序列可以正确解码。

    编辑:插图

    假设我们有一个程序,base64对单词进行编码、连接并通过网络发送它们。它对“I”、“AM”和“TJM”进行编码,将结果不加填充地夹在一起并进行传输。

    • I 编码到 SQ SQ== 带衬垫)
    • AM 编码到 QU0 ( QU0= 带衬垫)
    • TJM 编码到 VEpN 维普 带衬垫)

    SQQU0VEpN . 接收器base64将其解码为 I\x04\x14\xd1Q) IAMTJM . 结果是无稽之谈,因为发件人 在编码的序列中。如果发送者发送了 SQ==QU0=VEpN IAMTJM公司 .

    为什么不设计一个协议,在每个单词前面加上一个整数长度呢?然后接收器可以正确解码流,不需要填充。

    知道 开始编码之前我们正在编码的数据的长度。但是,如果我们不是用文字,而是用现场摄像机来编码视频片段呢?我们可能事先不知道每一块的长度。

    如果协议使用padding,则根本不需要传输长度。当数据从摄像机输入时,可以对其进行编码,每个块以填充结束,接收器将能够正确解码流。

    显然,这是一个非常做作的例子,但也许它说明了为什么填充在某些情况下可能会有帮助。

        2
  •  33
  •   Zamicol    5 年前

    https://convert.zamicol.com/

    什么是填充字符?

    填充字符有助于满足长度要求,并且没有任何意义。

    如果任意要求所有字符串的长度都是8个字符,则数字640可以使用前面的0作为填充字符来满足此要求,因为它们没有意义,“00000640”。

    二进制编码

    字节范式: 字节是事实上的标准度量单位,任何编码方案都必须与字节相关。

    基256

    基数16

    基数64 与base256和base16不同,它不能均匀地适应字节范式(base32也不能)。所有base64字符都可以用6位表示,比完整字节少2位。

    我们可以用分数表示base64编码与字节范式: . 减少的这个分数是3字节超过4个字符。

    Base64编码只能保证即使使用3字节束进行测量, 与base16和base256不同,base16和base256的每个字节都可以独立存在。

    所以 即使编码在没有填充字符的情况下也可以正常工作,是否鼓励填充?

    作为反例,有些标准 JOSE 不允许填充字符。在这种情况下,如果缺少某些内容,加密签名将不起作用,或者其他非base64字符将丢失(如“.”)。虽然没有对长度进行假设,但不需要填充,因为如果出现错误,填充就不起作用。

    这正是 base64

    在某些情况下,在基本编码数据中使用填充(“=”) 不需要或不使用。在一般情况下,当假设 无法确定传输数据的大小,需要填充 产生正确的解码数据。

    基64中的填充步骤[…]如果不正确 实现时,会导致编码数据的非显著更改。 然后使用第一个符号的所有六位,但只使用第一个 使用下一个符号的两位。这些焊盘位必须设置为 通过一致的编码器归零,如描述中所述 在下面的垫子上。如果这个财产不存在,就没有 基编码数据和多个基的规范表示- 编码的字符串可以解码为相同的二进制数据。如果这个 属性(以及本文档中讨论的其他属性)持有 保证编码。

    实例

    以下是RFC4648表格示例( 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

        3
  •  2
  •   Roman Starkov    13 年前

    这只是我的一个理论,我不能提供任何来源,但我认为填充字符只能用来 一些实现 最小的 简单一点。特别是,如果算法将编码字符串放入 int[] 最后的值有时会太长。

    但是,如果不允许算法假设填充存在, 它使用 整数[] -就像数据结构一样, 它需要在解码前手动填充最后一个整数,或者对输入的原始长度做一些额外的记账。

    我个人认为填充不再起任何作用,但回到CPU和RAM不够丰富的时候,这个小小的优化可能已经很重要了。但我怀疑这有多重要。。。当fed输入被随机截断时,一个好的实现仍然需要做一些明智的事情,而IMO将提供处理未添加的输入的能力,而不需要额外的成本。