Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:Ignore';填充不正确';base64解码时出错_Python_Base64 - Fatal编程技术网

Python:Ignore';填充不正确';base64解码时出错

Python:Ignore';填充不正确';base64解码时出错,python,base64,Python,Base64,我有一些数据是base64编码的,我想转换回二进制,即使其中有填充错误。如果我使用 base64.decodestring(b64_string) 它会引发“不正确的填充”错误。还有别的办法吗 更新:感谢所有的反馈。老实说,所有提到的方法听起来都有点刺耳 所以我决定试试openssl。以下命令用于处理: openssl enc -d -base64 -in b64string -out binary_data 如果存在填充错误,则可能意味着字符串已损坏;base64编码字符串的长度应为4的倍

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

base64.decodestring(b64_string)
它会引发“不正确的填充”错误。还有别的办法吗

更新:感谢所有的反馈。老实说,所有提到的方法听起来都有点刺耳 所以我决定试试openssl。以下命令用于处理:

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

如果存在填充错误,则可能意味着字符串已损坏;base64编码字符串的长度应为4的倍数。您可以尝试自己添加填充字符(
=
)以使字符串为四的倍数,但它应该已经有了四的倍数,除非出现问题,只需根据需要添加填充即可。然而,请注意迈克尔的警告

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安全的方式完成的。如果是这种情况,您将能够在数据中看到减号和下划线字符,并且应该能够使用
base64.b64解码(strg,'-'.')

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

如果在数据中看不到减号、下划线、加号和斜杠,则需要确定两个可选字符;他们将是不在[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

正如在其他回复中所说,base64数据可能会以各种方式被破坏

但是,如上所述,删除填充(base64编码数据末尾的“=”字符)是“无损的”:

从理论上讲,不需要填充字符, 因为丢失的字节数可以从这个数字中计算出来 以64位为基数

因此,如果这真的是base64数据唯一“错误”的地方,那么可以将填充添加回去。我提出这个方法是为了能够解析WeasyPrint中的“数据”URL,其中一些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)

此函数的测试:

在尝试解码目标字符串值之前,只需添加额外的字符,如“=”或任何其他字符,并将其设置为4的倍数。有点像

if len(value) % 4 != 0: #check if multiple of 4
    while len(value) % 4 != 0:
        value = value + "="
    req_str = base64.b64decode(value)
else:
    req_str = base64.b64decode(value)

检查您试图解码的数据源的文档。您是否打算使用
base64.urlsafe\u b64解码
而不是
base64.b64解码
?这就是您可能看到此错误消息的原因之一

使用URL安全字母表解码字符串s,该字母表替代-而不是 用+和u代替标准Base64字母表中的/

例如,各种Google API都是如此,比如Google的Identity Toolkit和Gmail有效负载。

使用

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'

>>> 

添加填充是相当。。。微小难弄的下面是我在这个线程中的注释以及base64的wiki页面的帮助下编写的函数(它非常有用)


如果此错误来自web服务器:请尝试url编码您的帖子值。我是通过“curl”发布的,发现我不是对base64值进行url编码,所以“+”之类的字符没有转义,所以web服务器url解码逻辑自动运行url解码并将+转换为空格


“+”是一个有效的base64字符,可能是唯一一个被意外的url解码破坏的字符。

在我的例子中,我在解析电子邮件时遇到了这个错误。我得到了base64字符串的附件,并通过re.search将其解压缩。最终在结尾处出现了一个奇怪的附加子字符串

dHJhaWxlcgo8PCAvU2l6ZSAxNSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWyhcMDAyXDMz
MHtPcFwyNTZbezU/VzheXDM0MXFcMzExKShcMDAyXDMzMHtPcFwyNTZbezU/VzheXDM0MXFcMzEx
KV0KPj4Kc3RhcnR4cmVmCjY3MDEKJSVFT0YK

--_=ic0008m4wtZ4TqBFd+sXC8--
当我删除
--ic0008m4wtZ4TqBFd+sXC8--
并删除字符串时,解析就完成了

因此,我的建议是确保您解码的是正确的base64字符串。

您应该使用

base64.b64decode(b64_string, ' /')

默认情况下,altchar是
'+/'

似乎您只需要在解码之前向字节添加填充。关于这个问题还有很多其他答案,但我想指出(至少在Python3.x中)
base64.b64decode
将截断任何额外的填充,前提是首先有足够的填充

因此,类似于:
b'abc='
的功能与
b'abc='
一样好(就像
b'abc===='

这意味着您只需添加所需的最大填充字符数,即两个(
b'=='
),base64将截断任何不必要的填充字符

这使您可以编写:

base64.b64解码(s+b'==)
这比:

base64.b64解码(s+b'='*(-len(s)%4))

有两种方法可以更正此处描述的输入数据,或者更具体地说,根据OP,使Python模块base64的B64解码方法能够处理
base64.b64decode(b64_string, ' /')
        missing_padding = len(data) % 4
        if missing_padding == 3:
            data = data[0:-3]
        elif missing_padding != 0:
            print ("Missing padding : " + str(missing_padding))
            data += '=' * (4 - missing_padding)
        data_decoded = base64.b64decode(data)   
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")