2013-07-01 31 views
9

Ho postato domande simili qui per un paio di giorni, ma sembra che non stavo chiedendo la cosa giusta, quindi scusami se ti ho esaurito con le mie domande XOR: D.Come eseguire XOR due stringhe esadecimali in modo che ogni byte sia XORed separatamente?

Al punto - Ho due stringhe esadecimali e voglio XOR queste stringhe in modo tale che ogni byte sia XORed separatamente (cioè ogni coppia di numeri è XORed separatamente). E voglio farlo in python, e voglio essere in grado di avere stringhe di diversa lunghezza. Farò manualmente un esempio per illustrare il mio punto (io ho usato l'ambiente di codice perché mi permette di mettere in spazi dove voglio che siano):

Input: 
s1 = "48656c6c6f" 
s2 = "61736b" 

Encoding in binary: 
48 65 6c 6c 6f = 01001000 01100101 01101100 01101100 01101111 
61 73 6b  = 01100001 01110011 01101011 

XORing the strings: 
01001000 01100101 01101100 01101100 01101111 
        01100001 01110011 01101011 
        00001101 00011111 00000100 

Converting the result to hex: 
00001101 00011111 00000100 = 0d 1f 04 

Output: 
0d1f04 

Quindi, per riassumere, voglio essere in grado di inserire due stringhe esadecimali (di solito lettere ASCII codificate in hex) di lunghezza diversa o uguale e ottenere il loro XOR in modo tale che ogni byte sia XORed separatamente.

+1

Perché non utilizzare la chiave 's2' e applicarla a * tutti * i caratteri di' s1'? Perché applicarlo solo agli ultimi 3? –

risposta

11

Usa binascii.unhexlify() per trasformare le stringhe esadecimali in dati binari, poi XOR che, tornando a esagono con binascii.hexlify():

>>> from binascii import unhexlify, hexlify 
>>> s1 = "48656c6c6f" 
>>> s2 = "61736b" 
>>> hexlify(''.join(chr(ord(c1)^ord(c2)) for c1, c2 in zip(unhexlify(s1[-len(s2):]), unhexlify(s2)))) 
'0d1f04' 

Il XOR reale è applicata per ogni byte dei dati decodificati (utilizzando ord() e chr() a andare ae da interi).

notare che, come nel tuo esempio, ho troncato s1 essere la stessa lunghezza s2 (caratteri ignorando dall'inizio del s1). È possibile codificare tutte di s1 con una chiave più corta s2 dal ciclismo al byte:

>>> from itertools import cycle 
>>> hexlify(''.join(chr(ord(c1)^ord(c2)) for c1, c2 in zip(unhexlify(s1), cycle(unhexlify(s2))))) 
'2916070d1c' 

non si hanno utilizzare unhexlify(), ma è molto più facile che loop oltre s1 e s2 2 caratteri alla volta e usando int(twocharacters, 16) per trasformarlo in valori interi per le operazioni XOR.

La versione Python 3 di quanto sopra è un po 'più leggera; utilizzare bytes() invece di str.join() e si può cadere le chr() e ord() chiamate come si arriva a iterare interi direttamente:

>>> from binascii import unhexlify, hexlify 
>>> s1 = "48656c6c6f" 
>>> s2 = "61736b" 
>>> hexlify(bytes(c1^c2 for c1, c2 in zip(unhexlify(s1[-len(s2):]), unhexlify(s2)))) 
b'0d1f04' 
>>> from itertools import cycle 
>>> hexlify(bytes(c1^c2 for c1, c2 in zip(unhexlify(s1), cycle(unhexlify(s2))))) 
b'2916070d1c' 
+1

Grazie per la risposta! Quello che non capisco, è questa parte: per c1, c2 in zip (non sillabare (s1), ciclo (svelare (s2))))) Il fatto è che sono nuovo in Python e facilmente confuso .Penso che la funzione zip abbia qualcosa a che fare con gli array, ma non so come funzionino in Python. Inoltre, ho pensato che i loop avessero un solo contatore, ma qui ci sono due - c1 e c2, che mi confondono anch'essi. –

+1

'zip()' accetta più sequenze di input e accoppia i loro elementi. Quindi ti dà una sequenza di '[(s1 [0], s2 [0]), (s1 [1], s2 [1]), ...]' con ogni tupla formata prendendo elementi da ciascuna sequenza di input a quello stesso indice. –

+1

@NorsulRonsul: Perché in questo caso 'zip()' ha due liste di input, ogni elemento di output è una tupla con due valori. Il ciclo 'for' scompatta quelli in due valori (proprio come si può fare tuple decomprimere in assegnazioni regolari,' foo, bar = ('spam', 'uova') 'assegna' foo = 'spam'' e 'bar =' uova '. –

1

Non sono sicuro di quello che stai cercando esattamente, ma spero che questo sia utile per voi .

>>> def getstr(encoded): 
    return "".join([chr(int(i+k, 16))for (i,k) in zip(encoded[0::2], encoded[1::2])]) 

>>> getstr(s1) 
'Hello' 

>>> getstr(s2) 
'ask' 

partire con due stringhe normali, si possono trovare i risultati facendo qualcosa di simile:

>>> "".join(reversed(["%02X" % (ord(c1)^ord(c2)) for c1, c2 in zip(reversed(getstr(s1)),  reversed(getstr(s2)))])) 
'0D1F04' 
7

ho trovato una soluzione molto semplice:

def xor_str(a,b): 
    result = int(a, 16)^int(b, 16) # convert to integers and xor them 
    return '{:x}'.format(result)  # convert back to hexadecimal 

Sarà XOR la ​​corda fino a uno dei temi termina

+1

Mi disturba sempre quando le persone non usano il formato incorporato. 'formato di ritorno (risultato, 'x')'. – Veky