Xor Hex/ASCII/Conversion Issue - python

So I have a problem where I want to xor various hex strings, convert them to regular english strings, then re-convert them to hex strings. I'm not really familiar with working with hex or xor in any meaningful way, however. Do I need to convert the hex to binary or unicode before I perform a bitwise xor operation? If so, how do I retrieve the hex values once that is done? I've been looking into using str.encode('hex') and str.decode('hex'), but I keep getting errors saying that I am using non-hexadecimal characters. In short, I'm totally lost.

Python has an XOR operator for integers: ^. Here's how you could use it:
>>> hex(int("123abc", 16) ^ int("def456", 16))
'0xccceea'
EDIT: testing with long hex strings as per your comment:
>>> def hexor(hex1, hex2):
... """XOR two hex strings."""
... xor = hex(int(hex1, 16) ^ int(hex2, 16))
... return xor[2:].rstrip("L") # get rid of "0x" and maybe "L"
...
>>> import random
>>> a = "".join(random.choice("0123456789abcdef") for i in range(200))
>>> b = "".join(random.choice("0123456789abcdef") for i in range(200))
>>> a
'8db12de2f49f092620f6d79d6601618daab5ec6747266c2eea29c3493278daf82919aae6a72
64d4cf3dffd70cb1b6fde72ba2a04ac354fcb871eb60e088c2167e73006e0275287de6fc6133
56e44d7b0ff8378a0830d9d87151cbf3331382b096f02fd72'
>>> b
'40afe17fa8fbc56153c78f504e50a241df0a35fd204f8190c0591eda9c63502b41611aa9ac2
27fcd1a9faea642d89a3a212885711d024d2c973115eea11ceb6a57a6fa1f478998b94aa7d3e
993c04d24a0e1ac7c10fd834de61caefb97bcb65605f06eae'
>>> hexor(a, b)
'cd1ecc9d5c64cc47733158cd2851c3cc75bfd99a6769edbe2a70dd93ae1b8ad36878b04f0b0
43281e94053d689c3f5e45392af75b13702e7102fa3e0a990ca0db096fcff60db1f672561c0d
cfd849a945f62d4dc93f01ecaf30011c8a6849d5f6af293dc'

#user1427661: you are seeing the same output as one of the input(say input1) because -
len(input1) > len(input2)
What you possibly can do now is apply a check on the length of the two strings and strip the larger one to match the size of the smaller one (because rest of the part is anyways useless) with something like this-
if len(input1) > len(input2):
input1 = input1[:len(b)]
Likewise an else condition.
Let me give you a more simpler answer (ofcourse in my opinion!). You may use the in-built 'operator' package and then directly use the xor method in it.
http://docs.python.org/2/library/operator.html
Hope this helps.

Related

convert str 'A123456' to bytes b'\x0A\x12\x34\x56' in python

I use python 2.7 and windows.
I want to convert string'A123456' to bytes: b'\x0A\x12\x34\x56' and then concatenate it with other bytes (b'\xBB') to b'\xbb\x0A\x12\x34\x56'.
That is, I want to obtain b'\xbb\x0A\x12\x34\x56' from string'A123456' and b'\xBB'
This isn't too hard to do with binascii.unhexlify, the only problem you've got is that you want to zero pad your string when it's not an even number of nibbles (unhexlify won't accept a length 7 string).
So first off, it's probably best to make a quick utility function that does that, because doing it efficiently isn't super obvious, and you want a self-documenting name:
def zeropad_even(s):
# Adding one, then stripping low bit leaves even values unchanged, and rounds
# up odd values to next even value
return s.zfill(len(s) + 1 & ~1)
Now all you have to do is use that to fix up your string before unhexlifying it:
>>> from binascii import unhexlify
>>> unhexlify(zeropad_even('A123456'))
'\n\x124V'
>>> _ == b'\x0A\x12\x34\x56'
True
I included that last test just to show that you got the expected result; the repr of str tries to use printable ASCII or short escapes where available, so only the \x12 actually ends up in the repr; \x0A' becomes \n, \x34 is 4 and \x56 is V, but those are all equivalent ways to spell the same bytes.

