为什么从 Base64 转换并返回乱码会导致该字符串的末尾出现乱码?

为什么从 Base64 转换并返回乱码会导致该字符串的末尾出现乱码?

命令:

echo "HelloWorld==" | base64 -d | base64

输出:

HelloWorlQ==

为什么我d现在是a Q

编辑:

我不想从任意数据开始并对其进行 Base64 编码。我的目的是从 Base64 开始并以 Base64 结束,在此期间只生成一个二进制值。

编辑2:

我注意到,如果输入字符串是四个字符的倍数,则不会发生这种情况,所以我认为这是与填充的交互:

❯ echo 'abcdefghij==' | base64 -d | base64
abcdefghig==

❯ echo 'abcdefgh' | base64 -d | base64 
abcdefgh

编辑3

删除了令人困惑的标志提及-i,事实证明这与我的问题无关。

答案1

HelloWorld==包含无法解码的信息,并且在技术上不是有效的 Base64,因为它们通常应该被0填充。当您使用 . 时,其中包含的额外1s 将被忽略并丢失echo "HelloWorld==" | base64 -d

解释...

Base64 适用于 4 个字符的组。每个字符代表 6 位,因此每组 4 个解码为 3 个字节(每个字节 8 位)。唯一的例外是最后 4 个字符,该字符会根据符号的数量而变化=。 Base64 字符串始终能被 4 整除。

  • 0 解码为 3 字节
  • 1 = 解码为 2 字节
  • 2 == 解码为 1 字节

在你的例子中HelloWor都是有效的。但ld==事实并非如此。要了解原因,请参阅此查找表: https://en.wikipedia.org/wiki/Base64

ld==应该只解码为一个字节,因为它=末尾有两个字节。但ld解码为: 100101 011101。一个字节只有八个8位。因此,当您使用 解码字符串时base64 -d,只会100101 01将其转换为字节,并且末尾1101将被完全忽略。

任何以 结尾的 Base 64 字符串==必须仅使用最后一个字符的前两位。这是唯一有效的结尾==Q== A== w== g==

答案2

是的,这是与填充的交互。

让我们通过解码来查看您的实际编码数据,并且(因为它不是 ASCII 字符串)将其转换为二进制:

$ base64 -d <<<'HelloWorld==' | xxd -b
00000000: 00011101 11101001 01100101 10100001 01101010 00101011  ..e.j+
00000006: 10010101                                               .

HelloWorld==这是经过 Base64 编码的数据。菲利普·库林解释了最后部分解码的复杂性,并且在某种程度上,在解码数据时实际上ld==仅使用了由 编码的数据的三分之一。d下面我将展示Q重新编码数据时的来源。

让我们重复一下这个二进制文件:

00011101 11101001 01100101 10100001 01101010 00101011 10010101

以六位为一组(这是 Base64 编码器将使用的):

000111 011110 100101 100101 101000 010110 101000 101011 100101 01

最后用四个零位填充以形成 10 个完整的 6 位代码:

000111 011110 100101 100101 101000 010110 101000 101011 100101 010000

010000Q您重新编码数据时看到的(请参阅Base64 代码表)。

答案3

管道不整齐。您应该先编码,然后再解码。

$ echo "Hello World!==" | base64 | base64 -id
Hello World!==

您正在解码无效的 Base64 编码格式。

相关内容