base85编码字符串解码时出现base85溢出错误

base85 overflow error during decoding of base85 encoded string

我需要将二进制数据嵌入到 XML 文件中,因此我选择为此使用 base85 编码。

我有一个很大的字节数组,里面装满了通过 bytearray.extend(struct.pack(varying_data)) 调用 struct.pack() 的输出。然后用 zlib 压缩并用 base64.b85encode().

编码

这一直有效,但在单个输入文件上,出现以下奇怪错误:

ValueError: base85 overflow in hunk starting at byte 582200`

然后我修改了 base64.py 以打印出当前块具有的值以及它由哪些字节组成。输入块为 b'||a|3',其值为 4.331.076.573,大于 256^4 = 4.294.967.296,因此不能用四个字节表示(这就是错误的来源)。

但是我不明白的是:怎么会这样?

这是代码的重要部分:

elif isinstance(self.content, (bytes, bytearray)):
    base85 = zlib.compress(self.content, 9)

    # pad=False doesn't make a difference here
    base85 = base64.b85encode(base85, pad=True).decode()

    base85 = escape_xml(base85)

    file.write(base85)
def escape_xml(text):

    text = text.replace("&", "&")
    text = text.replace("<", "&lt;")
    text = text.replace(">", "&gt;")
    text = text.replace("\"", "&quot;")
    text = text.replace("'", "&apos;")

    return text

解码代码:

def decode_binary_data(data):
    data = unescape_xml(data)

    # Remove newline for mixed content support (does not apply in this case)
    data = data.split("\n", 1)[0]

    # Error!
    data = base64.b85decode(data)

    return zlib.decompress(data)

def unescape_xml(text):
    text = text.replace("&quot;", "\"")
    text = text.replace("&apos;", "'")
    text = text.replace("&lt;", "<")
    text = text.replace("&gt;", ">")
    text = text.replace("&amp;", "&")

    return text

Base85 理论上可以与 85^5 = 4.437.053.125 可能的组合一起使用,但是当它从字节获取输入时,我想知道这怎么可能。这是来自压缩吗?这不应该是问题,因为编码和解码应该是对称的。如果是问题,如何压缩数据?

改为选择 Ascii85 (a84encode()) 可行,但我认为这并不能真正解决问题,也许在其他情况下会失败?

感谢您的帮助!

我找到问题了! base85 算法和压缩都不是这里的问题。就是 XML.

对于 exporting/writing 包含 base85 字符串的 XML,我编写了自己的 class 和导出 XML 的函数,这样它看起来很漂亮(xml.etree.ElementTree 将所有内容写入一行,对于这个项目,我不能使用来自 pip 的外部包)。这就是必须手动转义 base85 字符串的原因。

但是为了读取 XML 个文件,我使用 xml.etree.ElementTree我不知道大多数 XML 库会自动 (un) 转义字符串(这是有道理的)。

所以,问题出在手动反转义上,ElementTree 是自动进行的。结果,base85 字符串未转义 两次 。由于 base85 字母表包含 XML 转义字符串($amp;$lt; 等)中包含的每个字母,并且该 base85 字符串中有超过 500.000 个字符,因此很可能存在是输出字符串中的字符组合,形成有效的 XML 转义字符串。

这就是问题所在。 &lt; 包含在未转义的 base85 字符串中并再次被转义,导致所有后续字节的偏移量导致此错误。

我经常使用 LabView、Python 和 javascript,并且不得不为 LabView 创建我自己的 Base85 编码和解码例程,它只有 MD5 校验和。对于加密或良好的混淆,您必须自己动手。也许未来版本的 LabView 会在库中包含 Base85。

我要表达的意思是我现在拥有 base85 的所有 3 种风格。 Ascii85、Base85 和 Z85。每个都有一个唯一的字符集,它在从 base10 转换为 base85 时使用。 每个版本都可能被诸如控制字符、连续 space 字符过多、HTML 和 XML 之类的符号繁重的东西等问题绊倒(损坏的输出) , 超过 126 个字符(波浪号)。

为了安全地编码大型文本文件,尤其是多行和符号较多的文件,我只是让代码感知所有这些潜在的问题并首先转换为十六进制。是的,它使字符数加倍,但 base10 到 base85 引擎不会崩溃。即使对于大型纯文本文件,Z85 也会在 1000 个字符左右后崩溃,问题在于 Z85 字符映射,它的符号是乱码的,因此在长字符串上会发生溢出。为了我自己的目的,我更改了 Z85 字符映射,使符号按十进制顺序排列,现在 Z85 不再在大文件上崩溃。

Ascii85、Base85 和 Z85 会因上述相同问题而崩溃,无论是用 python、javascript 还是 LabView 编写。 通常是多个连续的 symbols/spaces 导致数学溢出, 因此输出已损坏且无法解码。

注意:填充字符串非常重要 可以被 4 整除,解码时用 'u' 或波浪号填充哈希字符串,这样hash 可以被 5 整除。