0

I am new to Python & I am trying to learn how to XOR hex encoded ciphertexts against one another & then derive the ASCII value of this.

I have tried some of the functions as outlined in previous posts on this subject - such as bytearray.fromhex, binascii.unhexlify, decode("hex") and they have all generated different errors (obviously due to my lack of understanding). Some of these errors were due to my python version (python 3).

Let me give a simple example, say I have a hex encoded string ciphertext_1 ("4A17") and a hex endoded string ciphertext_2. I want to XOR these two strings and derive their ASCII value. The closest that I have come to a solution is with the following code:

result=hex(int(ciphertext_1, 16) ^ int(ciphertext_2, 16))
print(result)

This prints me a result of: 0xd07 (This is a hex string is my understanding??)

I then try to convert this to its ASCII value. At the moment, I am trying:

binascii.unhexliy(result)

However this gives me an error: "binascii.Error: Odd-length string" I have tried the different functions as outlined above, as well as trying to solve this specific error (strip function gives another error) - however I have been unsuccessful. I realise my knowledge and understanding of the subject are lacking, so i am hoping someone might be able to advise me?

Full example:

#!/usr/bin/env python
import binascii

ciphertext_1="4A17"
ciphertext_2="4710"

result=hex(int(ciphertext_1, 16) ^ int(ciphertext_2, 16))
print(result)
print(binascii.unhexliy(result))
DaveMac001
  • 155
  • 3
  • 13

2 Answers2

1
from binascii import unhexlify

ciphertext_1 = "4A17"
ciphertext_2 = "4710"
xored = (int(ciphertext_1, 16) ^ int(ciphertext_2, 16))
# We format this integer: hex, no leading 0x, uppercase
string = format(xored, 'X')
# We pad it with an initial 0 if the length of the string is odd
if len(string) % 2:
    string = '0' + string
# unexlify returns a bytes object, we decode it to obtain a string
print(unhexlify(string).decode())
#
# Not much appears, just a CR followed by a BELL

Or, if you prefer the repr of the string:

print(repr(unhexlify(string).decode()))
# '\r\x07'
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
  • I have tried this, word for word, but the print does not print out any result. I expected it to print '\r\x07'. Perhaps I have overlooked something? – DaveMac001 Mar 16 '18 at 14:24
  • 1
    `\r` is a carriage return and `\x07` is a bell, so you won't see much when printing them ( an empty line, and maybe a nice little , depending on your terminal). If you want to see ` '\r\x07'`, you need the `repr` of the string: `print(repr(unhexlify(string).decode()))` – Thierry Lathuille Mar 16 '18 at 15:34
0

When doing byte-wise operations like XOR, it's often easier to work with bytes objects (since the individual bytes are treated as integers). From this question, then, we get:

ciphertext_1 = bytes.fromhex("4A17")
ciphertext_2 = bytes.fromhex("4710")

XORing the bytes can then be accomplished as in this question, with a comprehension. Then you can convert that to a string:

result = [c1 ^ c2 for (c1, c2) in zip(ciphertext_1, ciphertext_2)]
result = ''.join(chr(c) for c in result)

I would probably take a slightly different angle and create a bytes object instead of a list, which can be decoded into your string:

result = bytes(b1 ^ b2 for (b1, b2) in zip(ciphertext_1, ciphertext_2)).decode()
glibdud
  • 7,550
  • 4
  • 27
  • 37