用字母的随机移位解密消息

Decrypt message with random shift of letters

我正在编写一个程序来解密一条消息,并且只假设解密消息的最大出现字母是“e”。没有给出班次编号。下面的代码是我的工作。我只能硬编码班次号码来解密给定的消息,但如果消息更改我的代码当然不起作用。

from collections import Counter
import string

message = "Zyp cpxpxmpc ez wzzv fa le esp delcd lyo yze ozhy le jzfc qppe Ehz ypgpc rtgp fa hzcv Hzcv rtgpd jzf xplytyr lyo afcazdp lyo wtqp td pxaej hteszfe te Escpp tq jzf lcp wfnvj pyzfrs ez qtyo wzgp cpxpxmpc te td espcp lyo ozye esczh te lhlj Depaspy Slhvtyr" 

#frequency of each letter
letter_counts = Counter(message)
print(letter_counts)    # Print the count of each element in string

#find max letter
maxFreq = -1
maxLetter = None
letter_counts[' '] = 0  # Don't count spaces zero count
for letter, freq in letter_counts.items(): 
    print(letter, ":", freq) 
    maxLetter = max(letter_counts, key = letter_counts.get)  # Find max freq letter in the string 
print("Max Ocurring Letter:", maxLetter)


#right shift for encrypting and left shift for descripting.
#predict shift
#assume max letter is 'e'
letters = string.ascii_letters #contains 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
shift = 15  #COMPUTE SHIFT HERE (hardcode)
print("Predicted Shift:", shift)

totalLetters = 26
keys = {} #use dictionary for letter mapping
invkeys = {} #use dictionary for inverse letter mapping, you could use inverse search from original dict

for index, letter in enumerate(letters):
    # cypher setup
    if index < totalLetters: #lowercase
        # Dictionary for encryption 
        letter = letters[index]
        keys[letter] = letters[(index + shift) % 26]
        # Dictionary for decryption 
        invkeys = {val: key for key, val in keys.items()}
    else: #uppercase
        # Dictionary for encryption 
        keys[letter] = letters[(index + shift) % 26 + 26]
        # Dictionary for decryption
        invkeys = {val: key for key, val in keys.items()}
print("Cypher Dict", keys)

#decrypt
decryptedMessage = []
for letter in message:
    if letter == ' ': #spaces
        decryptedMessage.append(letter)
    else:
        decryptedMessage.append(keys[letter])
print("Decrypted Message:", ''.join(decryptedMessage)) #join is used to put list inot string

# Checking if message is the same as the encrypt message provided 
#Encrypt
encryptedMessage = []
for letter in decryptedMessage:
    if letter == ' ': #spaces
        encryptedMessage.append(letter)
    else:
        encryptedMessage.append(invkeys[letter])
print("Encrypted Message:", ''.join(encryptedMessage)) #join is used to put list inot string

加密部分代码没有必要存在,仅供校验。如果有人可以帮助修改我的代码/给我一些预测移位部分的提示,那就太好了。谢谢!

代码输出:

Cypher Dict {'a': 'p', 'b': 'q', 'c': 'r', 'd': 's', 'e': 't', 'f': 'u', 'g': 'v', 'h': 'w', 'i': 'x', 'j': 'y', 'k': 'z', 'l': 'a', 'm': 'b', 'n': 'c', 'o': 'd', 'p': 'e', 'q': 'f', 'r': 'g', 's': 'h', 't': 'i', 'u': 'j', 'v': 'k', 'w': 'l', 'x': 'm', 'y': 'n', 'z': 'o', 'A': 'P', 'B': 'Q', 'C': 'R', 'D': 'S', 'E': 'T', 'F': 'U', 'G': 'V', 'H': 'W', 'I': 'X', 'J': 'Y', 'K': 'Z', 'L': 'A', 'M': 'B', 'N': 'C', 'O': 'D', 'P': 'E', 'Q': 'F', 'R': 'G', 'S': 'H', 'T': 'I', 'U': 'J', 'V': 'K', 'W': 'L', 'X': 'M', 'Y': 'N', 'Z': 'O'}
Decrypted Message: One remember to look up at the stars and not down at your feet Two never give up work Work gives you meaning and purpose and life is empty without it Three if you are lucky enough to find love remember it is there and dont throw it away Stephen Hawking
Encrypted Message: Zyp cpxpxmpc ez wzzv fa le esp delcd lyo yze ozhy le jzfc qppe Ehz ypgpc rtgp fa hzcv Hzcv rtgpd jzf xplytyr lyo afcazdp lyo wtqp td pxaej hteszfe te Escpp tq jzf lcp wfnvj pyzfrs ez qtyo wzgp cpxpxmpc te td espcp lyo ozye esczh te lhlj Depaspy Slhvtyr

这样的事情应该允许您根据原始消息中频率最高的字母是 'e':

的假设来计算偏移
letter_counts = Counter(message)
e_encrypted = [k for k, v in letter_counts.items() if v == max(count for c, count in letter_counts.items() if c != ' ')][0]
shift = (ord('e') - ord(e_encrypted)) % 26

或者,展开推导式以便于理解:

letter_counts = Counter(message)
e_encrypted, max_v = None, 0
for k, v in letter_counts.items():
    if v > max_v and k != ' ':
        e_encrypted, max_v = k, v
shift = (ord('e') - ord(e_encrypted)) % 26

它执行以下操作:

  • 使用 Counter class
  • message 中的字符进行频率计数
  • 找到最大频率,以及具有最大频率的字符
  • 将移位设置为该字符的 ascii 值与字母 'e'(模 26)之间的差值

这包含三个组成部分:

  1. 寻找频率最高的字符:
test_str = "" # your string
counter = Counter(test_str)
keys = sorted(counter, key=counter.get, reverse=True)
res = keys[1] if keys[0] == " " else keys[0]
  1. 正在计算偏移:
shift = ord('e') - ord(res)
  1. Encrypting/decrypting 字符串,这是微不足道的,因为你现在知道班次了