Brandon Schaefer
Brandon Schaefer

Reputation: 531

Hex number (0-15) and return ascii representation

For a cryptography application, I'm reading in strings that represent hexadecimal ( "36E06921", "27EA3C74" ) and need to xor them together and return a str of the result ("110A5555"). I'm able to xor char by char and get decimal result, but am having issues getting the ascii representation of the result. So, 0x3 xor 0x3 = 0x0. Whats the best way to get value 0 into ascii value 0x30?

Current attempt at implementation:

def xor_hexstrings(xs, ys):
    bin_x = binascii.unhexlify(xs)
    bin_y = binascii.unhexlify(ys)
    hex_str = ""
    for x,y in zip(xs, ys):         
        # fails, with error TypeError: 'int' does not support the buffer interface
        xored = binascii.b2a_hex(int(x, 16) ^ int(y, 16))
        hex_str += xored
return None

EDIT: Close, only issue is with zero. Following example shows recommended solution returns empty string for zero.

>>> hex(int('0', 16)).lstrip("0x")
''
>>> hex(int('1', 16)).lstrip("0x")

Upvotes: 0

Views: 798

Answers (4)

ShadowRanger
ShadowRanger

Reputation: 155507

Adapting a pattern from Python 3 to the types available on Python 2: Use bytes-like objects to get natural int iteration:

import binascii 
from operator import xor 

def xor_hex(xs, ys): 
    xs = bytearray(binascii.unhexlify(xs))
    ys = bytearray(binascii.unhexlify(ys))
    return binascii.hexlify(bytearray(map(xor, xs, ys)))   # Stick a .upper() on this if it must produce uppercase hex

>>> print xor_hex( "36E06921", "27EA3C74" )
110a5555

In Python 3, it's simpler, since you can use bytes types directly instead of converting from Py2 str to bytearray to get bytes-like behavior:

def xor_hex(xs, ys): 
    xs = binascii.unhexlify(xs)
    ys = binascii.unhexlify(ys)
    return binascii.hexlify(bytes(map(xor, xs, ys)))

Although even that is fairly slow compared to what you can do with Python 3's int.to_bytes and int.from_bytes methods (which admittedly produce even uglier code).

Upvotes: 0

MervS
MervS

Reputation: 5902

You can do the following:

x = "36E06921"
y = "27EA3C74"
z = ''.join([format((int(i,16)^int(j,16)),'X') for i,j in zip(x,y)])
print z

Output:

110A5555

Upvotes: 2

Gil
Gil

Reputation: 380

I think what you are asking here is to convert an integer into it's respective string representation. At least that is what the example 0x0 -> 0x30 would seem to suggest. If so, just cast to a string in python with the str() function.

>>> ord(str(0))
48

Just for reference 48 equals 0x30 and the ord() function gives you integer representation of a character.

EDIT: Check out the format function. Seems to have expected behavior!

>>> format(0x0, 'x')
'0'

Upvotes: -1

Ankur Agarwal
Ankur Agarwal

Reputation: 24768

I am guessing you need this:

>>> base10_int = int('0x0',16)
>>> base10_int_str = str(base10_int)
>>> base10_ascii_val = ord(base10_int_str)
>>> hex_ascii_val = hex(base10_ascii_val)
>>> hex_ascii_val
'0x30'

Upvotes: 0

Related Questions