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

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

“分配了一个附加的填充字符,可以用来强制编码的输出为4个字符的整数倍(或者等同于未编码的二进制文本不是3个字节的倍数);这些填充字符在解码时必须丢弃,仍然允许计算未编码文本的有效长度,当其input二进制长度不会不是3字节的倍数时(最后一个非填充字符通常被编码,以致它表示的最后6位块将是零在其最低有效位上填充,最多两个填充字符可能出现在编码stream的末尾)“。

我写了一个程序,可以base64编码任何string,并解码任何base64编码的string。 填充解决什么问题?

你的结论,填充是不必要的是正确的。 总是可以从编码序列的长度明确地确定input的长度。

但是,在base64编码的string以这种方式连接在一起的情况下,填充是有用的,例如在一个非常简单的networking协议中,单个序列的长度会丢失。

如果未压缩的string连接在一起,则不可能恢复原始数据,因为有关每个单独序列末尾的奇数字节数的信息将丢失。 但是,如果使用填充序列,则没有歧义,整个序列可以正确解码。

编辑:插图

假设我们有一个基于64位编码的程序,将它们连接在一起并通过networking发送。 它编码“I”,“AM”和“TJM”,将结果夹在一起而不填充并传送。

  • I编码为SQSQ==填充)
  • AM编码为QU0QU0=带填充)
  • TJM编码为VEpN (带填充的VEpN

所以传输的数据是SQQU0VEpN 。 接收器I\x04\x14\xd1Q)解码为I\x04\x14\xd1Q)而不是预期的IAMTJM 。 结果是无意义的,因为发送者已经破坏了关于每个词在编码序列中结束的信息 。 如果发送者发送了SQ==QU0=VEpN ,接收者可以将其解码为三个单独的base64序列,这些序列将连接成IAMTJM

为什么要填充?

为什么不只是devise协议前缀每个单词的整数长度? 然后接收机可以正确解码stream,不需要填充。

只要我们知道我们编码之前编码的数据的长度,这是个好主意。 但是,如果不是用文字来说,我们是用实时相机对video进行编码的呢? 我们可能不知道每个块的长度。

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

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

什么是填充字符?

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

填充的十进制例子:给定任意要求,所有string的长度是8个字符,数字640可以满足这个要求,使用前面的0作为填充字符,因为它们不带有意义“00000640”。

二进制编码

字节范例:字节是事实上的标准测量单位,任何编码scheme都必须与字节相关联。

Base256完全符合这个范例。 一个字节等于base256中的一个字符。

Base16 ,hex或hex,每个字符使用4位。 一个字节可以代表两个base16字符。

与base256和base16不同, Base64并不适合字节范例。 所有的base64字符都可以用6位表示,比全字节短2位。

我们可以将base64编码与字节范例表示为一个分数: 每个字节8位,每个字符6位 。 减less这个部分是3个字节超过4个字符。

这个比率,每4个base64字符3个字节,是我们编码base64时要遵循的规则。 Base64编码只能保证使用3个字节的包进行测量,不像base16和base256,每个字节都可以独立运行。

那么为什么即使编码在没有填充字符的情况下工作得很好,也会鼓励填充? 填充字符明确地沟通,那些额外的斑点应该是空的,并排除任何不明确或潜在的讨厌的错误。 填充允许我们解码base64编码,承诺没有丢失的位。 如果没有填充,就不再需要在三个字节的包中进行测量的明确的确认,而且我们也不能保证没有附加信息的原始编码的准确再现。

例子

这里是RFC 4648的例子( 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

这只是我的一个理论,我不能提供任何资源,但我认为填充字符只是使解码algorithm的一些实现 简单一点。 特别是,如果algorithm将编码的string放入类似int[]那么最终的值有时会太长。

如果填充已经存在于input中,则不需要做其他任何事情 – algorithm只能读取和解码input。

但是,如果不允许algorithm假设填充存在, 并且它使用类似于int[]的数据结构, 在解码之前需要手动填充最终的整数,或者对input的原始长度进行一些额外的簿记。

我个人认为填充不再是为了任何目的,但是当CPU和RAM不像现在那样充足时,这个微小的优化可能是非常重要的。 我怀疑这很重要,虽然…一个好的实现仍然需要做一些明智的事情,当喂养的input被随机截断,并且,国际海事组织,将能够处理无衬垫的input,没有额外的成本。