Понимание Python struct.pack и двоичного ввода

Следующая функция принимает двоичный 4-байтовый ключ для key. buf — это двоичный ввод, который подвергается операции xor против 4-байтового ключа.

def four_byte_xor(buf, key):
    #key = struct.pack(b">I", key) # removed for binary processing
    buf = bytearray(buf)
    for offset in range(0, len(buf), 4):
        for i, byte in enumerate(key):
            buf[offset + i] = chr(buf[offset + i] ^ ord(byte))
    return str(buf)

Я удалил key = struct.pack(b">I", key) из four_byte_xor(), чтобы указать бинарные данные через str(p.payload.payload.payload)[:4] для key. Это отлично работает, если длина заканчивается 4 байтами, в противном случае возникает следующая ошибка (см. Тестирование ниже).

Вот несколько тестов, состоящих из ввода xor'd с ключом, результатом которого является 00, первый из которых был успешным:

'ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD'
'ABCD'

bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
'ABCD'

Второй тест не успешен и заканчивается на A или на 1 дополнительный байт:

'ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA'
'ABCD'
Traceback (most recent call last):
  File "./decode.py", line 36, in <module>
    process_packets()
  File "./decode.py", line 34, in process_packets
    out_buf.write(bin_four_byte_xor(pkt_payload, pkt_offset))
  File "./decode.py", line 22, in bin_four_byte_xor
    buf[offset + i] = chr(buf[offset + i] ^ ord(byte))
IndexError: bytearray index out of range

Можно ли изменить four_byte_xor(), чтобы принять buf разной длины?


person Astron    schedule 15.07.2012    source источник
comment
Ваши ошибки с linehexdump были вызваны тем, что эта функция не возвращает шестнадцатеричные значения, а просто печатает их. Я рад видеть, что вы отказались от этого подхода. Использование ваших двоичных данных непосредственно в качестве ключа имеет гораздо больше смысла. Длина массива байтов buff точно кратна 4? Если нет, вы получите ошибку вне диапазона, когда доберетесь до дополнительных 1-3 байтов в конце.   -  person Blckknght    schedule 16.07.2012
comment
Возможно, это не так, хотя я тестировал отдельные пакеты, и, похоже, все работает нормально. Когда я пытаюсь передать несколько пакетов через буфер, я получаю индекс вне допустимого диапазона. Должно ли это быть что-то, что очищает buf и key между итерациями или это происходит автоматически?   -  person Astron    schedule 16.07.2012
comment
Этот вопрос близок к предоставлению воспроизводимого примера, но не совсем. Прежде чем упомянуть, что еще вы пробовали, не могли бы вы включить точный код, который не работает, несокращенное (кроме случаев, когда речь идет об именах файлов) сообщение об ошибке и вызов функции ( то есть что-то вроде four_byte_xor(b'a', 42)), чтобы программа стала самодостаточным примером? Если вы не знаете точных аргументов, вы можете использовать print(repr(buf)) для их отображения в реальной системе.   -  person phihag    schedule 16.07.2012
comment
Оказывается, есть некоторая дисперсия. Обновлен вопрос с выводом из print(repr(buf)).   -  person Astron    schedule 16.07.2012


Ответы (1)


Конечно, вы можете изменить функцию, чтобы она принимала ключи разной длины. Например, что-то вроде

def many_byte_xor(buf, key):
    buf = bytearray(buf)
    for i, bufbyte in enumerate(buf):
        buf[i] = chr(bufbyte ^ ord(key[i % len(key)]))
    return str(buf)

который циклически перебирает все символы ключа (модульная версия itertools.cycle). Это производит

>>> many_byte_xor("AABAA", "AB")
'\x00\x03\x03\x03\x00'
>>> many_byte_xor("ABCDABCD", "ABCD")
'\x00\x00\x00\x00\x00\x00\x00\x00'
>>> many_byte_xor("ABCDABCDA", "ABCD")
'\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> many_byte_xor("ABCDABCDAB", "ABCD")
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> many_byte_xor("ABCDABCDAB", "ABC")
'\x00\x00\x00\x05\x03\x01\x02\x06\x02\x03'

какой IIUC - это то, что вы хотите.

person DSM    schedule 16.07.2012
comment
Для большей эффективности вы можете добавить key = bytearray(key) и key_len = len(key) непосредственно перед циклом, а затем присваивание внутри него можно упростить до buf[i] = bufbyte ^ key[i % key_len]. Поскольку bytearray представляют собой просто изменяемые последовательности небольших целых чисел, нет необходимости в вызовах функций ord() и chr(). - person martineau; 16.07.2012