# how to do bitwise exclusive or of two strings in python?

Each Answer to this Q is separated by one/two green lines.

I would like to perform a bitwise exclusive or of two strings in python, but xor of strings are not allowed in python. How can I do it ?

You can convert the characters to integers and xor those instead:

``````l = [ord(a) ^ ord(b) for a,b in zip(s1,s2)]
``````

Here’s an updated function in case you need a string as a result of the XOR:

``````def sxor(s1,s2):
# convert strings to a list of character pair tuples
# go through each tuple, converting them to ASCII code (ord)
# perform exclusive or on the ASCII code
# then convert the result back to ASCII (chr)
# merge the resulting array of characters as a string
return ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2))
``````

See it working online: ideone

If you want to operate on bytes or words then you’ll be better to use Python’s array type instead of a string. If you are working with fixed length blocks then you may be able to use H or L format to operate on words rather than bytes, but I just used ‘B’ for this example:

``````>>> import array
>>> a1 = array.array('B', "https://stackoverflow.com/questions/2612720/Hello, World!")
>>> a1
array('B', [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33])
>>> a2 = array.array('B', ('secret'*3))
>>> for i in range(len(a1)):
a1[i] ^= a2[i]

>>> a1.tostring()
';\x00\x0f\x1e\nXS2\x0c\x00\t\x10R'
``````

For bytearrays you can directly use XOR:

``````>>> b1 = bytearray("test123")
>>> b2 = bytearray("321test")
>>> b = bytearray(len(b1))
>>> for i in range(len(b1)):
...   b[i] = b1[i] ^ b2[i]

>>> b
bytearray(b'GWB\x00TAG')
``````

Here is your string XOR’er, presumably for some mild form of encryption:

``````>>> src = "https://stackoverflow.com/questions/2612720/Hello, World!"
>>> code = "secret"
>>> xorWord = lambda ss,cc: ''.join(chr(ord(s)^ord(c)) for s,c in zip(ss,cc*100))
>>> encrypt = xorWord(src, code)
>>> encrypt
';\x00\x0f\x1e\nXS2\x0c\x00\t\x10R'
>>> decrypt = xorWord(encrypt,code)
>>> print decrypt
Hello, World!
``````

Note that this is an extremely weak form of encryption. Watch what happens when given a blank string to encode:

``````>>> codebreak = xorWord("      ", code)
>>> print codebreak
SECRET
``````

the one liner for python3 is :

``````def bytes_xor(a, b) :
return bytes(x ^ y for x, y in zip(a, b))
``````

where `a`, `b` and the returned value are `bytes()` instead of `str()` of course

can’t be easier, I love python3 🙂

``````def strxor (s0, s1):
l = [ chr ( ord (a) ^ ord (b) ) for a,b in zip (s0, s1) ]
return ''.join (l)
``````

If the strings are not even of equal length, you can use this

``````def strxor(a, b):     # xor two strings of different lengths
if len(a) > len(b):
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
else:
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])
``````

Do you mean something like this:

``````s1 = '00000001'
s2 = '11111110'
int(s1,2) ^ int(s2,2)
``````

Below illustrates XORing string s with m, and then again to reverse the process:

``````>>> s="hello, world"
>>> m='markmarkmark'
>>> s="".join(chr(ord(a)^ord(b)) for a,b in zip(s,m))
>>> s
'\x05\x04\x1e\x07\x02MR\x1c\x02\x13\x1e\x0f'
>>> s="".join(chr(ord(a)^ord(b)) for a,b in zip(s,m))
>>> s
'hello, world'
>>>
``````

``````def xor_strings(s1, s2):
max_len = max(len(s1), len(s2))
s1 += chr(0) * (max_len - len(s1))
s2 += chr(0) * (max_len - len(s2))
return ''.join([chr(ord(c1) ^ ord(c2)) for c1, c2 in zip(s1, s2)])
``````

I’ve found that the ”.join(chr(ord(a)^ord(b)) for a,b in zip(s,m)) method is pretty slow. Instead, I’ve been doing this:

``````fmt="%dB" % len(source)
s = struct.unpack(fmt, source)
m = struct.unpack(fmt, xor_data)
final = struct.pack(fmt, *(a ^ b for a, b in izip(s, m)))
``````

Based on William McBrine’s answer, here is a solution for fixed-length strings which is 9% faster for my use case:

``````import itertools
import struct
def make_strxor(size):
def strxor(a, b, izip=itertools.izip, pack=struct.pack, unpack=struct.unpack, fmt="%dB" % size):
return pack(fmt, *(a ^ b for a, b in izip(unpack(fmt, a), unpack(fmt, b))))
return strxor
strxor_3 = make_strxor(3)
print repr(strxor_3('foo', 'bar'))
`````` The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .