• XSS.stack #1 – первый литературный журнал от юзеров форума

Вопросы по блочному шифрованию

Encommerce

(L3) cache
Пользователь
Регистрация
25.11.2022
Сообщения
235
Реакции
97
Тема опубликована в данном разделе в виду того, что вопрос затрагивает не столько криптографию, сколько работу с железом.



Потихноньку разбираюсь с многопоточным шифрованием. Пишу на Rust, хотя значения это не имеет.
Проводить замеры и тесты, приближенные к реальным условиям, очень сложно и муторно.
Предпологаю, что тут есть умные люди, которые в этом разбираются и могут дать несколько наводок, которые очень сильно упростят мне жизнь)

И так, мы хотим шифровать файлы, при чем в нескольких потоках.

Для больших файлов мы можем и должны использовать блочное шифрование.
Но стоит ли его использовать для небольших файлов, которых большинство, как правило?
Может ли одновременная аллокация в памяти нескольких крупных объектов(10мб, например) нарушить нормальную работу системы?

Кустарные замеры показали отставание на 15-25% при использовании буфера 8кб для файла размером 11мб (ChaCha20)
Довольно существенно.

Стоит также отметить, что тест проводился на SSD, в одном потоке.
А что, если в качестве хранилища будет выступать старый жесткий диск, каждое оброщение к которому будет занимать в десятки раз больше времени?
Можно представить сколько будет генерироваться обращений в режиме многопоточности.

Более редкие обращаения к диску, больший объем записи за раз или частые обращения и меньший объем?
Что из этого будет быстрее с точки зрения времени, затраченного на запись?



Заранее спасибо!
И извините, если вопрос изложен слегка беспорядочно)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Это ты перед собесом к Локбиту решил матчасть подтянуть штоле?)
 
Это ты перед собесом к Локбиту решил матчасть подтянуть штоле?)
Скоро локбит будет матчасть подтягивать, чтобы на нас работать)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Для больших файлов мы можем и должны использовать блочное шифрование.
Но стоит ли его использовать для небольших файлов, которых большинство, как правило?
А в чем проблема с небольшими файлами и как вы их хотите шифровать?

Может ли одновременная аллокация в памяти нескольких крупных объектов(10мб, например) нарушить нормальную работу системы?
Нет. И это разве крупные?
Но если хочется сверхоптимизаций, то я делал когда-то так - выделял через VirtualAlloc допустим 64 мб, и писал кастомный аллокатор, который "выделял" блоки, помечал их как free/commit, ну ты понял. хз как в вашем расте, я пишу на С.
 
Надо внести ясность. Для шифрования файлов, любых размеров, можно использовать блочные шифры. Но, надо учитывать, что для этого вам придется выравнивать размер файла (данных) на размер блока. К примеру, для AES это 16 байт (размер блока AES). Что, естественно, влечет автоматически увлечение размера данных и как следствие, размер файла. На больших файлах это не критично. На мелких... как посмотреть.. в зависимости от исходного размера файла. Может в файле данных всего 17-18 байт, после выравнивания это будет уже 32 байта.
Кто-то скажет, что это все фигня. Но на больших объемах файлов, общий размер зашифрованных файлов увеличется значительно (до нескольких сотен мегабайт может доходить на жестком диске (SSD), что может грозить переполнением диска, если он уже почти заполнен и остановкой процесса шифрования с последующим "вылетом" программы шифрования). Плюс к выровненному размеру файла добавляем, метаданные (ключ шифрования самого файла и доп. информация, как правило в минимуме, это реальный размер файла, по которому будет "обрезаться" метадата после расшифровки файла). Кстати, AES, если это не AES NI (с аппаратным ускорением), довольно меленный блочный шифр (программная его реализация). AES NI хорош, но тут мы привязываемся уже к железу, а именно, к процессорам, которые поддерживают его. И т.к. могут попадаться старые модели процессоров, тут нам надо будет переключаться на программную реализацию, а это просадка по скорости.
Для шифрования файлов, любых размеров (но с небольшим уменьшением скорости) можно использовать поточные шифры.
Как пример, так же Salsa20. В случае, с потоковым шифром, не нужно выравнивать размер файла (данных).
Шифруем от нулевого до последнего байта. Добавляем в конец зашифрованные метаданные (содержащий ключ шифрования самого файла) и все.
Реальный размер файла нам не нужно сохранять в метаданных. Т.к. размер метаданных всегда известен, то при расшифровке мы просто "откусываем" от конца файла их. И размер расшифрованного файла будет соответствовать оригинальному, до шифрования.
Главное, нужно понимание, что нам необходим баланс скорости и надежности шифрования.
Из программных и достаточно надежных блочных шифров, я бы рекомендовал RC5 или RC6. Во первых, у них нет аппаратной зависимости как у AES NI. По скорости они не уступают тому же AES NI (я делал тесты). И рекомендую использовать RC5 и (или) RC6 с длиной слова 64 или 128 бит в режиме CBC.
Для шифрования метаданных, лучше curve25519-donna. С помощью него создаем ключ размером 256 бит и им шифруем метаданные, тем же шифром, что и файл. Можно RSA, но он медленный и будет неизбежная просадка скорости. При условии, что ключ (метаданные) у каждого файла уникальны.
Безусловно скорость шифрования высока, если мы открываем файл с флагом FILE_FLAG_NO_BUFFERING, вместе с другими флагами, необходимыми для асинхронного доступа к файлу. Но перед процессом шифрования необходимо выронить размер файла на размер сектора (для NTFS, по умолчанию 512 байт (0х200)), в противном случае получим ошибку при попытке записи. Вот в этом случае будет оправдано использование блочного шифра.
Это мысли в слух. Возможно, что из написанного выше, уже вам многое известно.
Возможно коллеги меня в чем-то поправят. Сильно не пинайте :cool:
 
