我的凯撒密码的输出无法解密为 Python、Windows 中的原始字符串

My Caesar cipher's output won't decrypt to the original string in Python, Windows

我写了一个简单的凯撒密码代码来获取一个字符串和一个位置偏移参数,即加密字符串的密码。但是,我已经意识到某些输出无法正确解密。例如:

python .\caesar_cipher.py 'fortuna' 6771 --encrypt 输出 ☼↑↔▲↨
python .\caesar_cipher.py '☼↑↔▲↨' 6771 --decrypt输出\`,/UC(\应该是`原谅我的markdown技巧)

我相当确定存在一些编码问题,但我无法查明。如果我只是在同一个 运行 输出中加密和解密,而不是在两个 运行 之间打印和传递它作为命令行参数似乎是正确的。
我正在使用 windows 并尝试 运行 在 cmd 和 PowerShell 中对上面的示例(以及其他几个)进行测试。

这是我的代码:

import argparse

# 127 number of chars in ascii
NO_OF_CHARS = 127


def encrypt(s: str) -> str:
    return ''.join([chr((ord(c)+cipher) % NO_OF_CHARS) for c in s])


def decrypt(s: str) -> str:
    return ''.join([chr((ord(c)-cipher) % NO_OF_CHARS) for c in s])


parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--encrypt", help="encrypt the string", action="store_true")
group.add_argument("--decrypt", help="decrypt the string", action="store_true")
parser.add_argument("string", type=str, help="string to encrypt/decrypt")
parser.add_argument("cipher", type=int,
                    help="positional shift amount for caesar cipher")
args = parser.parse_args()

string = args.string

encrypt_arg = args.encrypt
decrypt_arg = args.decrypt
cipher = args.cipher

if encrypt_arg:
    result = encrypt(string)

else:
    result = decrypt(string)

print(result)

我认为问题出在复制和粘贴值加密之后。当我测试这段代码时,我发现和你也提到了,通过存储在变量中直接将加密值传递给解密函数不会导致任何问题,但是直接粘贴时会导致问题。

为了解决这个问题,您可以通过将加密文本以二进制编码写入文件,然后从该文件中读取来写入加密文本。

文件名必须传递给 CLI 和 CIPHER,它会给你正确的输出。

这可行:

import argparse
# 127 number of chars in ascii
NO_OF_CHARS = 127


def encrypt(s: str) -> str:
    return ''.join([chr((ord(c)+cipher) % NO_OF_CHARS) for c in s])


def decrypt(s: str) -> str:
    return ''.join([chr((ord(c)-cipher) % NO_OF_CHARS) for c in s])


parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--encrypt", help="encrypt the string", action="store_true")
group.add_argument("--decrypt", help="decrypt the string", action="store_true")
parser.add_argument("string", type=str, help="string to encrypt/decrypt")
parser.add_argument("cipher", type=int,
                    help="positional shift amount for caesar cipher")
args = parser.parse_args()

string = args.string

encrypt_arg = args.encrypt
decrypt_arg = args.decrypt
cipher = args.cipher

if encrypt_arg:
    result = encrypt(string)
    with open('encrypt','wb') as f:
        a = result.encode(encoding='utf-8')
        f.write(a)
        f.close()
        print("Encrypted File created with name encrypt")

else:
    with open(string,'rb') as r:
        text = r.readlines()
        print(decrypt(text[0].decode('utf-8')))

测试:

$ python caesar_cipher.py 'fortuna' 6771 --encrypt

Encrypted File created with name encrypt

$ python caesar_cipher.py 'encrypt' 6771 --解密

fortuna

如@KnowledgeGainer 所述,您的代码没有问题。出现此问题是因为您从终端复制了加密输出,并将其用作解密输入。您正在使用的终端正在尽力解释一些潜在的不可打印控制字符 - fortuna 有七个字符,但 ☼↑↔▲↨ 似乎只有五个 - 但这些显然是 unicode 字符。在凯撒密码中,您的明文和加密消息的长度应该相同,因此很明显终端正在将一个或多个“输出字节”映射到 unicode 字符。它以何种方式执行此操作对我来说并不是很明显。

添加 print(' '.join([str(ord(c)) for c in result]))print(result)。然后你看到 result 包含 32 (0x20) 以下的不可打印字符:15,24,27,29,30,23,10.

这里有一个可能的技术如何保持在 可打印 范围 ASCII:

NO_OF_NOPRNT =  32                 # number of unprintable chars in ascii
NO_OF_CHARS  = 128 - NO_OF_NOPRNT  # number of   printable chars in ascii

def encrypt(s: str) -> str:
    return ''.join([chr(((ord(c)-NO_OF_NOPRNT+cipher) % NO_OF_CHARS)+NO_OF_NOPRNT) for c in s])


def decrypt(s: str) -> str:
    return ''.join([chr(((ord(c)-NO_OF_NOPRNT-cipher) % NO_OF_CHARS)+NO_OF_NOPRNT) for c in s])

对您的脚本进行上述改进:

.\SO519212.py  "fortunaX" 6771 --encrypt
9BEGHA4+
.\SO519212.py  "9BEGHA4+" 6771 --decrypt
fortunaX