我有一些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
bad*_*adp 32
只需根据需要添加填充.然而,请注意迈克尔的警告.
b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh
Run Code Online (Sandbox Code Playgroud)
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)
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)
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)
导致不正确的填充错误,因为有时,元数据也存在于编码字符串中解码之前的部分。
假设你有图像 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)