Base64编码/解码后结果不同。

3

我有以下的base64字符串:

R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueS==

使用在线base64解码器,我得到了以下结果:

GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany

一切都好,对吧?但是现在如果我尝试将这段文本转换回Base64 - 结果就变成了

R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueQ==

有什么想法吗?

这是我用于解码的C#代码:

string basestring = "R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueS==";

string output = Encoding.UTF8.GetString(Convert.FromBase64String(basestring));

return output;

这里是编码部分

string basestring = "GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany";

string output = Convert.ToBase64String(Encoding.UTF8.GetBytes(basestring));

return output;

2
相关问题,可能是重复的:一个base64编码的字符串是否唯一? - Brian61354270
我删除了加密标签,因为这个问题与加密无关。 - Brian61354270
听起来像是其中一个编码器正在使用未初始化的变量。但在实践中应该没有关系。 - Jeremy Lakeman
1个回答

3

这实际上是从8位编码(UTF8)转换为6位编码(Base64)的结果。
参考此处的Base64编码表

我们以字符串"AB"为例;AB分别是字符(6566)。在8位二进制编组中,65/66为01000001/01000010

编码

当进行Base64编码时,与您的字符串相同的位被分成6个一组,而不是8个。因此,上面的相同16位序列被分成010000/010100/0010(相同的位模式,只是分组方式不同)。

现在,前两组很容易。查找上面链接的编码表,您会看到010000=Q/010100=U。然后您有最后一组,其中仅有4位,而不是预期的6位。这就是事情变得有趣的地方。

编码时,通常会用零填充结尾以达到6位。因此,您的0010变成了001000,即I。因此,在Base64中编码时,"AB"变成了"QUI="=是可选的,只是为了使字符数成为4的倍数。

解码

记得当您最后一组0010被填充为6位时吗?这里有趣的部分:它们不必是零。由于填充,原始字符串中的16位(2x8)变为18位(3x6)。由于18不是8(位)的倍数,编码器/解码器知道足够丢弃多余的位。因此,两个位填充可以是任何,它们仍然可以正确解码。

0010在填充后可以是001000001001001010001011 - 这些分别对应于I,J,K或L。打开任何解码器,尝试解码QUIQUJQUKQUL。它们都将解码为"AB"

您的字符串

现在,当您的字符串被分成6位组时,它看起来像下面这样(请参见fiddle):

var basestring = "GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany";
var sixBitGroups = Encoding.UTF8.GetBytes(basestring)
  .SelectMany(b => $"{Convert.ToString(b, 2).PadLeft(8,'0')}")
  .Chunk(6)
  .Select(c => new string(c.ToArray()));
string.Join("/", sixBitGroups).Dump();

你会注意到它以 ../01 结尾。那个 01 需要用 4 个额外的比特位填充。通常情况下,它们是零,使其变成 010000,即为Q。因此,你会看到你的编码字符串以 ..FueQ== 结尾。但当你意识到它们不一定都是零时,你会在表格中看到01xxxx 包括从Q、R、S、..i、j 的所有内容。这就解释了为什么你的base64 ..FueS== 解码后仍然得到相同的字符串。


很好,谢谢你提供如此深入的答案,将来肯定会有帮助! - Tomas Dovidavičius
这只是一个侧面的注释:如果能生成并发送大量的base64字符串,那么这些填充位可能会被滥用来发送隐藏信息。 - Oliver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接