Vigenere Cipher Key 未按预期工作

Posted

技术标签:

【中文标题】Vigenere Cipher Key 未按预期工作【英文标题】:Vigenere Cipher Key not working as expected 【发布时间】:2019-08-23 19:49:15 【问题描述】:

我已经构建了一个运行良好的 Vigenere 密码函数,除了它没有通过我需要通过的编码测试这一事实。

这是因为我使用的是序数值,而我认为测试期望我使用一个函数来旋转字符串字母。

我已经解决了处理非字母字符的问题,并让它同时处理大写和小写字符。但是,如果密钥有大写或小写字符的任何变化,即密钥是小写但纯文本是大写,它似乎会崩溃。

def encrypt(text, key):
    cipher_text = []
    key = list(key) 
    if len(text) == len(key): 
        return(key) 
    else: 
        for i in range(len(text) - 
                       len(key)): 
            key.append(key[i % len(key)]) 
    for i in range(len(text)): 
        a = text[i]
        if a.isalpha() and a.islower():
            x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
            cipher_text.append(chr(x))
        elif a.isalpha() and a.isupper():
            x = ((ord(text[i]) + ord(key[i])-65) % 26 + 65)
            cipher_text.append(chr(x))
        else: 
            cipher_text.append(a) 

    return("" . join(cipher_text)) 


def main():
    mess = input(str("What is message?"))
    key = input("What is key?")
    print(encrypt(mess, key))

if __name__ == '__main__':
    main()

对于 vigenere.encrypt('BaRFoo', 'BaZ')

    You should have returned this:         
        'CaQGon'                           

    But you actually returned this:        
        'PtDTha'

【问题讨论】:

如果我使用全部大写和全部小写,我会得到不同的答案。这似乎表明您没有同时使用大写和小写。 这个短程序中有很多错误.. 1. 如果密钥长度等于源长度,它什么也不做,而是返回密钥。 2. 你从 key[i] 中减去 65 或 97,这取决于 text[i] 是低还是高。让它依赖于 key[i] 怎么样? 3. 你不能从 text[i] 中减去 65 / 97,但你应该这样做。 4. return 不是函数。不需要括号。 【参考方案1】:

从您的单个示例看来,密钥不区分大小写:

def encrypt_letter(c, k):
  if c.isupper():
    base = ord('A')
  else:
    base = ord('a')

  return chr((ord(c) - base + ord(k) - ord('a')) % 26 + base)

def encrypt(text, key):
    key = key.lower()

    return "".join([encrypt_letter(text[i], key[i % len(key)]) for i in range(len(text))])

def main():
    print(encrypt('BaRFoo', 'BaZ'))

if __name__ == '__main__':
    main()

【讨论】:

【参考方案2】:

首先,我不会用 python 编程,所以请原谅我的表格。然而,我在在线编译器中测试了所有内容。

在我回答你的问题之前,我不确定这部分:

    if len(text) == len(key): 
        return(key) 
    else: 
        for i in range(len(text) - 
                       len(key)): 
            key.append(key[i % len(key)]) 

我将其读作“如果密钥与明文具有相同的长度,则密钥就是密文”,这显然不是真的,除非密钥是“aaaaaaaaaa ...”。我希望是这样的:

    if len(text) > len(key): 
        for i in range(len(text) - 
                       len(key)): 
            key.append(key[i % len(key)])
#   else:
#       I don't care - the key is long enough

从 Kfir Dadosh 的回答中,我还要指出,您实际上并不需要这一步,不妨直接访问密钥为 key[i % len(key)]

至于您所指的问题。您只需检查明文(消息)是小写还是大写并根据那个。

        if a.isalpha() and a.islower():
            x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
Here you take raw      ^                ^
ascii value instead of |                |
normalized (0-25) number                |
                                        |
Here you normalize the key according to the
message case

以下是一些严重的剧透,所以如果你理解并想自己解决问题,那么请停止阅读这里。


我建议将规范化和加密步骤分开,以避免混淆。让我们先去掉特殊字符而不是最后,因为这很容易做到,我们只需要担心字母:

        if not (text[i].isalpha()):
            cipher_text.append(text[i]) 
            continue; # done with this symbol - skip to the next one

然后在内置方法的帮助下规范化字母。让我们使用变量 p 表示明文,k 表示密钥,c 表示密文(稍后):

        p = ord(text[i].lower()) - ord('a') # converts to lowercase, then to number
        k = ord(key[i].lower()) - ord('a')  # both key AND plaintext

我使用 ord('a') 而不是 65,因为我已经习惯了并且发现它更清晰,但这是一个偏好和语言传统的问题(我不习惯)。

然后是加密步骤:

        c = (p + k) % 26;

现在恢复大写。我们在变量 p 和 k 中销毁了它,但我们仍然有它们的源数组 text[] 具有完整的值。我们可以使用它来恢复大写(假设应该从明文继承大小写):

        if (text[i].islower()):
            cipher_text.append(chr(c + ord('a')))
        elif (text[i].isupper()):
            cipher_text.append(chr(c + ord('A')))

这样就完成了主循环。随意修改它以使其更符合 python。

    for i in range(len(text)):
        if not (text[i].isalpha()):
            cipher_text.append(text[i]) 
            continue;

        p = ord(text[i].lower()) - ord('a')
        k = ord(key[i].lower()) - ord('a')
        # k = ord(key[i % len(key)].lower()) - ord('a')
        # if you skipped the key lengthening process

        c = (p + k) % 26;

        if (text[i].islower()):
            cipher_text.append(chr(c + ord('a')))
        elif (text[i].isupper()):
            cipher_text.append(chr(c + ord('A')))
        else:
            # not sure if this can happen in python, but if it does, we're probably
            # in trouble
            # otherwise it might as well be merged with the elif above

    return("" . join(cipher_text)) 

【讨论】:

在 veprolet 和 @Kfir Dadosh 之间,我认为答案就在这里。 Kfir Dadosh 问题是特殊字符和 veprolet 我认为 python 上下文只是稍微偏离了。我会继续玩它,让你知道会发生什么。 @ChipWoodson 请注意,Kfir 的回答将代码很好地重组为函数,我避免这样做只是为了与您的代码保持更多相似性,因为我觉得函数足够短。他还跳过了密钥延长部分,直接以key[i % len(key)] 访问密钥,这样可以节省大量内存,尽管您的方法也可以。我将其编辑为我的答案。随意进一步编辑我的答案以符合 python 上下文,因为正如我所说,我对此一无所知。

以上是关于Vigenere Cipher Key 未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

Vigenere Cipher - 解密(手动)

Vigenere Cipher - 解密(手动)

PSET 2:Vigenere Cipher 部分工作?

Vigenere Cipher - 不给信[关闭]

Vigenere Cipher使用命令行提示

Vigenere Cipher 没有错误消息 Python