【问题标题】:Reverse engineer Ceasar cipher逆向工程凯撒密码
【发布时间】:2020-07-02 20:01:46
【问题描述】:

我反向工程解密,但没有得到预期的结果。

例如输入

Lipps${svph%

偏移量为 4 的结果应该是

Hello World!

但我明白了

ello´world³

我做错了什么?

code = input("Enter text to decrypt: ")
distance = int(input("Enter number of offset: "))
plainText = ''
for ch in code:
    ordValue = ord(ch)
    cipherValue = ordValue - distance
    if cipherValue < ord('a'):
        cipherValue = ord('z') - \
            (distance - (ord('a') - ordValue + 1))
    plainText += chr(cipherValue)
print(plainText)

【问题讨论】:

  • 你为什么使用if cipherValue &lt; ord('a')
  • 之前做过凯撒解密/加密。您是否考虑过生成地图字典而不是尝试执行 ord 然后大写转换?这种转变是你问题的一部分。
  • 我对python的了解有限,只知道课文教什么。
  • 作为一个更新,我已经尝试修改我当前的代码几次,但仍然有相同的意外结果。
  • 我可能对此一无所知,但我认为凯撒密码保持在相同的 a-zA-Z 范围内,那么非字母数字来自哪里?覆盖范围的上限和下限是多少?

标签: python reverse-engineering


【解决方案1】:

好的,我让它为 a-z 工作,并给了你一个小测试框架来自动输入/检查,而不是每次都输入它。

def dowork(code, distance, lower, upper):


    bounddown, boundup = ord(lower), ord(upper)

    plaintext = ""
    for ch in code:
        ordValue = ord(ch)
        cipherValue = ordValue - distance
        if cipherValue < bounddown:
            cipherValue = boundup - bounddown - ordValue +1

        plaintext += chr(cipherValue)


    return plaintext

dataexp = [
    (("jgnnq",2, 'a', 'z'),"hello"),
    ]

for input_, exp in dataexp:
    got = dowork(*input_)
    msg = "exp:%s:%s:got for %s" % (exp, got, inp)
    if exp == got:
        print("good! %s" % msg)
    else:
        print("bad ! %s" % msg)

这会打印出来

good! exp:hello:hello:got for ('jgnnq', 2, 'a', 'z')

现在您需要做的就是在 dataexp 列表中添加一个额外的项目,例如

(("Lipps${svph%", 4, &lt;lowerbound&gt;, &lt;upperbound char&gt;), "Hello World!")

一旦你确定了上限和下限,它应该可以工作。请注意,我不知道凯撒密码,我只是直接复制了您的,但对其进行了一些重组。

*_input 所做的是在该元组(或多或少的列表)中获取这 4 个值,并将它们分配给 dowork 函数中的 code, distance, lower, upper

lower 对应于代码中的aupper 对应于z

exp 是你所期望的,exp == got 只是检查函数返回的内容是否正确。一旦你得到正确的功能,它应该适用于both我简单的a-z,2距离,hello测试和你更复杂的4距离,但包括标点符号

上下界

您的 2 个字符串,输入和输出,分别是 Lipps${svph%Hello World!。这意味着所有这些字符都需要在您的上下顺序值范围内,对吗?所以所有这些中的最小排序位置是你的lower,最大值是你的upper。现在,我不是 Cryptonomicon 的人,我不记得 ord(a)

最终版本

这不需要您弄清楚将哪个字符放在下限以及哪个字符放在上限。我们取 lower = 32(可打印字符的开头),upper = 255。这样标点符号、大小写、数字、它们的 ord 值就不再重要了。

#full ASCII range, you can go to town on entering whatever you want
bounddown, boundup = 32, 255

plaintext = ""
for ch in code:
    ordValue = ord(ch)
    cipherValue = ordValue - distance
    if cipherValue < bounddown:
        cipherValue = boundup - bounddown - ordValue +1

    plaintext += chr(cipherValue)

【讨论】:

  • 感谢您的意见。您的代码不包含输入文本和距离的选项,而是一个预先编写的数据库?
  • 这样说吧。当dowork 很好时,您可以再次粘贴您的用户询问代码。同时,它可以防止您每次都手动输入它而让自己发疯。 database 是一个相当宏大的术语,但是,是的,这就是 dataexp 的用途。
  • 我剪切并粘贴了相同的小愚蠢循环来测试稍微复杂的功能,比如你的凯撒,这样我就不需要手动检查多次运行。 你的代码已经是正确的了,你只需要注意你的边界测试。
  • 好的,我正在尝试修改输出以便它只显示转换。试图找出要编辑的内容。
  • hmm,暂时保留输出,因为它会为您显示测试结果。弄清楚你的lower, upper,看看dowork 是否有效,一旦完成,你就可以去镇上重组。事实上,一旦你有一个工作的dowork,别管我的代码,复制dowork,硬编码upperlower,然后放回你的用户输入代码和输出。如果您还没有使用过源代码控制的奇迹,git 可用于跟踪有效和无效的副本
【解决方案2】:

这是一个在输入一定范围内的字符时进行加密和解密的实现(在本例中为a-z)。您可以根据需要将其调整为其他范围。

def caesar(text, offset, decrypt=False):
    lower_bound, upper_bound = ord('a'), ord('z')
    if decrypt:
        offset = (upper_bound - lower_bound + 1) - offset
    result = ''
    for t in text:
        o = ord(t)
        if lower_bound <= o <= upper_bound:
            new_t = o + offset
            if new_t > upper_bound:
                new_t = (new_t % upper_bound) + lower_bound - 1
            result += chr(new_t)
        else:
           result += t
    return result

然后你可以调用:

caesar(caesar('hello world!', 2,), 2, True)
# => 'hello world!'

【讨论】:

  • 简化,曾经我想到的只是使用 chr(0), chr(255), 完整的 ASCII 范围。整个概念与简单的 caesar 和您的代码相同,只是不需要担心 *@%&~ 位置 ;-)
  • 好的,我理解并更改了程序,它有效。谢谢
  • @wilmckenzie 如果您对答案感到满意,请点赞并将其标记为已解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 2020-05-31
  • 2014-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
相关资源
最近更新 更多