hellman/xortool

Python 3 support incomplete

xtaran opened this issue · 6 comments

Hi,

I'm sorry, but my pull request #15 was incomplete. What makes -c work with Python 3.5 is the following patch:

diff --git a/xortool/routine.py b/xortool/routine.py
index 98f353a..9e760f1 100644
--- a/xortool/routine.py
+++ b/xortool/routine.py
@@ -76,7 +76,7 @@ def dexor(text, key):
     ret = list(text)
     mod = len(key)
     for index, char in enumerate(ret):
-        ret[index] = chr(ord(char) ^ ord(key[index % mod]))
+        ret[index] = chr(char ^ ord(key[index % mod]))
     return "".join(ret)
 
 
diff --git a/xortool/xortool b/xortool/xortool
index c9fd0aa..2fcbc97 100755
--- a/xortool/xortool
+++ b/xortool/xortool
@@ -271,7 +271,7 @@ def guess_keys(text, most_char):
         max_count = max(chars_count.values())
         for char in chars_count:
             if chars_count[char] >= max_count:
-                key_possible_bytes[offset].append(chr(ord(char) ^ most_char))
+                key_possible_bytes[offset].append(chr(char ^ most_char))
 
     return all_keys(key_possible_bytes)
 
@@ -358,7 +358,7 @@ def produce_plaintexts(ciphertext, keys, key_char_used):
                                                repr(key_char_used[key]),
                                                perc))
         f = open(file_name, "wb")
-        f.write(dexored)
+        f.write(dexored.encode())
         f.close()
     key_mapping.close()
     perc_mapping.close()

Unfortunately (at least) the first two hunks break Python 2 compatibility and so far I haven't figured out how to make it work with both Python generations.

And I'm not 100% sure if appending that .encode() is the correct fix, but at least I get the same results on the same input data plus command-line parameters.

noraj commented

It must be it.

Python 3

xortool -o -x key.txt                                       
Traceback (most recent call last):
  File "/usr/bin/xortool", line 381, in <module>
    main()
  File "/usr/bin/xortool", line 53, in main
    ciphertext = get_ciphertext()
  File "/usr/bin/xortool", line 96, in get_ciphertext
    ciphertext = decode_from_hex(ciphertext)
  File "/usr/lib/python3.7/site-packages/xortool/routine.py", line 58, in decode_from_hex
    only_hex_digits = "".join([c for c in text if c in string.hexdigits])
  File "/usr/lib/python3.7/site-packages/xortool/routine.py", line 58, in <listcomp>
    only_hex_digits = "".join([c for c in text if c in string.hexdigits])
TypeError: 'in <string>' requires string as left operand, not int

Python 2

xortool -o -x key.txt                                       
The most probable key lengths:
   2:   38.3%
   5:   22.7%
  10:   26.9%
  17:   6.4%
  20:   5.6%
Key-length can be 5*n
100 possible key(s) of length 2:
\n\x15
\x0b\x14
\x08\x17
\t\x16
\x0e\x11
...
Found 50 plaintexts with 95.0%+ printable characters
See files filename-key.csv, filename-char_used-perc_printable.csv
noraj commented

Also: with python3.7.2:

$ xortool-xor -h 607b7b7b -h 3f3c3e2f
Traceback (most recent call last):
  File "/usr/bin/xortool-xor", line 117, in <module>
    main()
  File "/usr/bin/xortool-xor", line 40, in main
    v = arg_data(c, val)
  File "/usr/bin/xortool-xor", line 110, in arg_data
    return from_hex(s)
  File "/usr/bin/xortool-xor", line 95, in from_hex
    return res.decode("hex")
AttributeError: 'str' object has no attribute 'decode'
noraj commented
$ python2 /usr/bin/xortool-xor -h 607b7b7b -h 3f3c3e2f                                                                                                        
_GET

As @redfast00 spotted, this is totally a matter of shebang.

possible solution for hex encoding:

def decode_from_hex(text):
    only_hex_digits = "".join([chr(c) for c in text if chr(c) in string.hexdigits])
    return bytes.fromhex(only_hex_digits)

maage commented

Also #26 fixes this issue.

I think should work now on master (not on PyPI yet)