Python:进行base64解码时忽略“错误填充”错误

问题描述 投票:92回答:14

我有一些base64编码的数据,即使其中存在填充错误,我也想将其转换回二进制。如果我使用

base64.decodestring(b64_string)

会引发“错误填充”错误。还有其他方法吗?

更新:感谢您的所有反馈。老实说,提到的所有方法听起来都有些打击和小姐,所以我决定尝试openssl。下面的命令有效了:

openssl enc -d -base64 -in b64string -out binary_data
python base64
14个回答
76
投票

如在其他答复中所述,有多种方法可以破坏base64数据。

但是,正如[C​​0]所说,删除填充(base64编码数据末尾的'='字符是“无损”:]

[从理论上讲,不需要填充字符,因为可以从数量中计算出丢失的字节数的Base64位数字。

因此,如果这真的是唯一的base64数据“错误”的内容,则只需重新添加填充即可。我想出了这一点,以便能够在WeasyPrint中解析“数据” URL,其中一些是base64而没有填充:

Wikipedia

此功能的测试: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)


0
投票

0
投票

0
投票
[当我删除dHJhaWxlcgo8PCAvU2l6ZSAxNSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWyhcMDAyXDMz MHtPcFwyNTZbezU/VzheXDM0MXFcMzExKShcMDAyXDMzMHtPcFwyNTZbezU/VzheXDM0MXFcMzEx KV0KPj4Kc3RhcnR4cmVmCjY3MDEKJSVFT0YK --_=ic0008m4wtZ4TqBFd+sXC8-- 并剥离字符串时,便修复了解析问题。

0
投票
默认情况下,altchars为base64.b64decode(b64_string, ' /')

0
投票
如果填充缺少3个字符,那么我将删除最后3个字符。

32
投票

只需根据需要添加填充。但是,请注意迈克尔的警告。

weasyprint/tests/test_css.py#L68

24
投票

“错误的填充”不仅可以表示“缺少填充”,还可以(不信不信)表示“错误的填充”。

如果建议的“添加填充”方法不起作用,请尝试删除一些尾随字节:

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

更新:在删除任何空格之后,应该在添加填充或从结尾删除可能坏的字节的任何摆弄,否则长度计算会很麻烦。

如果您向我们展示了您需要恢复的数据的(简短)样本,那将是一个好主意。编辑您的问题,然后复制/粘贴 lens = len(strg) lenx = lens - (lens % 4 if lens % 4 else 4) try: result = base64.decodestring(strg[:lenx]) except etc 的结果。

更新2:可能已经以url安全的方式完成了编码。在这种情况下,您将能够在数据中看到减号和下划线字符,并且应该能够使用print repr(sample)

对其进行解码

如果您在数据中看不到减号和下划线字符,但是可以看到加号和斜杠字符,则说明您还有其他问题,可能需要使用添加或删除技巧。

如果您在数据中看不到减号,下划线,加号​​和斜杠,则需要确定两个替代字符;他们将是[A-Za-z0-9]中没有的人。然后,您需要进行实验以查看在base64.b64decode(strg, '-_')

的第二个参数中需要使用它们的顺序

Update 3:如果您的数据是“公司机密”:(a)你应该这样说(b)我们可以探索其他途径来理解该问题,这很可能与使用什么字符代替编码字母中的base64.b64decode()+或其他格式或无关字符有关。

这样一种途径就是检查数据中有哪些非“标准”字符,例如

/

23
投票

如果存在填充错误,则可能意味着您的字符串已损坏; base64编码的字符串的长度应为四个的倍数。您可以尝试自己添加填充字符(from collections import defaultdict d = defaultdict(int) import string s = set(string.ascii_letters + string.digits) for c in your_data: if c not in s: d[c] += 1 print d ),以使字符串为四的倍数,但是除非有问题,否则应该已经有该字符了


20
投票

使用

=

贷方在此处发表评论。

string += '=' * (-len(string) % 4)  # restore stripped '='s

17
投票

我没有评论员,但要注意的一件好事是(至少在Python 3.x中)base64.b64decode将截断任何多余的填充,前提是首先要有足够的填充。

所以,类似:>>> import base64 >>> enc = base64.b64encode('1') >>> enc >>> 'MQ==' >>> base64.b64decode(enc) >>> '1' >>> enc = enc.rstrip('=') >>> enc >>> 'MQ' >>> base64.b64decode(enc) ... TypeError: Incorrect padding >>> base64.b64decode(enc + '=' * (-len(enc) % 4)) >>> '1' >>> b'abc='一样好。

这意味着您可以添加所需的最大填充字符数,即三个(b'abc=='),而base64会截断所有不必要的填充字符。

基本:

b'==='

比...干净

base64.b64decode(s + b'===')

4
投票

检查您要解码的数据源的文档。您是否可能要使用base64.b64decode(s + b'=' * (-len(s) % 4)) 而不是base64.urlsafe_b64decode(s)?这就是您可能已经看到此错误消息的原因之一。

使用URL安全字母来解码字符串,它代替-在标准Base64字母中用+和_代替/。

例如,各种Google API(例如Google的身份工具包和Gmail负载)就是这种情况。


1
投票

添加填充相当...好玩。这是我借助此线程中的注释以及base64的Wiki页面编写的函数(非常有用)base64.b64decode(s)

https://en.wikipedia.org/wiki/Base64#Padding

1
投票

有两种方法可以更正此处描述的输入数据,或者更具体地说,与OP保持一致,以使Python模块base64的b64decode方法能够将输入数据处理为something而不会引起不必要的注意例外:

  1. 附加==到输入数据的末尾并调用base64.b64decode(...)
  2. 如果引发异常,则

    i。通过try / except捕获它,

    ii。 (R?)从输入数据中去除任意=字符(N.B.可能没有必要),

    iii。将A ==附加到输入数据(A ==至P ==将起作用),

    iv。使用那些A ==附加的输入数据调用base64.b64decode(...)。

上述项目1或项目2的结果将产生所需的结果。

注意事项

这不保证解码后的结果将是原始编码的结果,但是(有时?)它会给OP足够的处理能力:

即使有损坏,我也想回到二进制文件,因为我仍然可以从ASN.1流中获得一些有用的信息”)。

