-
Notifications
You must be signed in to change notification settings - Fork 0
/
caesar-breaker.py
101 lines (76 loc) · 2.54 KB
/
caesar-breaker.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
#!/usr/bin/env python
import sys
import string
import getopt
ALPHABET = list(string.ascii_lowercase)
MOST_FREQUENT_LETTER_BY_LANG = {'en': 'e'}
def usage():
print("Usage: caesar-breaker.py [OPTIONS] \"ciphertext\"")
print(" -f, --force - Decrypt using brute force, otherwise shifts are calculated based on the language")
print(" -l, --lang - Language that the plaintext is supposed to be in")
def get_letters_frequency(text):
"""
returns a map containing each text letter and its frequency
"""
letters_frequency = {}
for letter in text:
if letter.isalpha():
if letter in letters_frequency:
letters_frequency[letter] += 1
else:
letters_frequency[letter] = 1
return letters_frequency
def calculate_shifts(letters_frequency, lang):
"""
returns the number of shifts based on the text's letters frequency map
and the language that the text is supposed to be written in
"""
most_freq_letter = max(letters_frequency, key=letters_frequency.get)
return ALPHABET.index(MOST_FREQUENT_LETTER_BY_LANG[lang]) - ALPHABET.index(most_freq_letter)
def decrypt(ciphertext, rotations):
"""
returns the input text with its letters rotated around the alphabet
following a forward or backward direction
"""
global ALPHABET
plaintext = ""
for letter in ciphertext:
if letter.isalpha():
plaintext += ALPHABET[(ALPHABET.index(letter) + rotations) % len(ALPHABET)]
else:
plaintext += letter
return plaintext
def main():
force_flag = False
lang = ""
if len(sys.argv) < 3:
usage()
sys.exit(2)
try:
opts, args = getopt.getopt(sys.argv[1:], 'hfl:',
['help', 'force', 'lang'])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
elif opt in ('-f', '--force'):
force_flag = True
elif opt in ('-l', '--lang'):
lang = arg
else:
usage()
sys.exit(2)
ciphertext = sys.argv[-1].lower()
# Decrypt by Brute Force
if force_flag:
for nshift in range(len(ALPHABET)):
print(decrypt(ciphertext, nshift))
# Decrypt based on lang
else:
letters_freq = get_letters_frequency(ciphertext)
shifts = calculate_shifts(letters_freq, lang)
print(decrypt(ciphertext, shifts))
if __name__ == '__main__':
main()