¿Cómo hacer bitwise exclusivo o de dos cadenas en python?

Me gustaría interpretar un bit exclusivo o de dos cadenas en python, pero xor de cadenas no están permitidas en python. Cómo puedo hacerlo ?

Puedes convertir los caracteres a enteros y xor esos en su lugar:

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

Aquí hay una función actualizada en caso de que necesite una cadena como resultado de 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)) 

Véalo trabajando en línea: ideone

Si desea operar con bytes o palabras, entonces será mejor usar el tipo de matriz de Python en lugar de una cadena. Si está trabajando con bloques de longitud fija, es posible que pueda usar el formato H o L para operar con palabras en lugar de bytes, pero solo usé ‘B’ para este ejemplo:

 >>> import array >>> a1 = array.array('B', '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' 

Para bytearrays puedes usar directamente 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') 

Aquí está su cadena XOR’er, probablemente para alguna forma suave de cifrado:

 >>> src = "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! 

Tenga en cuenta que esta es una forma extremadamente débil de cifrado. Mira lo que sucede cuando se le da una cadena en blanco para codificar:

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

El único forro para python3 es:

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

donde a , b y el valor devuelto son bytes() lugar de str() por supuesto

No puede ser más fácil, me encanta python3 🙂

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

(Basado en la respuesta de Mark Byers.)

Si las cadenas no tienen la misma longitud, puede usar esto

 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)])]) 

Te refieres a algo como esto:

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

A continuación se ilustra la cadena XORing con m, y luego nuevamente para revertir el proceso:

 >>> 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)]) 

Descubrí que el método ” .join (chr (ord (a) ^ ord (b)) para a, b en zip (s, m)) es bastante lento. En cambio, he estado haciendo esto:

 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))) 

Basado en la respuesta de William McBrine, aquí hay una solución para cadenas de longitud fija que es un 9% más rápida para mi caso de uso:

 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'))