为什么下面的代码
var s = "2I==";
var b = Convert.FromBase64String(s);
var new_s = Convert.ToBase64String(b);到头来new_s是2A==
s最初是一个较长的字符串(96个字符),但我无法包含它,因为它是一个秘密密钥。
发布于 2015-03-26 20:19:02
"2I==“表示数字54、8 (填充x2),按维基百科表示。
换言之,所代表的双边投资条约是:
110110 000100 XXXXXX XXXXXX(其中X代表“我不在乎,它来自填充”)
但是,由于填充表明这里只有一个字节的信息,第二个字符的最后4位与此无关。与以往一样,我们可以将4段6位信息重新格式化为3段8位信息,此时它变得更加清晰:
11011000 0100XXXX XXXXXXXX您可以看到,第二个字节必须是填充的,因为它的一些位来自填充字符。因此,只有第一个字符和第二个字符的前两位是相关的-它只对单个字节0b11011000进行解码。
现在,当您编码0b11011000时,您知道您将有两个填充字符,第一个字符必须是'2‘(表示位'110110'),但第二个字符可以是其前两个位表示'00’的任何字符。碰巧Convert.ToBase64String使用'A',它对不相关的部分有0位。
我脑海中的问题是为什么编码器会选择使用“I”而不是“A”。我不认为在Base64中这样做是无效的,但这是一个奇怪的选择。
发布于 2015-03-26 20:42:01
乔恩·斯基特为观察到的行为提供了一个很好的解释。但是,在Base64的大多数定义中,输入字符串将被视为无效。这些标准包括以下案文:
当输入组中可用的输入位数少于24个时,将值为零的比特(在右边)相加,形成一个6位组的整数。
RFC 4648进一步强调了这一点:
基座64和基32编码中的填充步骤如果实现不当,可以导致编码数据的非显着更改。例如,如果输入仅为基64编码的一个八进制,则使用第一个符号的所有六个比特,但只使用下一个符号的前两个比特。这些垫位必须设置为零通过符合编码器..。如果衬垫位尚未设置为零,解码器可以选择拒绝编码。
我们可以假设您的原始输入由一个具有值216 (0xD8)的字节组成。二进制数:
11011000这需要分成6位组:
110110 00而且,根据上面引用的定义,最后一组需要填充零:
110110 000000根据Base64字母表,110110 (十进制:54)映射到字符2,而000000 (十进制:0)映射到字符A。添加=填充以获得24位组,最终结果将是2A==。这是原始输入的唯一有效编码。
https://stackoverflow.com/questions/29287892
复制相似问题