-
Notifications
You must be signed in to change notification settings - Fork 0
/
encryption.py
371 lines (328 loc) · 17.3 KB
/
encryption.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# Cameron Rodriguez
# May 23, 2019
# This program encrypts and decrypts files.
# These modules generates the GUI for the program
import Tkinter as tk
import tkFileDialog
import math # This module is used to split the password into sets of three
"""
Data Dictionary
main: instance: an instance of Tkinter Frame that becomes the parent of the Toplevel classes
crypt: instance: creates and starts an instance of the FileMenu class
location: instance/string: a Tkinter Text object that stores the file location, later converted to a string
selected_file: string: the location of the file selected in the tkFileDialog
raw_file: file: the opened file to be encrypted or decrypted
original: string: the text of the file to be encrypted or decrypted
password_field: instance: a Tkinter Label object where the user enters their password
password: string: the user's password
key: string: the numeric encryption key used to encrypt or decrypt the file
crypted_text: string: the encrypted or decrypted text
invalid: instance: a Tkinter Toplevel object that alerts the user if the password is too short
key_trio: array: stores triples of characters from the password for key generation
key_val: string: the ones digit of the key divided by its length, inserted into the final key
key_half: int: the floor division of halfway in the key
ascii_list: array: stores character of the file as ASCII decimals during encryption
key_shift: int: the number by which characters are shifted
triple_key: int: a number added to some characters
single_key: int: the sum of all digits in the key, inserted at intervals in the encrypted file
single_key_sum: int: used to calculate single_key
final_file: file: writes the encrypted or decrypted text to a new file
"""
# This class generates the GUI for the program and runs the main menu
# tk.Frame: classobj: provides the Tkinter Frame interface as a superclass
class MainMenu(tk.Frame):
# This function initializes the Tkinter interface and hosts the main menu of the program.
def __init__(self):
# Initialize window
main = tk.Tk()
tk.Frame.__init__(self, master=main)
self.main = main
# Configure window
self.main.title('Encryption Program')
self.main.lift()
self.main.rowconfigure(0, weight=1)
self.main.columnconfigure(0, weight=1)
# Add intro and buttons to encrypt/decrypt/quit program
tk.Label(self.main, text='Welcome to the Encryption program! This program will take a text file that you specify, and '+
'then either encrypt or decrypt its data with the provided password. Select an option to the right to get started.',
wraplength=240, height=5, justify='left').grid(rowspan=3, row=0, columnspan=2, column=0, padx=(0,5))
tk.Button(self.main, text='Encrypt data', command=self.encrypt, anchor='center').grid(column=2, row=0, sticky='NSEW')
tk.Button(self.main, text='Decrypt data', command=self.decrypt, anchor='center').grid(column=2, row=1, sticky='NSEW')
tk.Button(self.main, text='Quit program', command=main.destroy, anchor='center').grid(column=2, row=2, sticky='NSEW')
# def __init__
# This function calls the FileMenu class to encrypt data.
def encrypt(self):
crypt = FileMenu(self, 'En')
# End encrypt
# This function calls the FileMenu class to decrypt data.
def decrypt(self):
crypt = FileMenu(self, 'De')
# End decrypt
# End MainMenu
# This class loads the encryption or decryption menu to allow the user to encrypt or decrypt a file.
# tk.Toplevel: classobj: provides the Tkinter Toplevel interface as a superclass
class FileMenu(tk.Toplevel):
# This function allows the user to select the file to encrypt or decrypt.
# main: instance: an instance of Tkinter Frame that becomes the parent of the Toplevel class
# action: str: indicates whether the file will be encrypted or decrypted
def __init__(self, main, action):
# Initialize window
tk.Toplevel.__init__(self, main)
self.lift()
self.main = main
self.action = action
self.title('{}crypt Data'.format(self.action))
# Add intro, text box to enter file address, and buttons to select with GUI and OK
tk.Label(self, text='Please type or select the location of the file you would like to {}crypt below.'.format(self.action.lower())).grid(columnspan=3,
column=0, row=0)
tk.Label(self, text='File\nlocation:', anchor='w', borderwidth=1, relief='solid').grid(column=0, rowspan=2, row=1, padx=(0,5), sticky='NSW')
self.location = tk.Text(self, wrap=tk.WORD, height=3, width=36)
self.location.grid(column=0, rowspan=2, row=1, padx=(50,0))
tk.Button(self, text='Open file', command=self.file_select, width=8).grid(column=1, row=1, sticky='NSEW')
tk.Button(self, text='Use this file', command=self.open_file, width=8).grid(column=1, row=2, sticky='NSEW')
# End __init__
# This function uses tkFileDialog to allow the user to select a specific file.
def file_select(self):
# Open GUI to select file
selected_file = None
selected_file = tkFileDialog.askopenfilename(initialdir='H:/', title = 'Select File', filetypes=(('Text Documents', '*.txt'), ('Markdown Document', '*.md'),
('Rich Text Format', '*.rtf'), ('All Files', '*.*')))
# Replace text box contents with selected file
self.location.delete('1.0', tk.END)
self.location.insert(tk.END, selected_file)
if selected_file is not None:
self.lift() # Lifts Toplevel window again after file is selected
# End if selected_file
# End file_select
# This function loads the selected file into the program and calls the PasswordMenu class to start encryption/decryption.
def open_file(self):
# Read the file into a variable
with open(self.location.get('1.0', 'end-1c'), 'r') as raw_file:
self.original = raw_file.read()
# End with open
self.location = self.location.get('1.0', 'end-1c')
self.destroy()
crypt = PasswordMenu(self.main, self.action, self.original, self.location)
#End open_file
# End FileMenu
# This class requests the password, and calls the encryption/decryption functions.
# tk.Toplevel: classobj: provides the Tkinter Toplevel interface as a superclass
class PasswordMenu(tk.Toplevel):
# This function requests a password from the user.
# main: instance: an instance of Tkinter Frame that becomes the parent of the Toplevel class
# action: str: indicates whether the file will be encrypted or decrypted
# original: str: the file to be encrypted or decrypted
# location: str: the location of the original file
def __init__(self, main, action, original, location):
# Initialize window
tk.Toplevel.__init__(self, main)
self.main = main
self.action = action
self.original = original
self.location = location
self.title('Enter Password')
# Add widgets to enter password and describe requirements
tk.Label(self, text='Please enter a password which meets the following requirement:\n'+
' - Minimum length of 3 characters', justify='left').grid(columnspan=3, column=0, row=0)
tk.Label(self, text='Password:', anchor='w').grid(column=0, row=1, sticky='W')
self.password_field = tk.Entry(self)
self.password_field.grid(columnspan=3, column=0, row=1, padx=(60,97), sticky='NSEW')
tk.Button(self, text='{}crypt my data'.format(self.action), command=self.check_password).grid(column=2, row=1, sticky='NSE')
# End __init__
# This function ensures that the password given is valid, and runs the encryption/decryption program if so.
def check_password(self):
self.password = self.password_field.get()
if len(self.password) >= 3:
self.destroy()
key = encryption_key(self.password) # Generate the encryption key
crypted_text = crypt(key, self.action, self.original)
result = FinalMenu(self.main, self.action, self.location, crypted_text)
else:
invalid = tk.Toplevel(self)
invalid.title('Invalid Password')
tk.Label(invalid, text='The password provided is too short.'+
'\nPlease use a password with at least three characters.').grid(column=0, row=0)
tk.Button(invalid, text='OK', command=invalid.destroy, width=8).grid(column=0, row=1)
# End if len(self.password)
# End check_password
# End PasswordMenu
# This class lets the user select where to save the completed file.
# tk.Toplevel: classobj: provides the Tkinter Toplevel interface as a superclass
class FinalMenu(tk.Toplevel):
# This function introduces the user to the filesave menu.
# main: instance: an instance of Tkinter Frame that becomes the parent of the Toplevel class
# action: str: indicates whether the file will be encrypted or decrypted
# original: str: the file to be encrypted or decrypted
# location: str: the location of the original file
# crypted_text: str: the encrypted/decrypted text
def __init__(self, main, action, location, crypted_text):
# Initialize window
tk.Toplevel.__init__(self, main)
self.main = main
self.action = action
self.location = location
self.crypted_text = crypted_text
self.title('Text {}crypted'.format(self.action))
# Describe result
tk.Label(self, text='Your file has been successfully {}crypted. On the next screen, you will select '.format(action.lower())+
'where to save the file.', height=2, wraplength=330).grid(column=0, row=0)
tk.Button(self, text='OK', command=self.save).grid(column=0, row=1)
# End __init__
# This function lets the user choose where to save the file and does so
def save(self):
selected_file = None
self.location = self.location[:len(self.location)-(self.location[::-1].index('/'))] # Sets location to parent folder of original file
selected_file = tkFileDialog.asksaveasfilename(initialdir=self.location, title = 'Save File', filetypes=(('Text Documents', '*.txt'), ('Markdown Document', '*.md'),
('Rich Text Format', '*.rtf'), ('All Files', '*.*')))
if selected_file is not None:
# Save file
with open(selected_file, 'w+') as final_file:
final_file.write(self.crypted_text)
# End with open
# Show confirmation window
self.destroy()
tk.Toplevel.__init__(self, self.main)
self.title('File Saved')
tk.Label(self, text='Your file has been saved.').grid(column=0, row=0, padx=30)
tk.Button(self, text='OK', command=self.destroy).grid(column=0, row=1)
# End if selected_file
# End save
# This function generates the encryption key from the password
# password: string: contains the user's password
# Returns the encryption key
def encryption_key(password):
key_val=0
key=[]
key_int=0
# Generate first part of encryption key by splitting password into groups of three or less
for i in range(int(math.ceil(len(password)/3.0))):
key_trio = [0, 0, 0]
# Generate first character in key trio
key_trio[0] = str(ord(password[i*3]))
while int(key_trio[0]) >= 10: # Add digits to get a single digit result, repeating if necessary
if int(key_trio[0]) >= 100:
key_trio[0] = str(int(key_trio[0][-3]) + int(key_trio[0][-2]) + int(key_trio[0][-1]))
else:
key_trio[0] = str(int(key_trio[0][-2]) + int(key_trio[0][-1]))
# End while key_trio[0]
# End while key_trio[0]
try:
# Generate second character in key trio
key_trio[1] = str(ord(password[(i*3)+1]))
for j in range(9, 0, -1): # Get single digit result from largest single digit factor
if int(key_trio[1]) % j == 0:
key_trio[1] = str(j)
break
# End if key_trio[1]
# End for j
# Generate third character in key trio
key_trio[2] = str(ord(password[(i*3)+2]))
key_trio[2] = key_trio[2][-1] # Uses last digit of character value for single digit result
except IndexError: # End of password reached
pass
# End try/except
for j in key_trio:
if type(j) is str:
key.append(j)
# End if type(j)
# End for j
# End for i
key = ''.join(key)
# Generate and add extra character in middle of key
key_val = str((int(key) / len(key)) % 10)
key_half = len(key) / 2
key = key[:key_half] + key_val + key[key_half:]
return key
# This function encrypts or decrypts the file depending on the option given.
# key: str: the encryption key
# action: str: indicates whether the file will be encrypted or decrypted
# original: str: the file to be encrypted or decrypted
# Returns the encrypted/decrypted file
def crypt(key, action, original):
# Convert every char in original to its ASCII value
ascii_list = [ord(i) for i in original]
key_shift = int(key[-3:]) % 224 # Within the range of visible ASCII chars, 32-255
triple_key = 3 * int(key[0])
single_key = key
while len(single_key) > 1: # Add key digits until a single digit is reached
single_key_sum = 0
for i in range(len(single_key)):
single_key_sum += int(single_key[i])
# End for i
single_key = str(single_key_sum)
# End while len(single_key)
single_key = int(single_key) + 100 # For printability
if action == 'En': # Encrypt file
# Shift to right by key_shift spaces, looping if necessary
for i in range(len(ascii_list)):
if ascii_list[i] < 32: # A functional character (ex. newline)
continue
# End if i
ascii_list[i] += key_shift
if ascii_list[i] > 255:
ascii_list[i] -= 224
# End if ascii_list[i]
# End for i
# Adds triple_key at intervals of key[1], looping if necessary
if int(key[1]) == 0:
pass
else:
for i in range(1, (len(ascii_list)/int(key[1]))+1):
if ascii_list[(i*int(key[1])) - 1] < 32:
continue
# End if i
ascii_list[(i*int(key[1])) - 1] += triple_key
if ascii_list[(i*int(key[1])) - 1] > 255:
ascii_list[(i*int(key[1])) - 1] -= 224
# End if ascii_list[(i*int(key[1])) - 1]
# End for i
# End if int(key[1])
# Inserts single_key in reverse order at interval of key[2]
if int(key[2]) == 0 or int(key[2]) > len(ascii_list):
pass
else:
for i in range((len(ascii_list) / int(key[2])), 0, -1):
ascii_list = ascii_list[:(i*int(key[2]))] + [single_key] + ascii_list[(i*int(key[2])):]
# End for i
# End if int(key[2])
else: # Decrypt file
# Removes single_key in reverse order at intervals of key[2]
if int(key[2]) == 0 or int(key[2]) > len(ascii_list):
pass
else:
for i in range((len(ascii_list) / (1 + int(key[2]))), 0, -1): # Adjust interval to account for extra characters
del ascii_list[(i*(int(key[2])+1)) - 1]
# End for i
# End if int(key[2])
# Subtracts triple_key at interval of key[1], looping if necessary
if int(key[1]) == 0:
pass
else:
for i in range(1, (len(ascii_list)/int(key[1]))+1):
if ascii_list[(i*int(key[1])) - 1] < 32:
continue
# End if i
ascii_list[(i*int(key[1])) - 1] -= triple_key
if ascii_list[(i*int(key[1])) - 1] < 32:
ascii_list[(i*int(key[1])) - 1] += 224
# End if ascii_list[(i*int(key[1])) - 1]
# End for i
# End if int(key[1])
# Shift to left by key_shift spaces, looping if necessary
for i in range(len(ascii_list)):
if ascii_list[i] < 32:
continue
# End if i
ascii_list[i] -= key_shift
if ascii_list[i] < 32:
ascii_list[i] += 224
# End if ascii_list[i]
# End for i
# End if action
# Convert to text and merge to string
ascii_list = [chr(i) for i in ascii_list]
crypted_text = ''.join(ascii_list)
return crypted_text
# Start the program
program = MainMenu()
program.mainloop()