Astron
Astron

Reputation: 1221

Understanding Python struct.pack and binary input

The following function accepts a binary 4 byte key for key. buf is binary input which is xor'd against the 4 byte key.

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)

I removed key = struct.pack(b">I", key) from four_byte_xor() in order to specify binary data via str(p.payload.payload.payload)[:4] for key. This works fine if the length end in 4 bytes, otherwise the following error fires (see testing below).

Here are some tests consisting of an input xor'd with a key resulting in 00, first one being successful:

'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'

Second test is not successful and end in A or 1 extra byte:

'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

Can the four_byte_xor() be modified to accept varying buf lengths?

Upvotes: 1

Views: 2124

Answers (1)

DSM
DSM

Reputation: 352979

Sure, you can modify the function to accept varying key lengths. For example, something like

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)

which cycles over all the characters of the key (the modulus version of itertools.cycle). This produces

>>> 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'

which IIUC is what you want.

Upvotes: 3

Related Questions