xor with leading zero issue in python

I want to xor two hex-format strings in python, like '45' and '4e'. But how do I keep the leading zero if the result is in [0x00, 0x0f]?
hex(int('45', 16) ^ int('4e', 16))
gives '0xb', while I'm expecting '0x0b'.
Thanks in advance.
The easiest method is to use str.format():
>>> '0x{:02x}'.format(0xb)
'0x0b'
For a relatively small number of values (like 0x00-0xff), one practical as well as very efficient method to convert the result into hexadecimal string the way you wish is to build and use a look-up table. The '0x%02x' % vexpression employed in building the table would also be a simple and fairly concise way of converting a single value just once.
>>> HEXDEC = ['0x%02x' % v for v in (x+y for x in range(16) for y in range(16))]
>>> HEXDEC[int('45', 16) ^ int('4e', 16)]
'0x0b'
>>>
The problem here is your expectations from the function hex.
hex() only produces a string presentation for output.
Proof:
>>> hex(2)+hex(15)
'0x20xf'
Which is utter nonsense of course since the string value of hex(2) and the string value of hex(15) are just being appended together.
The solution is to do your arithmetic clear though to the end THEN select how you wish to present the result.
The result of your calculation is 11:
>>> int('45', 16) ^ int('4e', 16)
11
Then format it.
Old way:
>>> '0x%0.2x' % 11
'0x0b'
Newer way:
>>> '0x'+format(11,'02x')
'0x0b'
Or:
>>> '0x{:02x}'.format(11)
'0x0b'

Split integer into two concatenated hex strings- Python

I need to transmit a value that is larger than 65535 via two different hex strings so that when the strings are received, they can be concatenated to form the integer again. For example if the value was 70000 then the two strings would be 0x0001 and 0x1170.
I thought it would be as simple as converting the integer to hex then shifting it right by 4 to get the top string and removing all but the last 4 characters for the bottom.
I think I might be struggling with some syntax (fairly new to Python) and probably some of the logic too. Can anyone think of an easy way to do this?
Thanks
Use divmod builtin function:
>>> [hex(x) for x in divmod(70000, 65536)]
['0x1', '0x1170']
Your algorithm can be implemented easily, as in Lev Levitsky's answer:
hex(big)[2:-4], hex(big)[-4:]
However, it will fail for numbers under 65536.
You could fix that, but you're probably better off splitting the number, then converting the two halves into hex, instead of splitting the hex string.
ecatmur's answer is probably the simplest way to do this:
[hex(x) for x in divmod(70000, 65536)]
Or you could translate your "shift right/truncate" algorithm on the numbers like this:
hex(x >> 16), hex(x & 0xFFFF)
If you need these to be strings like '0x0006' rather than '0x6', instead of calling hex on the parts, you can do this:
['%#06x' % (x,) for x in divmod(x, 65536)]
Or, using the more modern string formatting style:
['0x{:04x}'.format(x) for x in divmod(x, 65536)]
But on the other side, you again probably want to undo this by converting to ints first and then shifting and masking the numbers, instead of concatenating the strings. The inverse of ecatmur's answer is:
int(bighalf) * 65536 + int(smallhalf)
The (equivalent) inverse of the shift/mask implementation is:
(int(bighalf) << 16) | int(smallhalf)
And in that case, you don't need the extra 0s on the left.
It's also worth pointing out that none of these algorithms will work if the number can be negative, or greater than 4294967295, but only because the problem is impossible in those cases.
You mean like this?
In [1]: big = 12345678
In [2]: first, second = hex(big)[2:][:-4], hex(big)[2:][-4:]
In [3]: first, second
Out[3]: ('bc', '614e')
In [4]: int(first+second, 16)
Out[4]: 12345678
Being wary of big/little endians, what you could do to keep it simple is:
val = 70000
to_send = '{:08X}'.format(val) # '00011170'
decoded = int('00011170', 16) # 70000
EDIT: to be very clear then...
hex1, hex2 = to_send[:4], to_send[4:] # send these two and on receipt
my_number = int(hex1 + hex2, 16)
for numbers greater than 65536 or for numbers whose with length >=5, you can use slicing:
>>> num=70000
>>> var1=hex(num)[:-4]
>>> var2='0x'+hex(num)[-4:]
>>> integ=int(var1+var2[2:],16)
>>> print(integ)
70000