Но если хочется сверхоптимизаций, то я делал когда-то так - выделял через VirtualAlloc допустим 64 мб, и писал кастомный аллокатор, который "выделял" блоки, помечал их как free/commit, ну ты понял. хз как в вашем расте, я пишу на С.
Дык зачем велосипед изобретать, куча уже и так реализует в себе описанное тобой действие, там имеются блоки, и менеджер памяти кучи дергает из уже заранее скажем так "свободных" кусков
Я когда-то делал замеры, подряд n-ное количество попарных вызовов HeapAlloc и HeapFree и так же VirtualAlloc и VirtualFree, так вот на небольших обьемах памяти (не помню точные цифры) в куче все выделялось и освобождалось в 2 раза быстрее чем через VirtualAlloc, но когда обьемы памяти большие, допустим 100-500 мб, то там почти одинаково, и все равно на куче было быстрее, хоть разница уже и не так значительна была. При этом для чистоты эксперимента выделялись не все время одинаковые куски памяти, а многопоточно кусочки разной длины, но +-5% в пределах указанной экспериментальной длины, что бы менеждер памяти не кидал нам после освобождения один и те же участки памяти циклично. Поэтому юзайте кучу и не городите велосипеды, это все уже реализовано в винде, без лишнего вмешательства программиста.
придется выравнивать размер файла (данных) на размер блока. К примеру, для AES это 16 байт (размер блока AES)
Есть режимы шифрования AES которые не требуют выравнивания данных по границе 16 байт, не помню точное название, так как я AES не использую, но я ставил эксперименты месяца 2 назад и наткнулся на один из режимов, который позволял шифровать произвольное количество байт, не выровненных по границе 16
Можно RSA, но он медленный и будет неизбежная просадка скорости. При условии, что ключ (метаданные) у каждого файла уникальны.
RSA медленный только в вопросе генерации ключей, само шифрование происходит очень быстро
Зачем генерировать на каждый файл свой RSA ключ ? Достаточно одного мастер-ключа (public), зашитого в теле шифровальщика (он уже сгенерирован, мы не тратим на это время)
В таком случае весь процесс выглядит так - генерация ключей AES\Salsa20, шифрование этих ключей при помощи того самого мастер-ключа RSA, и запись в конец файла, далее шифрование самого файла ключами AES\Salsa20 (их незашифрованными копиями в оперативной памяти)
Вот и все, нигде нет просадки в скорости
Сюда можно еще включить генерацию уникального RSA ключа на каждый хост, где запускается шифровальщик, тогда уникальный публичный ключ этого хоста используется для шифрования ключей AES\Salsa20, а приватный ключ шифруется при помощи зашитого в теле шифровальщика мастер-ключа. Даже в таком варианте мы теряем буквально 2-3 секунды на генерацию уникального ключа для конкретного хоста.
Нет смысла на каждый файл генерировать новый RSA ключ, достаточно одного, а вот AES\Salsa20 - конечно же должны быть разными для каждого файла

