2

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

我有一个大字节数组,里面充满了对struct.pack()via的调用的输出bytearray.extend(struct.pack(varying_data))。然后它被压缩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()) 有效,但我认为这并不能真正解决问题,也许在其他情况下会失败?

谢谢您的帮助!

4

2 回答 2

1

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

我要说的是,我现在拥有了所有 3 种口味的 base85。Ascii85、Base85 和 Z85。每一个都有一个独特的字符集,它在从 base10 转换到 base85 时使用。每个版本都可能被诸如控制字符、连续太多的空格字符、HTML 和 XML 等符号繁重的东西、超过 126 个字符(波浪号)之类的东西绊倒(损坏的输出)。

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

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

注意:将您的字符串填充为可被 4 整除非常重要,并且在解码时使用“u”或波浪号填充您的哈希字符串,以便哈希可被 5 整除。

于 2019-12-29T22:45:09.593 回答
0

我发现了问题!base85 算法和压缩都不是这里的问题。它是 XML。

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

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

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

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

于 2019-06-11T20:29:28.933 回答