请参见下面的[[我们知道

假设

TL; DR

来自对base64.b64decode(...)的一些快速测试

  1. 似乎忽略了非[A-Za-z0-9 + /]字符;包括忽略= s

    除非

    ,它们是已解析的四个字符组中的最后一个字符,在这种情况下,= s终止解码(a = b = c = d =给出与abc =相同的结果,而a == b == c ==得出的结果与ab ==)相同。
  • [还似乎在base64.b64decode(...)终止解码之后,在来自= =作为组中的第四个。
  • 如上面的几条评论所述,当[解析到该点的模数为4的字符数]值为0时,在输入数据的末尾需要填充数为零或一或二。 3或2。因此,从以上第3项和第4项开始,在输入数据中附加两个或多个=可以纠正这些情况下的所有[Invalid padding]问题。

    HOWEVER,解码无法处理[以4为模的解析字符总数]为1的情况,因为它需要至少两个编码字符来表示三个解码字节组中的第一个解码字节。在

    un损坏的编码输入数据中,不会发生[N模4] = 1的情况,但是由于OP指出字符可能丢失,因此可能会在这里发生。这就是为什么简单地附加= s并不总是有效的原因,以及为什么在附加==时不能附加

    A

    ==的原因。 N.B.使用[A]几乎是任意的:它仅将已清除的(零)位添加到解码后的位(可能正确或不正确),但是此处的对象不是正确的,而是由base64.b64decode(...)完成,没有异常。
    我们所知道的>>来自OP,尤其是随后的评论是

    怀疑是在计算机中缺少数据(字符)Base64编码的输入数据

    Base64编码使用标准的64位值加上填充:A-Z; a-z; 0-9; +; /; =是填充。这已经确认,或者至少通过import logging import base64 def base64_decode(s): """Add missing padding to string and return the decoded base64 string.""" log = logging.getLogger() s = str(s).strip() try: return base64.b64decode(s) except TypeError: padding = len(s) % 4 if padding == 1: log.error("Invalid base64 string: {}".format(s)) return '' elif padding == 2: s += b'==' elif padding == 3: s += b'=' return base64.b64decode(s) 有效的事实提出建议。
    • 假设
    • 输入数据仅包含7位ASCII数据

    • 唯一的损坏是缺少编码的输入数据
      OP在任何对应于丢失的编码输入数据的点之后的任何时候都不关心解码的输出数据
  • Github
  • 这里是实现此解决方案的包装器:
  • openssl enc ...

    仅在尝试解码目标字符串值之前,添加其他字符,例如“ =”或其他任何字符,并将其设为4的倍数。像;

    © www.soinside.com 2019 - 2024. All rights reserved.