可以去掉base64字符串中的等号吗?

30 投票
7 回答
38568 浏览
提问于 2025-04-17 11:09

我有一个字符串,我把它编码成base64格式是为了节省空间。如果我把最后的等号去掉,这会有什么大问题吗?这样会大幅降低随机性吗?我该怎么做才能确保生成的字符串长度是固定的呢?

>>> base64.b64encode(combined.digest(), altchars="AB")
'PeFC3irNFx8fuzwjAzAfEAup9cz6xujsf2gAIH2GdUM='

谢谢。

7 个回答

16

去掉等号是没问题的,只要你知道它们的作用。

Base64编码每3个字节会输出4个字符,也就是说每个字符代表6个比特。填充字符是为了确保任何Base64字符串的长度总是4的倍数,这些填充字符实际上并不编码任何数据。(我不能确定为什么要这样做——是为了检查字符串是否被截断,方便解码,还是其他原因?)

无论如何,这意味着如果你有x个Base64字符(去掉填充后),那么就会有4-(x%4)个填充字符。(不过x%4=1这种情况是不会发生的,因为6和8的因数关系)。由于这些填充字符不包含实际数据,并且可以被恢复,所以我经常在想节省空间的时候把它们去掉,比如下面这样:

from base64 import b64encode, b64decode

# encode data
raw = b'\x00\x01'
enc = b64encode(raw).rstrip("=")

# func to restore padding
def repad(data):
     return data + "=" * (-len(data)%4)
raw = b64decode(repad(enc))
20

每3个字节的数据会被转换成4个ASCII字符,这个过程叫做Base64编码。为了确保编码后的字符数量总是4的倍数,如果最后的结果不够,就会用'='这个符号来填充。比如,如果你刚好有3个字节的数据,那么编码后就不会有'='符号。如果多出1个字节,编码结果的末尾就会有两个'='符号;如果多出2个字节,末尾就会有一个'='符号。根据你解码字符串的方式,可能会把这个结果当作有效的字符串,也可能不会。你提供的这个例子在解码时没有成功,但我试过的一些简单字符串是可以解码的。

如果想更深入了解Base64字符串以及编码和解码的过程,可以看看这篇文章。

http://www.nczonline.net/blog/2009/12/08/computer-science-in-javascript-base64-encoding/

网上有很多免费的编码和解码工具,你可以用来检查你的输出字符串。

18

看看你的代码:

>>> base64.b64encode(combined.digest(), altchars="AB")
'PeFC3irNFx8fuzwjAzAfEAup9cz6xujsf2gAIH2GdUM='

这里编码成base64的字符串是一个叫做 digest() 的函数的结果。如果你的digest函数产生的值是固定长度的(比如说它在计算MD5或SHA1的摘要),那么传给b64encode的参数长度总是一样的。

如果上面的说法是对的, 那么你可以去掉末尾的等号,因为它们的数量总是相同的。如果你这样做了,只需在解码之前再把相同数量的等号加回去就可以了。

如果digest的长度不是固定的,那就不安全去掉等号。

编辑: 看起来你可能在使用SHA-256摘要?SHA-256的摘要是256位(也就是32字节)。32字节可以分成10组3字节,加上剩下的2字节。正如你在维基百科关于填充的部分中看到的,这意味着你总是会有一个末尾的等号。如果是SHA-256,那去掉它是可以的,只要你记得在解码之前再加上去。

撰写回答