我有一些经过Base64编码的数据,即使其中存在填充错误,我也想将其转换回二进制。如果我使用
base64.decodestring(b64_string)
它引发了一个“填充不正确”的错误。还有其他方法吗?
更新:感谢所有的反馈。老实说,提到的所有方法听起来都有点靠运气,所以我决定尝试openssl。以下命令非常有效:
openssl enc -d -base64 -in b64string -out binary_data
看起来你只需要在解码之前给字节添加填充即可。 这个问题有很多其他答案,但是我想指出的是(至少在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 在评论中指出这一点。
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4
。感谢你指出这一点! - Henry Woodygrep -A23 "def b64decode" /usr/lib/python3.10/base64.py
https://github.com/python/cpython/blob/v3.10.9/Lib/base64.py#L85显示了一个正则表达式`b'[A-Za-z0-9+/]*={0,2}'`和一个`raise`。新版本可能有类似的严格行为,https://github.com/python/cpython/blob/a87c46e/Modules/binascii.c#L427。 - eel ghEEz就像其他回答中所说,base64数据可能会以各种方式损坏。
然而,正如维基百科所述,移除填充(在base64编码数据结尾处的'='字符)是“无损的”:
从理论上讲,填充字符是不必要的,因为可以通过Base64数字的数量计算出缺失的字节数。
因此,如果这确实是您的base64数据唯一的“问题”,则可以将填充字符添加回去。我设计了这个方法来解析WeasyPrint中的“data”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)
该函数的测试内容:weasyprint/tests/test_css.py#L68
str(data)
。 - MarkHubase64.decodestring
在Py3中已被弃用,但为了版本兼容性最好使用base64.b64decode
。 - Casbase64
模块会忽略输入中无效的非base64字符,所以您首先需要规范化数据。删除任何不是字母、数字、/
或+
的内容,然后再添加填充。 - Martijn Pieters4n+1
个标准化(未填充)编码输入字母已经是无效编码的迹象,因为base64仅编码为4n
、4n+2
或4n+3
个未填充字母。 - eel ghEEz只需根据需要添加填充。然而请注意迈克尔的警告。
b64_string += "=" * ((4 - len(b64_string) % 4) % 4) #ugh
===
即可。Python 似乎可以安全地忽略多余的 =
符号。 - Asclepius((4 - len(b64_string)) % 4)
似乎对于所有值,包括len=0这样的边缘情况,都返回相同的结果。 - Luclens = len(strg)
lenx = lens - (lens % 4 if lens % 4 else 4)
try:
result = base64.decodestring(strg[:lenx])
except etc
更新:在移除任何空格之后才进行添加填充或删除可能的末尾无效字节的操作,否则长度计算可能会出错。
如果您能展示一段(简短)需要恢复的数据样本,将是一个好主意。编辑您的问题并复制/粘贴以下结果:print repr(sample)
。
更新2:可能已经以url安全的方式进行了编码。如果是这种情况,则您将能够在数据中看到减号和下划线字符,并且您应该能够通过使用 base64.b64decode(strg,'-_')
来解码它。
如果您的数据中没有减号和下划线字符,但可以看到加号和斜杠字符,则您可能有其他问题,并且可能需要添加填充或删除无用字符。
如果您的数据中既没有减号、下划线、加号也没有斜杠字符,则需要确定两个备选字符;它们将是不在[A-Za-z0-9]中的字符。然后,您需要自行实验以确定它们在base64.b64decode()
的第二个参数中需要使用的顺序。
更新3:如果您的数据是“公司保密”:
(a) 您应该事先说明
(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
使用
string += '=' * (-len(string) % 4) # restore stripped '='s
这里的评论是原作者发表的。
>>> 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'
>>>
=
),使字符串成为四的倍数,但是除非有问题,否则它应该已经具有这个长度。不正确的填充错误是由于有时元数据也存在于编码的字符串中而导致的。如果您的字符串看起来像:'data:image/png;base64,...base 64 stuff....',那么您需要在解码之前删除第一部分。
例如,如果您有图像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")
base64.urlsafe_b64decode(data)
。 它会自动处理填充。请查看你尝试解码的数据源文件的文档。你是否想使用base64.urlsafe_b64decode(s)
而非base64.b64decode(s)
?这可能是你遇到此错误消息的原因之一。
使用URL安全字符表解码字符串s,其中将+替换为-,将/替换为_,以代替标准Base64字符表中的符号。
例如,这是各种Google API(如Google身份验证工具包和Gmail负载)使用的情况。
urlsafe_b64decode
也需要填充。 - rdbbase64.urlsafe_b64decode
。 - Daniel F增加填充有些繁琐。这是我写的函数,结合了本线程中的评论和Base64维基页面(它非常有帮助)https://en.wikipedia.org/wiki/Base64#Padding。
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)
base64.b64decode(strg, '-_')
?在你没有提供任何示例数据的情况下,这是解决你问题最有可能的Python方法。之前提出的"方法"只是调试建议,鉴于提供的信息很少,它们必然是"靠瞎猜"的。 - John Machinbase64.urlsafe_b64decode(s)
。该函数用于解码使用URL安全字符集编码的Base64字符串。 - Daniel Fsorted(list(set(b64_string)))
。通过此方式,我们可以知道用于编码原始数据的字符集,进而提供一个更加准确的解决方案,同时不会泄露任何公司机密信息。 - Brian Carcich