10

几天来我一直在这里发布类似的问题,但似乎我没有问正确的问题,所以如果我的 XOR 问题让你筋疲力尽,请原谅:D。

直截了当-我有两个十六进制字符串,我想对这些字符串进行异或运算,以便每个字节分别进行异或运算(即每对数字分别进行异或运算)。我想在python中做到这一点,我希望能够拥有不同长度的字符串。我将手动做一个例子来说明我的观点(我使用了代码环境,因为它允许我在我想要的地方放置空间):

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

所以,总而言之,我希望能够输入两个不同或相等长度的十六进制字符串(这些通常是用十六进制编码的 ASCII 字母),并获得它们的异或,使得每个字节分别进行异或。

4

3 回答 3

13

用于binascii.unhexlify()将您的十六进制字符串转换为二进制数据,然后将其异或,返回到十六进制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'

实际 XOR 应用于解码数据的每个字节(使用ord()chr()来往来于整数)。

请注意,就像在您的示例中一样,我将其截断为与(忽略开头的字符)s1相同的长度。您可以通过循环字节来使用较短的密钥对所有内容进行编码:s2s1s1s2

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

您不必使用unhexlify(),但它比一次循环遍历2 个字符并使用s1将其转换为整数值进行异或运算要容易得多。s2int(twocharacters, 16)

上面的 Python 3 版本要轻一些;使用bytes()而不是,您可以在直接迭代整数str.join()时删除chr()and调用:ord()

>>> 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'
于 2013-07-01T12:46:20.867 回答
6

我找到了一个非常简单的解决方案:

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

它将对字符串进行异或运算,直到其中一个主题结束

于 2013-08-20T07:35:20.733 回答
1

我不确定您到底在寻找什么,但希望这对您有用。

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

从两个普通字符串开始,你会发现你的结果是这样的:

>>> "".join(reversed(["%02X" % (ord(c1) ^ ord(c2)) for c1, c2 in zip(reversed(getstr(s1)),       reversed(getstr(s2)))]))
'0D1F04'
于 2013-07-01T13:03:12.907 回答