Python:在base64解码时忽略'Incorrect padding'错误

201 投票
23 回答
461261 浏览
提问于 2025-04-15 23:22

我有一些数据是用base64编码的,我想把它转换回二进制格式,即使里面有填充错误。如果我使用

base64.decodestring(b64_string)

就会出现“填充不正确”的错误。有没有其他的方法呢?

更新:感谢大家的反馈。说实话,提到的所有方法听起来都有点不靠谱,所以我决定试试openssl。下面这个命令效果很好:

openssl enc -d -base64 -in b64string -out binary_data

23 个回答

55

只需根据需要添加一些内边距。不过,要注意迈克尔的警告。

b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh
105

正如其他回答所说,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

163

看起来你只需要在解码之前给你的字节加上填充。关于这个问题有很多其他的回答,但我想特别提一下(至少在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 错误。

根据 文档

如果 validateFalse(默认值),在检查填充之前,会丢弃那些不在正常base-64字母表或替代字母表中的字符。如果 validateTrue,输入中的这些非字母字符会导致 binascii.Error

不过,如果 validateFalse(或者留空使用默认值),你可以随意加两个填充字符,完全没有问题。感谢eel ghEEz在评论中指出这一点。

撰写回答