How do I convert a string of bits to a hex string in Python?

I have a bit-string of 32 characters that I need to represent as hexadecimal in Python. For example, the string "10000011101000011010100010010111" needs to also be output as "83A1A897".
Any suggestions on how to best go about this in Python?
To format to hexadecimal you can use the hex function:
>>> hex(int('10000011101000011010100010010111', 2))
0x83a1a897
Or to get it in exactly the format you requested:
>>> '%08X' % int('10000011101000011010100010010111', 2)
83A1A897
>>> binary = '10010111'
>>> int(binary,2)
151
>>> hex(int(binary,2))
'0x97'
I hope this helps!
You can do this very easy with build in functions.
The first thing you want to do is convert your binary to an integer:
>> int("1010",2)
10
The second step then would be to represent this as hex:
>> "%04X" % int("1010",2)
'000A'
in case you don't want any predefined length of the hex string then just use:
>> "%X" % int("1010",2)
'A'
>> "0x%X" % int("1010",2)
'0xA'
To read in a number in any base use the builtin int function with the optional second parameter specifying the base (in this case 2).
To convert a number to a string of its hexadecimal form just use the hex function.
>>> number=int("10000011101000011010100010010111",2)
>>> print hex(number)
0x83a1a897L
Well we could string format just like Mark Byers said.Or in other way we could string format in another method like given below:
>>> print('{0:x}'.format(0b10000011101000011010100010010111))
83a1a897
To make the alphabets between the hex in upper case try this:
>>> print('{0:X}'.format(0b10000011101000011010100010010111))
83A1A897
Hope this is helpful.

Is there a way to pad to an even number of digits?

I'm trying to create a hex representation of some data that needs to be transmitted (specifically, in ASN.1 notation). At some points, I need to convert data to its hex representation. Since the data is transmitted as a byte sequence, the hex representation has to be padded with a 0 if the length is odd.
Example:
>>> hex2(3)
'03'
>>> hex2(45)
'2d'
>>> hex2(678)
'02a6'
The goal is to find a simple, elegant implementation for hex2.
Currently I'm using hex, stripping out the first two characters, then padding the string with a 0 if its length is odd. However, I'd like to find a better solution for future reference. I've looked in str.format without finding anything that pads to a multiple.
def hex2(n):
x = '%x' % (n,)
return ('0' * (len(x) % 2)) + x
To be totally honest, I am not sure what the issue is. A straightforward implementation of what you describe goes like this:
def hex2(v):
s = hex(v)[2:]
return s if len(s) % 2 == 0 else '0' + s
I would not necessarily call this "elegant" but I would certainly call it "simple."
Python's binascii module's b2a_hex is guaranteed to return an even-length string.
the trick then is to convert the integer into a bytestring. Python3.2 and higher has that built-in to int:
from binascii import b2a_hex
def hex2(integer):
return b2a_hex(integer.to_bytes((integer.bit_length() + 7) // 8, 'big'))
Might want to look at the struct module, which is designed for byte-oriented i/o.
import struct
>>> struct.pack('>i',678)
'\x00\x00\x02\xa6'
#Use h instead of i for shorts
>>> struct.pack('>h',1043)
'\x04\x13'

Categories