【问题标题】:Single-Byte XOR Cipher (python)单字节异或密码(python)
【发布时间】:2017-01-24 03:23:09
【问题描述】:

这是我目前正在学习的现代密码学课程。

挑战是密码挑战 3:单字节异或密码,我正在尝试使用 python 3 来帮助完成。

我知道我应该对字符串进行异或并转换为英文。十六进制字符串为“1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736”,其转换到“806748453371902409051174291875458592743800337585421566549206796642836053682239286”十进制形式。

我对多个十六进制字节组合(2 个十六进制数字)进行了异或运算,但我不知道如何将其转换为英文。在这一点上只是蛮力和有根据的猜测吗?

我知道 ETAOIN SHRDLU,但这并没有那么有用。

感谢您的时间和帮助。


添加: 此外,我尝试了挑战 #4,但此代码似乎不起作用。但它确实适用于挑战 #3,所以我很困惑。

Challenge #3 Challenge #4

【问题讨论】:

  • 你有解密密码的密钥吗?
  • 有 256 个可能的键。它是两个十六进制字符的任意组合。我已经尝试了很多,但我不知道要寻找什么才能选择密钥。

标签: python string python-3.x byte


【解决方案1】:

您可以使用binascii.hexlifybinascii.unhexlify 将字节字符串转换为十六进制,反之亦然:

>>> import binascii
>>> binascii.hexlify(b'HELLO')  # to Hex
b'48454c4c4f'
>>> binascii.unhexlify('48454c4c4f')  # from Hex
b'HELLO'

使用str.isprintable,可以过滤掉不可打印的候选:

>>> 'abcd'.isprintable()
True
>>> '\x00'.isprintable()
False
>>> '\x7f'.isprintable()
False

import binascii

encoded = binascii.unhexlify('1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736')
for xor_key in range(256):
    decoded = ''.join(chr(b ^ xor_key) for b in encoded)
    if decoded.isprintable():
        print(xor_key, decoded)

【讨论】:

  • 您可以使用 ETAOIN SHRDLU 找到正确的解码消息。
  • 这可能是使用上面的代码得到的答案:像一磅培根一样烹饪 MC
  • @StefanPochmann,我试过了,发现ETAOIN SHRDLU不是消息。
  • @falsetru 我尝试以两种不同的方式将其用作权重,都得到了正确的结果。
  • @PhillipSloan,请阅读以下内容:List comprehensionGenerator expressionstr.joinchr
【解决方案2】:

基于@falsetru 的答案,但仅显示具有最多空格字符的解码字符串:

>>> encoded = '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736'
>>> import binascii
>>> nums = binascii.unhexlify(encoded)
>>> strings = (''.join(chr(num ^ key) for num in nums) for key in range(256))
>>> max(strings, key=lambda s: s.count(' '))
"Cooking MC's like a pound of bacon"

您可以使用ETAOIN SHRDLU(“英语中最常用的12个字母的大致频率顺序”)来代替计算空格,但这里没有必要。

顺便说一句,我认为如果你链接到the challenge 会很好。


编辑: 或者,您可以尝试找到密钥(或一些最有希望的密钥),然后仅使用该密钥(或那几个密钥)进行解码。例如,假设计算空格将确定获胜者:

>>> encoded = '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736'
>>> import binascii
>>> nums = binascii.unhexlify(encoded)
>>> key = max(nums, key=nums.count) ^ ord(' ')
>>> ''.join(chr(num ^ key) for num in nums)
"Cooking MC's like a pound of bacon"

这甚至可以很容易地手动完成(尽管挑战告诉你不要这样做)。

【讨论】:

  • 注明。我将来会这样做。您将如何使用 ETAOIN SHRDLU 对字符进行加权?我应该用手找到钥匙。
  • @PhillipSloan 谁说你应该手工完成?不是挑战。挑战恰恰相反,您应该手动完成。对于权重,我只是注意到,如果我只使用 12 个字母,而不是像昨天那样包括中间的空格,我实际上很难将正确的结果作为最高值的字符串......
  • 哦,好吧。我完全误读了它。我认为它的意思是“手工完成。不要编写代码来为你做这件事。”谢谢你的澄清。标点符号很重要。
  • @PhillipSloan 我已经用我的第一种方法解决了挑战#4,只需使用每个可能的键解码每个字符串并使用最多空格字符打印结果。如果这对您不起作用,请尝试打印更多的最佳候选人,而不仅仅是一个。总的来说,只有两个空格字符数最多,正确答案就是其中之一。
  • @PhillipSloan 另外,我在上面的评论中建议的权重效果很好。正确答案得到353分,第二高的只有318分。
【解决方案3】:

通过观察你可以在编码字符串中找到“3737”,所以它可以是“e”,“E”,“o”,“O”,“r”,“R”对于一个英文单词可能是? 使用逆向工程,XOR 结果显示 "R","r","X","x","E","e" 作为势键。 尝试这些潜力 Keys 后,您将获得“X”是关键 ;-)

【讨论】:

    猜你喜欢
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 2014-06-12
    • 2015-03-24
    相关资源
    最近更新 更多