Python:在base64解码时忽略'不正确的填充'错误

Fun*_*der 92 python base64

我有一些base64编码的数据,我想转换回二进制,即使它有填充错误.如果我使用

base64.decodestring(b64_string)
Run Code Online (Sandbox Code Playgroud)

它引发了"不正确的填充"错误.还有另外一种方法吗?

更新:感谢您的所有反馈.说实话,所提到的所有方法听起来都有点受伤,所以我决定尝试openssl.以下命令有效:

openssl enc -d -base64 -in b64string -out binary_data
Run Code Online (Sandbox Code Playgroud)

Sim*_*pin 76

如其他响应中所述,base64数据可能有多种方式被破坏.

但是,正如维基百科所说,删除填充(base64编码数据末尾的'='字符)是"无损"的:

从理论的观点来看,不需要填充字符,因为可以从Base64数字的数量计算丢失字节的数量.

因此,如果这对于base64数据来说真的是唯一"错误",那么填充就可以添加回来.我想出了这个能够解析WeasyPrint中的"数据"URL,其中一些是没有填充的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)
Run Code Online (Sandbox Code Playgroud)

测试此功能:weasyprint/tests/test_css.py#L68

  • 注意:ASCII 不是 Unicode,所以为了安全起见,你可能需要 `str(data)` (2认同)
  • 有一点需要注意,这很好.不推荐使用base64.decodestring,请使用base64.b64_decode (2认同)
  • 为了澄清@ariddell 注释,Py3 中的 base64.decodebytes 已弃用 `base64.decodestring`,但为了版本兼容性,最好使用 `base64.b64decode`。 (2认同)

bad*_*adp 32

只需根据需要添加填充.然而,请注意迈克尔的警告.

b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh
Run Code Online (Sandbox Code Playgroud)

  • @badp:`base64.b64decode(s +'='*(-len(s)%4))` (35认同)
  • 只需附加 `===` 总是有效的。任何额外的“=”字符似乎都会被 Python 安全地丢弃。 (11认同)
  • 肯定有一些更简单的映射 0 到 0、2 到 1 和 1 到 2。 (2认同)
  • 你为什么要扩展到3的倍数而不是4? (2认同)

Mic*_*zek 23

如果有填充错误,则可能意味着您的字符串已损坏; base64编码的字符串应具有四个长度的倍数.您可以尝试=自己添加填充字符()以使字符串为四的倍数,但除非出现问题,否则它应该已经存在


Joh*_*hin 23

"不正确的填充"不仅意味着"缺少填充",而且(不管你信不信)"填充不正确".

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

lens = len(strg)
lenx = lens - (lens % 4 if lens % 4 else 4)
try:
    result = base64.decodestring(strg[:lenx])
except etc
Run Code Online (Sandbox Code Playgroud)

更新:任何摆弄添加填充或从末尾删除可能坏字节的任何摆弄应该在删除任何空格后完成,否则长度计算将被打乱.

如果您向我们展示了您需要恢复的(短)数据样本,那将是一个好主意.编辑您的问题并复制/粘贴结果 print repr(sample).

更新2:编码可能是以URL安全的方式完成的.如果是这种情况,您将能够在数据中看到减号和下划线字符,并且您应该能够使用它来解码它base64.b64decode(strg, '-_')

如果您在数据中看不到减号和下划线字符,但可以看到加号和斜线字符,那么您还有其他一些问题,并且可能需要添加填充或删除 - 删除技巧.

如果您在数据中看不到减号,下划线,加号​​和斜线,则需要确定两个备用字符; 他们将是那些不在[A-Za-z0-9]中的人.然后你需要尝试看看他们需要在第二个arg中使用哪个顺序base64.b64decode()

更新3:如果您的数据为"公司机密":
(一)你应该这么说了前面
(B),我们可以理解这一问题,这是极有可能涉及到什么字符代替的探索其他渠道+,并/在编码字母表,或其他格式或无关字符.

一种这样的途径是检查数据中的非"标准"字符,例如

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
Run Code Online (Sandbox Code Playgroud)

  • 我的要求不是要解决为什么base64损坏的问题 - 它来自我无法控制的来源.我的要求是提供有关收到的数据的信息,即使它已损坏.一种方法是从损坏的base64中获取二进制数据,以便从底层ASN.1中收集信息.流.我问了原来的问题,因为我想要回答这个问题而不是另一个问题的答案 - 比如如何调试腐败的base64. (7认同)

war*_*iuc 20

使用

string += '=' * (-len(string) % 4)  # restore stripped '='s
Run Code Online (Sandbox Code Playgroud)

信用在这里发表评论.

>>> 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'

>>> 
Run Code Online (Sandbox Code Playgroud)

  • 他的意思是这个评论:http://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding#comment12174484_2942039 (4认同)

Hen*_*ody 17

我没有代表评论,但值得注意的是(至少在Python 3.x中)base64.b64decode会截断任何额外的填充,前提是有足够的内容.

所以,像:b'abc='一样有效b'abc=='.

这意味着你可以只添加你需要的最大填充字符数 - 这是三(b'===') - 而base64会截断任何不必要的填充字符.

基本上:

base64.b64decode(s + b'===')
Run Code Online (Sandbox Code Playgroud)

比...更干净

base64.b64decode(s + b'=' * (-len(s) % 4))
Run Code Online (Sandbox Code Playgroud)

  • 好吧,这不是太“难看”,谢谢:)顺便说一句,我认为你永远不需要超过 2 个填充字符。Base64 算法一次适用于 3 个字符的组,仅当最后一组字符的长度仅为 1 或 2 个字符时才需要填充。 (2认同)
  • @Otto 这里的填充用于解码,适用于 4 个字符的组。Base64 *编码*适用于 3 个字符组:) (2认同)
  • @奥托我相信你是对的。虽然长度为 5 的 Base64 编码字符串需要 3 个填充字符,但长度为 5 的字符串甚至不是 Base64 编码字符串的有效长度。您会收到错误:“binascii.Error:无效的 base64 编码字符串:数据字符数 (5) 不能比 4 的倍数多 1”。感谢您指出了这一点! (2认同)

sam*_*sam 9

导致不正确的填充错误,因为有时,元数据也存在于编码字符串中解码之前的部分。

假设你有图像 base64 编码的字符串,然后尝试下面的代码片段..

from PIL import Image
from io import BytesIO
from base64 import b64decode
imagestr = 'data:image/png;base64,...base 64 stuff....'
im = Image.open(BytesIO(b64decode(imagestr.split(',')[1])))
im.save("image.png")
Run Code Online (Sandbox Code Playgroud)


小智 5

base64.urlsafe_b64decode(data)如果您正在尝试解码网络图像,您可以简单地使用。它会自动处理填充。