НО САМОЕ ГЛАВНОЕ Для всех в теме полезная инфа - достаточно мало смысла в оптимизациях скорости шифрования, так как основные просадки в скорости - это операции ввода и вывода, именно тут потолок скорости. Хоть 10 Гб\с у тебя шифрование, ты все равно упрешься в IO, и даже при граммотном распараллеливании задач "задачи" шифрования всегда будут ждать "задачи" чтения\записи, от этого никуда не деться. Наоборот может случиться только если ты специально как-то попытаешься замедлить скорость шифрования до уровня скорости IO. Но если специально ничего не портить, то IO будет всегда медленнее шифрования. Самое узкое место, которое еще называют "бутылочным горлышком" - это операции IO. Если все очень хорошо распараллелено, разницы между обычным AES, или AES-NI или же Salsa20 практически не будет, потому что все задачи будут "дожидаться" пока закончится чтение\запись, даже при асинхронном и прочих доступах, быстрый поток\потоки шифрования отработает, и будет дожидаться поступления новой порции информации. А если не параллелить и асинхронить, то какой смысл вообще от многозадачности, будет все в одни поток тянуться как черепаха.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Пожалуйста, обратите внимание, что пользователь заблокирован
Я когда-то делал замеры, подряд n-ное количество попарных вызовов HeapAlloc и HeapFree и так же VirtualAlloc и VirtualFree, так вот на небольших обьемах памяти (не помню точные цифры) в куче все выделялось и освобождалось в 2 раза быстрее чем через VirtualAlloc, но когда обьемы памяти большие, допустим 100-500 мб, то там почти одинаково, и все равно на куче было быстрее, хоть разница уже и не так значительна была.
Куча реализована в юзермоде и выделяет память сама себе условно через VirtualAlloc. VirtualAlloc лазит в ядро, чтобы выделить страницы виртуальной памяти. Если куче хватает выделенной до этого памяти, чтобы разместить блок, то она ничего нового выделять не будет. В этих случаях будет быстрее. Но в целом, куда быстрее вендовой кучи будет сделать свой арена-аллокатор, выделить большой линейный диапазон памяти для него, и из него уже выделять самому себе память.

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

RSA медленный только в вопросе генерации ключей, само шифрование происходит очень быстро
Элиптические кривые быстрее будут скорее всего, но надо тестить.
 
Дык зачем велосипед изобретать, куча уже и так реализует в себе описанное тобой действие, там имеются блоки, и менеджер памяти кучи дергает из уже заранее скажем так "свободных" кусков
Я когда-то делал замеры, подряд n-ное количество попарных вызовов HeapAlloc и HeapFree и так же VirtualAlloc и VirtualFree, так вот на небольших обьемах памяти (не помню точные цифры) в куче все выделялось и освобождалось в 2 раза быстрее чем через VirtualAlloc, но когда обьемы памяти большие, допустим 100-500 мб, то там почти одинаково, и все равно на куче было быстрее, хоть разница уже и не так значительна была. При этом для чистоты эксперимента выделялись не все время одинаковые куски памяти, а многопоточно кусочки разной длины, но +-5% в пределах указанной экспериментальной длины, что бы менеждер памяти не кидал нам после освобождения один и те же участки памяти циклично. Поэтому юзайте кучу и не городите велосипеды, это все уже реализовано в винде, без лишнего вмешательства программиста.

Есть режимы шифрования AES которые не требуют выравнивания данных по границе 16 байт, не помню точное название, так как я AES не использую, но я ставил эксперименты месяца 2 назад и наткнулся на один из режимов, который позволял шифровать произвольное количество байт, не выровненных по границе 16

RSA медленный только в вопросе генерации ключей, само шифрование происходит очень быстро
Зачем генерировать на каждый файл свой RSA ключ ? Достаточно одного мастер-ключа (public), зашитого в теле шифровальщика (он уже сгенерирован, мы не тратим на это время)
В таком случае весь процесс выглядит так - генерация ключей AES\Salsa20, шифрование этих ключей при помощи того самого мастер-ключа RSA, и запись в конец файла, далее шифрование самого файла ключами AES\Salsa20 (их незашифрованными копиями в оперативной памяти)
Вот и все, нигде нет просадки в скорости
Сюда можно еще включить генерацию уникального RSA ключа на каждый хост, где запускается шифровальщик, тогда уникальный публичный ключ этого хоста используется для шифрования ключей AES\Salsa20, а приватный ключ шифруется при помощи зашитого в теле шифровальщика мастер-ключа. Даже в таком варианте мы теряем буквально 2-3 секунды на генерацию уникального ключа для конкретного хоста.
Нет смысла на каждый файл генерировать новый RSA ключ, достаточно одного, а вот AES\Salsa20 - конечно же должны быть разными для каждого файла

