Доброго времени суток друзья !
Программа для защиты информации на языке питон на основе Tkinter GUI и библиотеки pyAesCrypt. Я не знаю для чего изобретать велосипед, но можно надежно шифровать свои данные (не ТераБайтные например) своими силами. Скорость шифрования устраивает но проблема скорости есть, над этим не работал пока. На директории до 5 - 10 ГБ уйдет от 3 до 7 минут в зависимости от системы (но это не точно). Но тут вопрос видимо в алгоритме шифрования и мультипроцессинге имхо. В общем, всегда есть над чем работать)
На выходе должен быть работающий код (при наличии поставленных библиотек), который можно доработать или изменить например алгоритм шифрования. В общем используется документация, питон и иногда гуглнет (куда без него). Если будет кому то интересно или полезно, буду рад получить обратную связь. По информативности и написанию тоже, хотя в основном будет оптимизировано документационный код)
Часть замечаний будет непосредственно в комментариях внутри кода, постарался сделать подробно (надеюсь не слишком)
Тут оставлю ссылку на вторую часть.
Короче, погнали.
Подключаем библиотеки :
Проверяем, устанавливаем через pip.
Создаем главное окно :
Далее создаем класс приложения и вызываем метод инит, инициализируем нужные переменные и виджеты. Виджеты расположены по осям х, у для геометрии окна 500х500 (вроде оптимально))
Для кнопок лучше вставлять изображения - закодированные в base64, или придется держать файлы изображений в рабочей директории, если заходите скомпилировать в один exe. файл - это неудобно.
Немного криптографии :
Немного отступлю от кода в сторону криптографии :
Основные функции расшифровка / дешифровка работают принимая на вход директорию и пароль и используя модуль pyAesCrypt. В документации указан алгоритм шифрования AES256-CBC, СВС (Цепочка блоков шифров) - это режим шифрования, поменять его нельзя, но этот режим является предпочтительным для современных алгоритмов (насколько мне известно из источников) Сам алгоритм шифрования здесь затрагивать не буду, но хочется заметить, что тут используется входной ключ длиной 256 бит и я нашел хорошую цитату из книги «Прикладная криптография» Брюса Шнайера ( она достаточно длинная, но точно достойна к прочтению ) о сложности дешифровки 256 битного ключа в специфике нашей физики материи и энергии)
Основные функции :
Расшифровка / дешифровка директории:
Тут используется функция self.insert_to_console для вывода в tk виджет scrolledtext.
Напишем ее :
Основные криптографические функции есть, но нам необходимо использовать потоки, чтобы окно не зависало. Во время работы криптографические функции нам надо получать динамический вывод в консоль программы, но без использования многопоточности, поток главного окна проги будет перекрывать поток выполнения, окно попросту будет висеть пока программа не закончит работу. Чтобы при повторном нажатии кнопки у нас потоки не накладывались друг на друга, разрешим запускаться только одному потоку.
Реализовал так:
Эти функции запускаются по нажатии кнопок CRYPT / DECRYPT соответственно.
Напишем функции для кнопки PASTE и STOP:
И наконец инициализируем запуск:
Вот так это выглядит.
Чтобы скомпилировать в .exe поменяйте расширение на your_file.pyw и выполните:
pyinstaller --onefile your_file.pyw
или
pyinstaller --onefile --icon=skeleton.ico zvepb_crypter.pyw
для эстетики.
Для компиляции необходима библиотека pyinstaller:
pip install pyinstaller
Файлы иконок для запуска:
Исходный код:
Может будет полезно / интересно тем кто начал или изучает питон, ну или для общего развития ^_^. Если есть какие то замечания - выслушаю конструктивную критику, помощь / недочеты по коду. Тут оставлю ссылку на вторую часть.
Спасибо за внимание)
Программа для защиты информации на языке питон на основе Tkinter GUI и библиотеки pyAesCrypt. Я не знаю для чего изобретать велосипед, но можно надежно шифровать свои данные (не ТераБайтные например) своими силами. Скорость шифрования устраивает но проблема скорости есть, над этим не работал пока. На директории до 5 - 10 ГБ уйдет от 3 до 7 минут в зависимости от системы (но это не точно). Но тут вопрос видимо в алгоритме шифрования и мультипроцессинге имхо. В общем, всегда есть над чем работать)
На выходе должен быть работающий код (при наличии поставленных библиотек), который можно доработать или изменить например алгоритм шифрования. В общем используется документация, питон и иногда гуглнет (куда без него). Если будет кому то интересно или полезно, буду рад получить обратную связь. По информативности и написанию тоже, хотя в основном будет оптимизировано документационный код)
Часть замечаний будет непосредственно в комментариях внутри кода, постарался сделать подробно (надеюсь не слишком)
Тут оставлю ссылку на вторую часть.
Короче, погнали.
Подключаем библиотеки :
Python:
#!/usr/bin/env python
import os
import threading
import pyperclip
import pyAesCrypt
from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
Создаем главное окно :
Далее создаем класс приложения и вызываем метод инит, инициализируем нужные переменные и виджеты. Виджеты расположены по осям х, у для геометрии окна 500х500 (вроде оптимально))
Python:
# инициализацию можно делать по разному, тут наследуемся от Frame.tk
class MainWindow(tk.Frame):
def __init__(self, root):
super().__init__(root)
self.init_main()
# создаем нужные переменные и виджеты главного окна
def init_main(self):
self.img_cache = [] # храним изображения
self.thread_count = 0 # счетчик потоков
self.path_error = False # отловить ошибку
# тут стандартные виджеты tkinter
lb_dir = Label(text=u"Директория шифрования : ")
lb_dir.pack()
self.ent_value_dir = Entry(width=40)
self.ent_value_dir.pack()
lb_pass = Label(text=u"Пароль : ")
lb_pass.pack()
ent_value_pass = Entry(width=40)
ent_value_pass.pack()
#base_img = "iVBORw0KGgoAAAAN_youR_very_long_code"
crypt_img = PhotoImage(file='1.png')
self.img_cache.append(crypt_img)
btn_crypt = ttk.Button(text=' CRYPT', image=self.img_cache[0], compound='left', command=lambda: self.crypting(self.ent_value_dir.get(), ent_value_pass.get()))
btn_crypt.place(x=5, y=20)
decrypt_img = PhotoImage(file='2.png')
self.img_cache.append(decrypt_img)
btn_decrypt = ttk.Button(text=' DECRYPT', image=self.img_cache[1], compound='left', command=lambda: self.decrypting(self.ent_value_dir.get(), ent_value_pass.get()))
btn_decrypt.place(x=5, y=60)
paste_img = PhotoImage(file='3.png')
self.img_cache.append(paste_img)
btn_stop = ttk.Button(text=' PASTE', image=self.img_cache[2], compound='left', command=lambda: self.paste_dir_to_entry())
btn_stop.place(x=390, y=20)
stop_img = PhotoImage(file='4.png')
self.img_cache.append(stop_img)
btn_stop = ttk.Button(text=' STOP', image=self.img_cache[3], compound='left', command=lambda: self.close_crypter())
btn_stop.place(x=390, y=60)
self.console = scrolledtext.ScrolledText(fg="red", bg="black", state='disable')
self.console.pack(pady=20)
Немного криптографии :
Немного отступлю от кода в сторону криптографии :
Основные функции расшифровка / дешифровка работают принимая на вход директорию и пароль и используя модуль pyAesCrypt. В документации указан алгоритм шифрования AES256-CBC, СВС (Цепочка блоков шифров) - это режим шифрования, поменять его нельзя, но этот режим является предпочтительным для современных алгоритмов (насколько мне известно из источников) Сам алгоритм шифрования здесь затрагивать не буду, но хочется заметить, что тут используется входной ключ длиной 256 бит и я нашел хорошую цитату из книги «Прикладная криптография» Брюса Шнайера ( она достаточно длинная, но точно достойна к прочтению ) о сложности дешифровки 256 битного ключа в специфике нашей физики материи и энергии)
Одним из следствий закона второго термодинамики является то, что для представления информации необходимо некоторое количество энергии. Запись одиночного бита, изменяющая состояние системы, требует количества энергии не меньше чем kT; где Т — абсолютная температура системы и k — постоянная Больцмана. (Не волнуйтесь, урок физики уже почти закончен.)
Приняв, что k = 1,38*10-16 эрг/K, и что температура окружающей вселенной 3,2K, идеальный компьютер, работая при 3,2K, потреблял бы 4,4*10-16 эрга всякий раз, когда он устанавливает или сбрасывает бит. Работа компьютера при температуре более низкой, чем температура космического пространства, потребовала бы дополнительных расходов энергии для отвода тепла.
Далее, энергия, излучаемая нашим Солнцем за год, составляет около 1,21*1041 эргов. Это достаточно для выполнения 2*1056 перемен бита в нашем идеальном компьютере, а этого, в свою очередь, хватит для того, что бы 187-битовый счетчик пробежал все свои значения. Если мы построим вокруг Солнца сферу Дайсона и перехватим без всяких потерь всю его энергию за 32 года, мы сможем получить компьютер для вычисления 2192 чисел. Конечно, энергии для проведения каких-нибудь полезных вычислений с этим счетчиком уже не останется.
Но это только одна жалкая звезда. При взрыве типичной сверхновой выделяется около 1051 эргов. (В сто раз больше энергии выделяется в виде нейтрино, но пусть они пока летают). Если всю эту энергию удастся бросить на одну вычислительную оргию, то все свои значения сможет принять 219-битовый счетчик.
Эти числа не имеют ничего общего с самой аппаратурой, они просто показывают максимальные значения, обусловленные термодинамикой. Кроме того, эти числа наглядно демонстрируют, что вскрытие грубой силой 256-битового ключа будет невозможно, пока компьютеры построены из обычной материи и располагаются в обычном пространстве.
Основные функции :
Расшифровка / дешифровка директории:
Python:
def crypt_file(self, file, password):
bufferSize = 512 * 1024 # размер буфера по умолчанию - больше не надо
try:
# шифруем с расширением .your_version&
pyAesCrypt.encryptFile(str(file), str(file) + ".your_version&",
password, bufferSize)
# выводим в консоль tkinter
self.insert_to_console('ENCRYPTED >>> ' + str(file) + ".your_version&" + '\n')
os.remove(file) # удаляем файл
except Exception as e:
self.insert_to_console('Ошибка шифрования <Unknown_Error>')
pass
def crypt_disk(self, dir, password):
try:
for file in os.listdir(dir):
if os.path.isdir(dir + '\\' + file): # если это директория - продолжаем рекурсивно
self.crypt_disk(dir + '\\' + file, password)
if os.path.isfile(dir + '\\' + file): # если файл - шифруем
try:
self.crypt_file(dir + '\\' + file, password)
except Exception as ex:
self.insert_to_console(ex)
pass
except OSError:
self.path_error = True # поймали ошибку
return
def decrypt_file(self, file, password): # расшифровка практически идентична, только меняем метод на decryptFile
bufferSize = 512 * 1024
try:
pyAesCrypt.decryptFile(str(file), str(os.path.splitext(file)[0]),
password, bufferSize)
self.insert_to_console('DECRYPTED >>> ' + str(os.path.splitext(file)[0]) + '\n')
os.remove(file)
except Exception as e:
print('Ошибка расшифровки, файлы не зашифрованы,'
'неверный пароль или файл поврежден')
self.insert_to_console(e)
pass
def decrypt_disk(self, dir, password):
try:
for file in os.listdir(dir):
if os.path.isdir(dir + '\\' + file):
self.decrypt_disk(dir + '\\' + file, password)
if os.path.isfile(dir + '\\' + file):
try:
self.decrypt_file(dir + '\\' + file, password)
except Exception as ex:
self.insert_to_console(ex)
pass
except OSError:
self.path_error = True
pass
Тут используется функция self.insert_to_console для вывода в tk виджет scrolledtext.
Напишем ее :
Python:
def insert_to_console(self, text):
self.console.configure(state='normal') # включаем инсерт
self.console.insert(END, text) # вставить текст
self.console.yview(END) # автоскролл
self.console.configure(state='disabled')
Основные криптографические функции есть, но нам необходимо использовать потоки, чтобы окно не зависало. Во время работы криптографические функции нам надо получать динамический вывод в консоль программы, но без использования многопоточности, поток главного окна проги будет перекрывать поток выполнения, окно попросту будет висеть пока программа не закончит работу. Чтобы при повторном нажатии кнопки у нас потоки не накладывались друг на друга, разрешим запускаться только одному потоку.
Реализовал так:
Python:
def crypting(self, dir, password):
# проверяем нет ли ошибки пути или пустой пароль
if self.path_error or password == '':
self.path_error = False # сбрасываем ошибку
self.thread_count = 0 # обнуляем счетчик процессов
self.insert_to_console('Ошибка : Неправильный путь или нет пароля !\n')
return
else:
self.thread_count += 1
if self.thread_count > 1:
# print(threading.enumerate())
self.insert_to_console('Ограничение потока, запущено : 1\n')
return
pycrypt = threading.Thread(target=self.crypt_disk, args=(dir, password))
pycrypt.start()
def decrypting(self, dir, password):
if self.path_error or password == '':
self.path_error = False
self.thread_count = 0
self.insert_to_console('Ошибка : Неправильный путь или нет пароля !\n')
return
else:
self.thread_count += 1
if self.thread_count > 1:
self.insert_to_console('Ограничение потока, запущено : 1\n')
return
pycrypt = threading.Thread(target=self.decrypt_disk, args=(dir, password))
pycrypt.start()
Напишем функции для кнопки PASTE и STOP:
Python:
def close_crypter(self): # закрыть окно
quit()
def paste_dir_to_entry(self): # вставить текст из буфера обмена в поле директория
self.ent_value_dir.insert(tk.END, pyperclip.paste())
И наконец инициализируем запуск:
Python:
def run_app():
root = tk.Tk()
root.resizable(width=False, height=False) # не изменять размер окна
MainWindow(root)
root.title("crypter")
root.geometry("500x500")
root.mainloop()
if __name__ == '__main__':
crypter = MainWindow
crypter.run_app()
Вот так это выглядит.
Чтобы скомпилировать в .exe поменяйте расширение на your_file.pyw и выполните:
pyinstaller --onefile your_file.pyw
или
pyinstaller --onefile --icon=skeleton.ico zvepb_crypter.pyw
для эстетики.
Для компиляции необходима библиотека pyinstaller:
pip install pyinstaller
Файлы иконок для запуска:
Исходный код:
Python:
#!/usr/bin/env python
import os
import threading
import pyperclip
import pyAesCrypt
from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
class MainWindow(tk.Frame):
def __init__(self, root):
super().__init__(root)
self.init_main()
def init_main(self):
self.img_cache = []
self.thread_count = 0
self.path_error = False
lb_dir = Label(text=u"Директория шифрования : ")
lb_dir.pack()
self.ent_value_dir = Entry(width=40)
self.ent_value_dir.pack()
lb_pass = Label(text=u"Пароль : ")
lb_pass.pack()
ent_value_pass = Entry(width=40)
ent_value_pass.pack()
crypt_img = PhotoImage(file='1.png')
self.img_cache.append(crypt_img)
btn_crypt = ttk.Button(text=' CRYPT', image=self.img_cache[0], compound='left', command=lambda: self.crypting(self.ent_value_dir.get(), ent_value_pass.get()))
btn_crypt.place(x=5, y=20)
decrypt_img = PhotoImage(file='2.png')
self.img_cache.append(decrypt_img)
btn_decrypt = ttk.Button(text=' DECRYPT', image=self.img_cache[1], compound='left', command=lambda: self.decrypting(self.ent_value_dir.get(), ent_value_pass.get()))
btn_decrypt.place(x=5, y=60)
paste_img = PhotoImage(file='3.png')
self.img_cache.append(paste_img)
btn_stop = ttk.Button(text=' PASTE', image=self.img_cache[2], compound='left', command=lambda: self.paste_dir_to_entry())
btn_stop.place(x=390, y=20)
stop_img = PhotoImage(file='4.png')
self.img_cache.append(stop_img)
btn_stop = ttk.Button(text=' STOP', image=self.img_cache[3], compound='left', command=lambda: self.close_crypter())
btn_stop.place(x=390, y=60)
self.console = scrolledtext.ScrolledText(fg="red", bg="black", state='disable')
self.console.pack(pady=20)
def close_crypter(self):
quit()
def insert_to_console(self, text):
self.console.configure(state='normal') # enable insert
self.console.insert(END, text)
self.console.yview(END) # autoscroll
self.console.configure(state='disabled')
def paste_dir_to_entry(self):
self.ent_value_dir.insert(tk.END, pyperclip.paste())
def crypt_file(self, file, password):
bufferSize = 512 * 1024
try:
pyAesCrypt.encryptFile(str(file), str(file) + ".zvp",
password, bufferSize)
self.insert_to_console('ENCRYPTED >>> ' + str(file) + ".zvp" + '\n')
os.remove(file)
except Exception as e:
self.insert_to_console('Ошибка шифрования <Unknown_Error>')
pass
def crypt_disk(self, dir, password):
try:
for file in os.listdir(dir):
if os.path.isdir(dir + '\\' + file):
self.crypt_disk(dir + '\\' + file, password)
if os.path.isfile(dir + '\\' + file):
try:
self.crypt_file(dir + '\\' + file, password)
except Exception as ex:
self.insert_to_console(ex)
pass
except OSError:
self.path_error = True
return
def decrypt_file(self, file, password):
bufferSize = 512 * 1024
try:
pyAesCrypt.decryptFile(str(file), str(os.path.splitext(file)[0]),
password, bufferSize)
self.insert_to_console('DECRYPTED >>> ' + str(os.path.splitext(file)[0]) + '\n')
os.remove(file)
except Exception as e:
print('Ошибка расшифровки, файлы не зашифрованы,'
'неверный пароль или файл поврежден')
self.insert_to_console(e)
pass
def decrypt_disk(self, dir, password):
try:
for file in os.listdir(dir):
if os.path.isdir(dir + '\\' + file):
self.decrypt_disk(dir + '\\' + file, password)
if os.path.isfile(dir + '\\' + file):
try:
self.decrypt_file(dir + '\\' + file, password)
except Exception as ex:
self.insert_to_console(ex)
pass
except OSError:
self.path_error = True
pass
# проблемы - ускорение процесса шифрования и создающиеся потоки при повторном нажатии кнопки
# (исправлено с помощью path_error и thread_count
def crypting(self, dir, password):
if self.path_error or password == '':
self.path_error = False
self.thread_count = 0
self.insert_to_console('Ошибка : Неправильный путь или нет пароля !\n')
return
else:
self.thread_count += 1
if self.thread_count > 1:
# print(threading.enumerate())
self.insert_to_console('Ограничение потока, запущено : 1\n')
return
pycrypt = threading.Thread(target=self.crypt_disk, args=(dir, password))
pycrypt.start()
def decrypting(self, dir, password):
if self.path_error or password == '':
self.path_error = False
self.thread_count = 0
self.insert_to_console('Ошибка : Неправильный путь или нет пароля !\n')
return
else:
self.thread_count += 1
if self.thread_count > 1:
self.insert_to_console('Ограничение потока, запущено : 1\n')
return
pycrypt = threading.Thread(target=self.decrypt_disk, args=(dir, password))
pycrypt.start()
def run_app():
root = tk.Tk()
root.resizable(width=False, height=False)
MainWindow(root)
root.title("zvepb_crypter")
root.geometry("500x500")
root.mainloop()
if __name__ == '__main__':
zv = MainWindow
zv.run_app()
Может будет полезно / интересно тем кто начал или изучает питон, ну или для общего развития ^_^. Если есть какие то замечания - выслушаю конструктивную критику, помощь / недочеты по коду. Тут оставлю ссылку на вторую часть.
Спасибо за внимание)
Последнее редактирование модератором: