-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcaesar_cipher.py
193 lines (124 loc) · 5.21 KB
/
caesar_cipher.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
"""Encodes or decodes a message using Caesar Cipher method."""
from string import ascii_letters, ascii_lowercase, ascii_uppercase
CAESAR_CIPHER_ASCII_ART = """
,adPPYba, ,adPPYYba, ,adPPYba, ,adPPYba, ,adPPYYba, 8b,dPPYba,
a8" "" "" `Y8 a8P_____88 I8[ "" "" `Y8 88P' "Y8
8b ,adPPPPP88 8PP""""""" `"Y8ba, ,adPPPPP88 88
"8a, ,aa 88, ,88 "8b, ,aa aa ]8I 88, ,88 88
`"Ybbd8"' `"8bbdP"Y8 `"Ybbd8"' `"YbbdP"' `"8bbdP"Y8 88
88 88
"" 88
88
,adPPYba, 88 8b,dPPYba, 88,dPPYba, ,adPPYba, 8b,dPPYba,
a8" "" 88 88P' "8a 88P' "8a a8P_____88 88P' "Y8
8b 88 88 d8 88 88 8PP""""""" 88
"8a, ,aa 88 88b, ,a8" 88 88 "8b, ,aa 88
`"Ybbd8"' 88 88`YbbdP"' 88 88 `"Ybbd8"' 88
88
88
"""
def get_mode():
"""Return a string containing the user's input.
Asks the user if they want to encrypt or decrypt their message.
This is repeated until a valid input is received.
"""
while True:
mode = input("\nEncrypt or Decrypt: ").lower()
if mode in "encrypt e decrypt d".split():
return mode
else:
print("\nInvalid input. Only 'encrypt', 'e', 'decrypt', or 'd'.")
def get_message():
"""Return a string containing the user's input.
Calls get_mode to check if the user wants
to encrypt or decrypt the message.
Asks the user to enter the message for encryption or decryption.
This is repeated until the user enters at least a
character into the input prompt.
"""
get_mode()
while True:
user_message = input("\nType your message: ")
if user_message != "":
return user_message
print("\nInput must not be null.")
def get_key():
"""Return an integer containing the user's input.
Asks the user to enter a key used for shifting the letters.
This is repeated until the user enters a valid key.
"""
key = 0
while True:
try:
key = int(input("\nEnter a key number: "))
except ValueError:
print("\nInput must only be an integer.")
else:
return key
def ask_user_yes_no(yes_no_question) -> bool:
"""Simplifies if/else to determine the correct answers from the user input.
Args:
yes_no_question: A string that asks user a yes or no question.
Returns:
True if the user's answer is in CHOICE_YES,
and False otherwise.
Prints a message to the user if their input are not the same as
the ones in CHOICE_YES and CHOICE_NO.
"""
choice_yes = ("yes", 'y')
choice_no = ("no", 'n')
while True:
user_choice = input(yes_no_question).lower()
if user_choice in choice_yes:
return True
if user_choice in choice_no:
return False
print("\nInvalid Input. Try again.")
def alphabet_position(shift):
"""Return the new shifted lowercase and uppercase alphabets.
Shifts the lowercase and uppercase characters given a new key.
"""
shifted_lowercase = ascii_lowercase[shift:] + ascii_lowercase[:shift]
shifted_uppercase = ascii_uppercase[shift:] + ascii_uppercase[:shift]
return shifted_lowercase, shifted_uppercase
def translate_message(message: str, offset):
"""Return a strings containing the encrypted message.
Each character of the encrypted message is mapped to the given translation table.
Rearranges the ordinal numbers of the alphabets with
the given offset including uppercase letters.
"""
lowercase_alpha, uppercase_alpha = alphabet_position(offset)
char_index = message.maketrans(
ascii_letters, lowercase_alpha + uppercase_alpha)
print(f"\n\nTranslated Message: {message.translate(char_index)}")
# def perform_brute_force(message):
# """Perform a brute-force attack if the user does
# not know the offset to decrypt the message.
# Prints every possible decryption key from 1 to 26
# along with the decrypted message.
# """
# for char in range(1, 26):
# print(f"Key: {char}")
# print(f"\t{translate_message(message, char)}")
def should_cipher_again():
"""Asks the user if they want to encode or decode another text.
Returns True if yes, False otherwise.
"""
return ask_user_yes_no("\n\nWould you like to encrypt or "
"decrypt another message? (Y/N): ")
def start_program():
"""Start the program.
Restarts the program if the user wants to encode or
decode another message.
Prints out a message telling the user that the program has ended
if they do not wish to continue with the program.
"""
print(CAESAR_CIPHER_ASCII_ART)
while True:
user_text, key_rotation = get_message(), get_key()
translate_message(user_text, key_rotation)
if not should_cipher_again():
break
print("\n\n-----Program Exited-----\n")
if __name__ == "__main__":
start_program()