НО САМОЕ ГЛАВНОЕ Для всех в теме полезная инфа - достаточно мало смысла в оптимизациях скорости шифрования, так как основные просадки в скорости - это операции ввода и вывода, именно тут потолок скорости. Хоть 10 Гб\с у тебя шифрование, ты все равно упрешься в IO, и даже при граммотном распараллеливании задач "задачи" шифрования всегда будут ждать "задачи" чтения\записи, от этого никуда не деться. Наоборот может случиться только если ты специально как-то попытаешься замедлить скорость шифрования до уровня скорости IO. Но если специально ничего не портить, то IO будет всегда медленнее шифрования. Самое узкое место, которое еще называют "бутылочным горлышком" - это операции IO. Если все очень хорошо распараллелено, разницы между обычным AES, или AES-NI или же Salsa20 практически не будет, потому что все задачи будут "дожидаться" пока закончится чтение\запись, даже при асинхронном и прочих доступах, быстрый поток\потоки шифрования отработает, и будет дожидаться поступления новой порции информации. А если не параллелить и асинхронить, то какой смысл вообще от многозадачности, будет все в одни поток тянуться как черепаха.
Спасибо за развернутый ответ.

У меня уже каша в голове от этого всего.
Как раз ограничения чтения/записи вызывают больше всего вопросов и именно про них изначально я и спрашивал.

Если на хосте стоит ЖД 5400 оборотов с пиковой скоростью чтения 25мб, то ничего особо не поможет. А вот если стоит быстрый SSD, что сейчас нередкость, то тут уже есть вероятность упереться в процессор. Однако, как бы там ни было, такие вещи как размер буфера, частота и размеры "порций" записи за раз, по идее должны влиять на конечную пропускную способноть.

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

Кстати, поддержка аппаратного ускорения AES проверяется легко, так что можно реализовать сразу два симметричных алгоритма. В моем случае, скорее всего, это будет ChaCha20-Poly1305 и как раз AES-GCM, упомянутый выше.
 
Последнее редактирование:
А вот если стоит быстрый SSD, что сейчас нередкость, то тут уже есть вероятность упереться в процессор.
Все равно упрешься в скорость чтения\записи, можешь проверить, пошифруй при помощи AES буфер размером 100 мб в цикле 10000 раз
и так же сделай запись 100 мб в один и тот же файл в цикле 10000 раз
сделай замеры, и ты увидишь какая колоссальная разница будет в скоростях, даже на современных SSD
чача как правило будет значительно медленнее AES, хотя для слабых тачек мастхев
Чача будет быстрее AES без аппаратного ускорения, это тоже уже проверено неоднократно, а вот с AES-NI чача потягаться не сможет
 
