开发者工具 · Base64 编码器和解码器
Base64 填充解释:= 符号的含义以及何时需要它们
· 工作原理
base64 编码 开发人员工作流程
Base64 字符串末尾的 = 不是装饰:它记录最后一组短了多少字节。这篇文章解释了算术,为什么有些字符串没有,以及为什么解码器不同意缺少填充。
看起来不错的令牌中的“不正确的填充”异常 - 解码失败及其后面的一两个缺失字符
当 Base64 解码器报告填充不正确时,字符串看起来完整,但带有结构错误。等号不是装饰性的:每个等号都编码最后一组短了多少字节,使解码器能够准确地知道实际数据何时结束。理解这些 = 符号——以及为什么严格的解码器会拒绝没有它们的字符串——将一个神秘的错误转化为可预测的算术。 JWT 段可能有一个 =、没有或两个。 API 响应可能会干净地结束而无需填充。
这些代表有意的选择,而不是实现变体。解码过程不需要机械填充。填充的存在是为了使输出明确:仅给出一个没有有关长度的元数据的 Base64 字符串,解码器读取填充并确切地知道数据结束的位置。 Base64 将三个字节组编码为四个字符。三个字节是 24 位,完美地重新组合成四个 6 位索引;每个选择 64 Base64 符号之一。当输入不是三的倍数时,编码器面临剩余:一个或两个字节不能被三整除。
三个字节组,四个字符块 — 为什么输入长度模 3 决定是否出现零、一个或两个 = 符号
编码器通过将位移入第一个索引来填充这些组,使最终值为零。为了标记这一意图,它附加了 = 符号:零表示完整的组,一表示两字节的结尾,两个表示一字节的结尾。该算法是确定性的:知道输入长度(以字节为单位)可以让您立即计算填充。一个字节产生两个 Base64 字符加上两个 =。两个字节产生三个字符加上一个=。三个字节产生四个没有填充的字节。
任何不是三个字节倍数的输入都将有填充;任何一个倍数都不会。这不是选择——这是算术。没有填充的字符串必须表示三个字节。一个等于 1 的字符串必须代表 2。填充对输入长度模三进行编码。检查三个输入的变换:单个 a、对 ab、三重 abc。 ASCII a 是字节 0x61; Base64 将其编码为 0x61 00 00,重新分组为六位组。
填充位包含什么以及为什么严格的解码器会检查它们 - 必须为零的位以及规范编码的含义
索引 24、4、0、0 映射到 Y、E、A、A。因为两个组进行了填充,所以编码器附加两个 = 符号,产生 YQ==。对于 ab,字节 0x61 0x62 变为 0x61 0x62 00。位重新组合为索引 24、22、8、0,输出 YWI=。对于 abc,字节重新组合为索引 24、22、9、35,输出 YWJj,无填充。填充不是任意的:它不符合位布局。当您解码 Base64 字符串时,解码器会读取每个字符,查找其六位索引,将位打包为字节。
对于 YQ==,字符 Y、E、A、A 解压缩为位。重新组合成八位字节得到一个字节,0x61。解码器丢弃填充位(尾随零)并报告一个字节。严格的解码器检查填充位实际上为零;如果不是,则输入不规范,这意味着有人使用不同的位布局进行编码,并且解码是不明确的。完全省略填充的系统会做出有意的权衡。 JWT 段使用 Base64url 而不进行填充,依赖于消费者了解预期输出长度或推断它。
工作示例:手动编码 'a'、'ab' 和 'abc' — 三个输入、三个填充结果,逐位显示
RFC 4648 允许填充不存在,但指示解码器接受它(如果存在)。代码库有所不同:有些会恢复丢失的填充并继续;有些会恢复丢失的填充并继续;其他人会失败。当您遇到解码失败的标记时,附加正确数量的 = 符号通常可以修复它。必需的 = 符号始终为零、一或二,具体取决于字符串长度模四。如果 Base64 字符串长度不是四的倍数,则填充肯定丢失或损坏。
长度 5 不能是有效的 Base64:每个完整字符编码六位,因此四个字符编码 24 位(三个字节),五个字符编码 30 位,它不是八的倍数,不能成为字节。解码器必须拒绝此操作或添加填充。如果长度为 2 模 4,则添加两个 =。如果 3 对 4 取模,则加一 =。如果 0 对 4 取模,则不添加任何内容。长度为 3 的字符串缺少它需要的 = ;加一,解码前生效。
为什么有些系统完全删除填充 — JWT 段和省略 = 的 URL 安全标记以及如何从长度恢复它
如果填充留在原处,则连接两个填充的 Base64 字符串会损坏。连接的两个单独的编码直接产生杂散填充字符,从而破坏解码字母表。这就是为什么某些系统在连接之前去除填充的原因:由三个点连接的 Base64url 段组成的令牌在段内没有填充,从而使连接变得简单。如果从各个部分构建 Base64 值,请在任何操作之前验证每个部分是否已填充并一致地剥离或添加填充。
Base64 编码器和解码器应用 RFC 4648,默认情况下需要填充。当您输入文本并请求 Base64 输出时,该工具会生成填充结果:规范形式。如果您看到没有填充的 Base64 并想要对其进行解码,请检查您的解码器是否接受缺少填充。该工具接受填充和未填充的输入,并正确恢复原始字节。为了进行调试,对长度模四进行计数会告诉您填充是否被剥离,并且公式会告诉您应该存在什么填充。
常见错误:修剪 = 就好像它是空格一样,或连接两个填充的字符串 - 每个字符串如何破坏解码
Base32 和 Base16(十六进制)在 RFC 4648 部分 6 和 7 中定义了不同的填充规则。 Base32 使用 =,但最终组可以是 2、4、5、7 或 8 字符,具体取决于输入长度模五。十六进制不需要填充;它总是将一个字节映射到两个字符,没有余数。 MIME Base64 换行涉及填充:76 列换行的字符串在最后几行仍然有填充。
了解 Base64 的填充就是了解位布局和输入长度模三;一旦你看到算术,填充就成为一个直接的结果,而不是一个需要记住的规则。填充是可导出的,而不是神奇的。
这不包括什么 - base32 和 base16 填充规则,以及 MIME 行长度约定
给定任意长度的 Base64 字符串,您可以通过将字符数除以四、取余数并附加相应数量的 = 符号来恢复规范的填充形式。这就是为什么缺少 = 是可以修复的,也是为什么严格的解码器可以宽容的原因:填充携带信息(您的输入属于三种情况的哪个分支),但该信息可以仅根据长度来计算。
Base64 编码器和解码器立即显示填充输出,以便您可以将解码后的字节与原始文本进行比较并验证往返是否有效。 Base64 和相关编码扩展了将位重新分组为不同字符宽度的原理。 RFC 4648 指定了这三者,理解其中之一会使其他概念在概念上变得简单。关键的见解是编码是纯粹的位操作:选择字母大小,相应地对位进行分组,在表中查找每个组。
要点:填充是可推导的,因此缺失的 = 是可以修复的 — Base64 编码器和解码器如何向您显示您编码的任何文本的填充规范形式
解码相反:查找每个字符,提取位,重新组合它们,写入字节。这种确定性的双向映射就是 Base64 在所有平台和语言上可靠工作的原因。编码和解码中的错误通常归因于对填充或字母差异的误解。如果解码因填充错误而失败,请检查解码器是否需要规范的 Base64(严格填充)或接受变体。如果由于字符错误而失败,请检查输入是否为 base64url 以及解码器是否需要标准 Base64。
Base64 编码器和解码器接受字母并一致地验证填充,因此可以立即验证任何手工计算的示例。通过解码回来测试编码是在错误导致生产问题之前发现错误的最可靠方法。