-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathPlayfairCipher.py
65 lines (57 loc) · 2.57 KB
/
PlayfairCipher.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
class PlayFairCipher:
def __init__(self, key):
self.key = key
self.letter2index = self.get_letter_2_index_map()
def get_letter_2_index_map(self):
index_map = {}
for row in range(len(self.key)):
for column in range(len(self.key[row])):
letter = self.key[row][column].lower()
if letter == 'i':
index_map['j'] = (row, column)
index_map[letter] = (row, column)
return index_map
def encrypt(self, plaintext):
plaintext = self.pad_extra(self.remove_consecutive_same_chars(plaintext.lower()))
# print('plaintext:', plaintext)
ciphertext = ''
for index in range(0, len(plaintext), 2):
pair = plaintext[index: index + 2]
ciphertext += self.encipher(pair)
return ciphertext.upper()
def decrypt(self, ciphertext):
plaintext = ''
for index in range(0, len(ciphertext), 2):
pair = ciphertext[index: index + 2].lower()
plaintext += self.decipher(pair)
return plaintext
def decipher(self, pair):
row1, column1 = self.letter2index[pair[0]]
row2, column2 = self.letter2index[pair[1]]
if row1 == row2:
return self.key[row1][(column1 - 1) % 5] + self.key[row1][(column2 - 1) % 5]
elif column1 == column2:
return self.key[(row1 - 1) % 5][column1] + self.key[(row2 - 1) % 5][column2]
return self.key[row1][column2] + self.key[row2][column1]
def encipher(self, pair):
row1, column1 = self.letter2index[pair[0]]
row2, column2 = self.letter2index[pair[1]]
if row1 == row2:
return self.key[row1][(column1 + 1) % 5] + self.key[row1][(column2 + 1) % 5]
elif column1 == column2:
return self.key[(row1 + 1) % 5][column1] + self.key[(row2 + 1) % 5][column2]
return self.key[row1][column2] + self.key[row2][column1]
@staticmethod
def pad_extra(plaintext):
return plaintext + PlayFairCipher.middle_character(plaintext[len(plaintext) - 1]) \
if len(plaintext) % 2 == 1 else plaintext
@staticmethod
def remove_consecutive_same_chars(plaintext):
for index in range(len(plaintext) - 1):
if plaintext[index] == plaintext[index + 1]:
plaintext = plaintext[: index + 1] + PlayFairCipher.middle_character(plaintext[index]) + plaintext[index + 1:]
return plaintext
@staticmethod
def middle_character(letter):
# return chr((ord(letter) - ord('a') + 1) % 26 + ord('a'))
return 'x'