Python:在base64解码时忽略'Incorrect padding'错误
我有一些数据是用base64编码的,我想把它转换回二进制格式,即使里面有填充错误。如果我使用
base64.decodestring(b64_string)
就会出现“填充不正确”的错误。有没有其他的方法呢?
更新:感谢大家的反馈。说实话,提到的所有方法听起来都有点不靠谱,所以我决定试试openssl。下面这个命令效果很好:
openssl enc -d -base64 -in b64string -out binary_data
23 个回答
只需根据需要添加一些内边距。不过,要注意迈克尔的警告。
b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh
正如其他回答所说,base64数据可能会以多种方式被损坏。
不过,正如维基百科所提到的,去掉填充(也就是base64编码数据末尾的'='字符)是“无损”的:
从理论上讲,填充字符并不是必需的,因为可以通过Base64数字的数量来计算缺失的字节数。
所以,如果你的base64数据真的只是这个“问题”,那么填充可以直接加回来。我想出了这个方法来解析WeasyPrint中的“data”网址,其中一些是没有填充的base64:
import base64
import re
def decode_base64(data, altchars=b'+/'):
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
data = re.sub(rb'[^a-zA-Z0-9%s]+' % altchars, b'', data) # normalize
missing_padding = len(data) % 4
if missing_padding:
data += b'='* (4 - missing_padding)
return base64.b64decode(data, altchars)
这个函数的测试可以在这里找到:weasyprint/tests/test_css.py#L68
看起来你只需要在解码之前给你的字节加上填充。关于这个问题有很多其他的回答,但我想特别提一下(至少在Python 3.x中),base64.b64decode
会自动去掉任何多余的填充,只要最开始有足够的填充。
所以,像 b'abc='
这样的字符串和 b'abc=='
一样有效(b'abc====='
也是)。
这意味着你只需要加上最多需要的填充字符,也就是两个(b'=='
),然后base64会自动去掉不必要的部分。
这样你就可以写:
base64.b64decode(s + b'==')
这比:
base64.b64decode(s + b'=' * (-len(s) % 4))
要简单多了。
注意,如果字符串 s
已经有一些填充(比如 b"aGVsbG8="
),这种方法只有在 validate
这个参数设置为 False
(默认就是这个)时才有效。如果 validate
设置为 True
,那么如果填充总长度超过两个字符,就会抛出一个 binascii.Error
错误。
根据 文档:
如果 validate 是
False
(默认值),在检查填充之前,会丢弃那些不在正常base-64字母表或替代字母表中的字符。如果 validate 是True
,输入中的这些非字母字符会导致binascii.Error
。
不过,如果 validate
是 False
(或者留空使用默认值),你可以随意加两个填充字符,完全没有问题。感谢eel ghEEz在评论中指出这一点。