Есть режимы шифрования AES которые не требуют выравнивания данных по границе 16 байт, не помню точное название, так как я AES не использую, но я ставил эксперименты месяца 2 назад и наткнулся на один из режимов, который позволял шифровать произвольное количество байт, не выровненных по границе 16
Блочный алгоритм на то и блочный, что шифрует данные блоками. Это не поточный. Только поточный не требует выравнивания.
Вспоминай этот волшебный AES, я такой разновидности не знаю (https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
RSA медленный только в вопросе генерации ключей, само шифрование происходит очень быстро
Зачем генерировать на каждый файл свой RSA ключ ? Достаточно одного мастер-ключа (public), зашитого в теле шифровальщика (он уже сгенерирован, мы не тратим на это время)
RSA с curve25519 по скорости рядом не стоял. Это доказанный факт. Шифрование public экспанентой в RSA относительно быстрое. А расшифровка? Там приватная экспонента не 10001 к примеру.. а равна длине битности ключа (прим. 1024) и расшифровка медленная. В противовес, в случае с curve25519 шифрование и расшифровка будет равна по скорости. И это тоже доказанный факт.
 
Блочный алгоритм на то и блочный, что шифрует данные блоками. Это не поточный. Только поточный не требует выравнивания.
Вспоминай этот волшебный AES, я такой разновидности не знаю
Выше Dildo Fagins написал название - это Счетчик Галуа (GCM). Разновидность AES. AES у нас блочный ? Блочный. Просто такая разновидность.

RSA с curve25519 по скорости рядом не стоял. Это доказанный факт. Шифрование public экспанентой в RSA относительно быстрое. А расшифровка? Там приватная экспонента не 10001 к примеру.. а равна длине битности ключа (прим. 1024) и расшифровка медленная. В противовес, в случае с curve25519 шифрование и расшифровка будет равна по скорости.
Зачем нам скорость дешифровки ? Главное все быстро и тихо зашифровать, это основная цель, декрипт идет после атаки и тем более "собеседования", там торопиться некуда
 
Выше Dildo Fagins написал название - это Счетчик Галуа (GCM).
Прочитай. "Режим GCM определяется для блочных шифров с размером блока в 128 бит."
Найди мне там, что данные не надо выравнивать.
 
Прочитай. "Режим GCM определяется для блочных шифров с размером блока в 128 бит."
Найди мне там, что данные не надо выравнивать.
Мне не нужно искать теорию, я на практике шифровал AES невыровненные данные, даже сейчас открыл проектик с либой cryptopp и повторил эксперимент, зашифровал данные длиной 12 байт, получил на выходе буфер длиной 12 байт используя:
1) CFB_Mode
2) OFB_Mode
3) CTR_Mode
Ничего не ровнял, на вход 12 байт, на выход 12 байт
ADD, Проверил то же самое с длиной 5, все работает, как швейцарские часы
P.S. Порой стоит взять в руки инструмент и потыкаться на практике, чем тыкать в теорию, которую не до конца понимаешь, не нужно дезинформировать народ
 
cryptopp
загляни в отладчике внутрь. то что ты на входе и на выходе получаешь 12 байт, не значит, что внутри либы данные не выравниваются.
шифруется блок 16 байт. на выходе он обрезается по размеру входящих данных.
и мы говорим о алгоритме шифрования, а не о криптолибе. не надо путать мягкое с теплым.
 
загляни в отладчике внутрь. то что ты на входе и на выходе получаешь 12 байт, не значит, что внутри либы данные не выравниваются.
шифруется блок 16 байт. на выходе он обрезается по размеру входящих данных.
Как это мешает мне в контексте шифрования файлов ? Мы же в этом контексте общаемся, не придется ровнять файлы по границе 16 байт, опять повторюсь - не нужно дезинформировать людей
Спокойно используешь нужный тебе режим шифрования и радуешься жизни
Из твоей же википедии вырезка, куда ты ссылку давал - "И GCM и GMAC принимают на вход вектор инициализации произвольной длины" - то же самое и с входными данными.

К тому же если бы использовались все 16 байт блока, а потом они обрезались бы по какой-то причине, мы бы теряли часть значимой информации, и расшифровка была бы невозможна
Алгоритм внутри адаптивный, он просто не использует вообще оставшиеся байты из "блока", если байт меньше чем 16. Если больше, то будет как обычный блок, затем адаптив с частичным использованием блока для оставшихся байт. Но он не отрезается, он попросту даже не используется.
 
Последнее редактирование:
Как это мешает мне в контексте шифрования файлов ? Мы же в этом контексте общаемся, не придется ровнять файлы по границе 16 байт, опять повторюсь - не нужно дезинформировать людей
Спокойно используешь нужный тебе режим шифрования и радуешься жизни
Согласен. Ну кому и кобыла невеста.
только чувак понимания не получит о принципе блочного шифра.
пусть использует что хочет. если нужен сиюминутный рецепт, то cryptopp пойдет. знаний только это не прибавит.
 
Чтобы не создавать отделбную тему, задам еще один вопрос тут.

Стоит ли собирать пулл директорий перед непосредственно шифрованием или молотить все подряд?

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

Можно конечно собрать директории в памяти, но даже на пустой виртуалке они занимают 200мб
 
если нужен сиюминутный рецепт, то cryptopp пойдет
И даже тут я бы его не рекомендовал, так как он медленный, удобный но медленный, есть более быстрые библиотеки, с хорошей релизацией. Я сравнивал чачу из mbedtls и cryptopp, последний проигрывал примерно на 30% в скорости
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх