Ошибка переполнения base85 при декодировании закодированной строки base85 - PullRequest
2 голосов
/ 10 июня 2019

Мне нужно встроить двоичные данные в файлы XML, поэтому я решил использовать для этого кодировку base85.

У меня есть большой байтовый массив, который заполнен выводом вызовов на struct.pack() через 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()) работает, но я думаю, что это действительно не решает проблему, может быть, это не помогает в других случаях?

Спасибо за помощь!

1 Ответ

0 голосов
/ 11 июня 2019

Я нашел проблему! Здесь не проблема ни алгоритма base85, ни сжатия. Это XML.

Для экспорта / записи XML с включенной строкой base85 я написал свой собственный класс и функции для экспорта XML, чтобы он выглядел довольно красиво (xml.etree.ElementTree записывает все в одну строку, и для этого проекта я не могу использовать внешние пакеты из пипа). Вот почему строка base85 должна быть экранирована вручную.

Но для чтения файлов XML я использую xml.etree.ElementTree. Я не знал, что большинство библиотек XML (не) экранируют строки автоматически (что имеет смысл).

Итак, проблема заключалась в ручном удалении, которое ElementTree делает автоматически. В результате строка base85 получила неэкранированный дважды . А так как алфавит base85 содержит каждую букву, включенную в escape-строки XML ($amp;, $lt; и т. Д.), И в этой строке base85 содержится более 500 000 символов, вполне вероятно, что в выходных данных есть комбинация символов строка, которая формирует допустимую управляющую строку XML.

И это была проблема. &lt; содержался в строке unescaped base85 и снова получался unescaped, что приводило к смещению всех следующих байтов, которое привело к этой ошибке.

...