D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Автор @Захотел-остаться-анонимным
Статья написана для Конкурса статей #10
Ребятушки, предлагаю обсудить один вопрос в житии всяческих Бенов Стиллеров, который всегда казался мне очень странным. А именно: то и дело всплывает какой-то недовольный господин, который купил себе уютненький (как ему казалось) стиллер Х, но теперь обвиняет партнерку стиллера X в том, что они пиздят его драгоценные логи. Или, например, сломали панель стиллера Х, из-за чего все логи утекли и теперь путешествуют по интернетам. Очередное сравнительно недавнее обсуждение этого вдохновило меня на написание этой статьи.
Оставим за скобками всю морально-этическую составляющую использования стиллеров, философские вопросы доверия друг-другу в наше непростое время, а также то, что процесс спизжевания логов может быть основной бизнес моделью партнерки стиллера Х, и обратимся к технической стороне вопроса. Дело в том, что понимание криптографии, как таковой, и честная реализация некоторых ее подходов может практически полностью убрать из уравнения опасность спизженных логов.
Немного теории
Начнем с небольшого количества теории, рассказанной простым пацанским языком, а затем перейдем к практике. В далеком 1976 году на Национальной Компьютерной Конференции очень смышлёными дядьками Уитфилдом Диффи и Мартином Хеллманом была выдвинута судьбоносная для криптографии идея о шифровании с открытыми ключами. До этого безопасная передача ключей шифрования по открытым каналам связи была весьма проблематична, поскольку ключ мог быть перехвачен, а все данные расшифрованы с его помощью.
Алгоритмы шифрования можно разделить по принципу использования ключей на симметричные и асимметричные. Первые для шифрования и расшифровки данных используют один и тот же ключ. Да-да, именно тот один и тот же ключ, который может быть перехвачен. Асимметричные алгоритмы с другой стороны используют ключевую пару: так называемый "публичный ключ" для шифрования и "приватный ключ" для расшифровки данных. Таким образом, мисс Алиса говорит всем: "так, челики, вот вам мой публичный ключ, пишите мне свои секретные сообщения", но приватный ключ держит у себя и никому не показывает. Мистер Боб шифрует свои секретики на публичном ключе мисс Алисы и посылает ей шифр-данные. Мисс Алиса расшифровывает секретики на своем приватном ключе, и никакая ебучая Ева не может узнать секретики, которые Боб переслал Алисе, пока у нее нет доступа к приватному ключу Алисы. В обратную сторону уже Боб может сделать себе публичный и приватный ключи и чувствовать безопасность входящих от Алисы или кого-то другого секретиков. Если вам когда-либо было интересно, почему в криптографии обычно все объясняют с участием Алисы, Боба и Евы, читайте тут, мы традиций не нарушаем.
Можно условно сказать, что в мире асимметричных алгоритмов шифрования существуют только RSA (Ривест, Шамир, Адлеман) и ECC (эллиптические кривые). Слава Летающему Макаронному Монстру, нам с вами не нужно особо много шарить в математике, чтобы использовать эти алгоритмы, вдаваться в подробности о том, как они работают, мы конечно же не будем.
Вроде бы, концепция весьма годная: шифровать сообщения Алисе может кто угодно, а расшифровать их может только сама Алиса. Но почему же тогда асимметричные шифры давным давно не выпилили симметричные из мира практической криптографии. Дело в том, что асимметричные шифры слишком медленные (помимо некоторых других проблем), чтобы их использовать для большого количества данных. Но! Комбинируя асимметричные и симметричные алгоритмы мы можем получить преимущества обоих типов в одном.
Каким же образом их можно объединить? Да очень просто: генерировать ключи симметричного шифрования на новый сеанс связи, а для обмена этими ключами пользоваться асимметричным алгоритмом. Я понимаю, что многим из вас тут я не открыл Америку (сорян, дропами зиродеев не пахнет), тк такой подход используется просто повсеместно в сети Интернет и много где еще. Но давайте посмотрим, как это можно использовать в среде Бенов Стиллеров.
Смоделируем ситуацию
Допустим у нас есть некий новый клиент, который решил купить себе стиллер, будем его так и называть - "Клиент". Так вот, Клиент приходит к Продавцу и говорит, мол "давай мне мой билд". Продавец выдает ему некую тулзу, с помощью которой Клиент генерирует себе ключевую пару какого-то асимметричного алгоритма, допустим RSA. В качестве такой тулзы можно использовать стороннюю программу, типа OpenSSL, или написать кастомную тулзу, но важно, чтобы она поставлялась без обфускации и морфинга, или вообще с исходными кодами в придачу, чтобы Клиент при необходимости мог провести ее аудит (и убедиться, что его нигде не наёбывают).
Публичный ключ Клиент отправляет Продавцу, а приватный хранит у себя и никому не дает. Продавец вшивает публичный ключ Клиента в новый билд Стиллера, который он передает Клиенту. Непосредственно в коде Стиллера после сборки каждого нового лога происходит следующее. Сначала генерируется псевдослучайный ключ для симметрического алгоритма шифрования, допустим AES. Лог зашифровывается с помощью симметричного алгоритма и сгенерированного ранее ключа. Ключ симметричного алгоритма зашифровывается асимметричным алгоритмом с помощью вшитого публичного ключа Клиента и, допустим, дописывается в конец шифр-данных лога.
И получается следующее. Каждый лог зашифрован на каком-то отдельном рандомном ключе симметричного шифрования, который может получить только обладатель приватного ключа, то есть только Клиент (если он, конечно, не был доблоёбом и не давал свой приватный ключ кому ни попадя). Продавец может собирать у себя в панели такие шифр-контейнеры с логами клиентов, при этом ни сам Продавец, ни тот сторонний кулхацкер, который каким-то образом ломанул панель, не сможет эти крипто-контейнеры расшифровать, так как приватные ключи находятся только у Клиентов. Клиенты же скачивают свои логи и расшифровывают их у себя локально с помощью своих приватных ключей.
У такого подхода, безусловно, есть свои недостатки. Например, если Клиент внезапно проебал где-то свой ключ, то все свои логи он тоже уже не сможет расшифровать. Или, например, если особо хитро-выебанный Продавец будет шифровать симметричный ключ не только на ключе Клиента, но и на каком-то своем, и без палева дописывать его к шифр-данным. Или же отбрасывать два разных шифр-контейнера: для Клиента и для Продавца. В целом, эти ситуации при наличии достаточной квалификации можно проверить (например, на предмет того, что в шифр-данных присутствуют только зашифрованные симметричным алгоритмом логи и одна версия зашифрованного асимметричным алгоритмом ключа, или что билд не левачит какими-то дополнительными даннами). И понятно, что тогда Продавец не сможет отображать логи в красивых таблицах в панели, да и расшифровка паролей и кук на сервере панели станет невозможной. Но суммарно этот подход может быть весьма неплохим в плане повышения уровня доверия Клиентов к Продавцу, а также исключить то, что слитые логи будут путешествовать по Интернетам.
Переходим к практике
Я набросал небольшой пример реализации такого подхода на дотнетах и языке программирования C#. Выбор языка обусловлен тем, что на его примере легко показать реализацию подхода, ведь в дотнет фреймворк с бородатых времен встроен и алгоритм RSA (асимметричный) и алгоритм AES (симметричный). Насколько я помню, какие-то из встроенных классов являются полностью managed-реализацией, то есть реализованы непосредственно на C#, а какие-то являются простой прослойкой поверх CryptoAPI. Разбираться, какие именно какие, я конечно же не стал, да и вообще сравнительно мало пишу на C#, так что заранее прошу прощения, если код не оптимальный. Напишите в комментариях, как бы вы его улучшили, если чего.
И как же без подъёба?... Я знаю, что разработчики публичных и приватных стиллеров на С# очень любят друг у друга (ну скажем) "заимствовать" код, поэтому реализация на языке C# для них будет привычнее, штоль. Ей богу, как только я вижу один и тот же пресловутый класс SqLiteHandler, который сначала дизассемблировали из VB.NET кода давным давно, а потом растащили просто по всем стиллерам, мне хочется выколоть себе глаза...
Для начала рассмотрим генерацию ключей. Один из классов в дотнете, который реализует RSA называется RSACryptoServiceProvider. Если ему в конструктор передать размер ключа в битах, то он сгенерирует новую ключевую пару. Хранение RSA ключей в нем сделано довольно странно: в виде XML с BASE64 данными ключей, но окей. Метод для генерации ключей принимает два полных пути на файловой системе, они указывают, куда методу сохранить приватный и публичный ключ соответственно.
C#: Скопировать в буфер обмена
Стоит сделать небольшую ремарку о размере RSA ключей. В принципе, я являюсь сторонником мнения, что в данном конкретном случае хватит ключей размером в 2048 бит, но если вы хотите большей "секьюрности", то можно сделать ключи 4096 или 8192 бита. В зависимости от увеличения размера RSA ключа зашифрованный AES ключ и вектор инициализации будет занимать больше места. То есть для ключа размером 2048 бит, размер дополнительных данных для передачи AES ключа составит 256 байт, для 4096 бит - 512 байт (в одном байте 8 бит, ога?).
Теперь представим, что в исходный код Стиллера добавлен следующий метод для шифрования массива байт, который был получен, допустим, из заранее созданного ZIP-архива с новыми логами. Метод принимает публичный ключ Клиента и массив данных, которые нужно Клиенту зашифровать. Сначала мы инициализируем алгоритмы RSA и AES, алгоритму RSA подпихиваем публичный ключ Клиента.
При инициализации алгоритма AES происходит генерация симметричного ключа и вектора инициализации, из которых мы формируем буфер с ключевой информацией и зашифровываем его с помощью RSA и публичного ключа Клиента. Второй параметр метода шифрования RSA (установленный в истину) указывает на то, что мы будем использовать OAEP (Optimal Asymmetric Encryption Padding) для выравнивания, в противном случае будет использоваться PKCS#1 v1.5, насколько я понимаю. Вдаваться в подробности о различиях двух этих алгоритмов, наверное, не стоит, ограничимся тем, что в интернетах пишут, что OAEP лучше.
Дальше мы устанавливаем режим алгоритма в CBC (Cipher Block Chaining, то есть режим сцепления блоков), при этом шифрование каждого следующего блока будет зависеть от предыдущего. Таким образом, если в открытых данных вдруг находятся длинные последовательности однотипных или же предсказуемых данных, по шифр-данным это будет понять сложно. Алгоритм AES является блочным, в данном случае шифрование происходит блоками по 16 байт. Если размер данных не кратен размеру блока, то нужно применять выравнивание. В качестве алгоритма выравнивания мы выбираем PKCS7 без особых глубоко-философских на то причин.
Далее мы просто производит шифрование данных алгоритмом AES. В дотнетах принято все делать через потоки данных, наверное, это в целом правильно (для учета случая, когда нужно обработать большое количество данных и не сожрать всю память), но для целей шифрования сравнительно небольшого лога - это не удобно, но окей. Для шифр-данных я сделал отдельный буфер, в который происходит шифрование, затем этот буфер объединяется с зашифрованным алгоритмом RSA ключом симметричного шифрования. Если вам вдруг станет нужно обрабатывать таким образом большие данные, то старайтесь не плодить дополнительных буферов в памяти.
C#: Скопировать в буфер обмена
У Клиента есть тулза для расшифровки логов и его собственный приватный ключ, в этой самой тулзе реализован следующий метод, который по своей сути является просто зеркальным отражением метода шифрования. Мы разделяем данные на зашифрованные логи и зашифрованный алгоритмом RSA симметричный ключ (с вектором инициализации). В данном случае нам нужно знать, какой размер будет у блока данных зашифрованного симметричного ключа, этот размер можно получить после инициализации RSA через свойство KeySize (возвращается размер в битах, поэтому мы приводим его к байтам). Далее мы расшифровываем AES ключ и вектор инициализации и с его помощью расшифровываем и возвращаем данные. Опять же данный подход не совсем оптимальный для больших данных, но для логов - почему бы нет. Важно отметить, что параметры алгоритмов шифрования, такие как режим и выравнивание, очевидным образом должны быть одинаковые при шифровании и расшифровке.
C#: Скопировать в буфер обмена
Я приложу полный демо-код этого подхода к статье, он должен работать на всех версиях дотнетов от 4.0 до 4.8. Скорее всего он будет работать и на более ранних версиях (если вам такое может быть нужно), но для этого нужно будет заменить вызовы некоторых методов своим кодом (например, метода CopyTo для потоков данных).
Заключение
Итак, мы с вами посмотрели (условно) реализацию старого (как мир) протокола господинов Диффи и Хеллмана применительно к современным стиллерам. Как говорили древние криптографы: "если сударь не хочет, чтобы логи его клиентов спиздили, сударю надобно использовать криптографию с открытыми ключами" (с). Да, у такого подхода есть свои недостатки, которые я предлагаю обсудить в комментариях, но вообще говоря, мне до сих пор не понятно, почему в каждом из стиллеров не применяется что-то такое? Или есть в природе стиллеры, которые так работают (я прост не шарю)? Может быть, все уже привыкли к типичной модели MaaS стиллеров, при которой риск спизженных логов является необходимым злом? В общем, я не знаю, да и не моё это дело по большому счету, но почему бы не обсудить? Пишите в комментариях, что думаете...
Специально для любимого XSS.is.
Автор материала - самый талантливый (в плане написания конкурсных статей) бот в мире XSSBot! (эти ихние американские ЧатыГПТ и китайские ЛЛМки сосац!)
Статья написана для Конкурса статей #10
Ребятушки, предлагаю обсудить один вопрос в житии всяческих Бенов Стиллеров, который всегда казался мне очень странным. А именно: то и дело всплывает какой-то недовольный господин, который купил себе уютненький (как ему казалось) стиллер Х, но теперь обвиняет партнерку стиллера X в том, что они пиздят его драгоценные логи. Или, например, сломали панель стиллера Х, из-за чего все логи утекли и теперь путешествуют по интернетам. Очередное сравнительно недавнее обсуждение этого вдохновило меня на написание этой статьи.
Оставим за скобками всю морально-этическую составляющую использования стиллеров, философские вопросы доверия друг-другу в наше непростое время, а также то, что процесс спизжевания логов может быть основной бизнес моделью партнерки стиллера Х, и обратимся к технической стороне вопроса. Дело в том, что понимание криптографии, как таковой, и честная реализация некоторых ее подходов может практически полностью убрать из уравнения опасность спизженных логов.
Немного теории
Начнем с небольшого количества теории, рассказанной простым пацанским языком, а затем перейдем к практике. В далеком 1976 году на Национальной Компьютерной Конференции очень смышлёными дядьками Уитфилдом Диффи и Мартином Хеллманом была выдвинута судьбоносная для криптографии идея о шифровании с открытыми ключами. До этого безопасная передача ключей шифрования по открытым каналам связи была весьма проблематична, поскольку ключ мог быть перехвачен, а все данные расшифрованы с его помощью.
Алгоритмы шифрования можно разделить по принципу использования ключей на симметричные и асимметричные. Первые для шифрования и расшифровки данных используют один и тот же ключ. Да-да, именно тот один и тот же ключ, который может быть перехвачен. Асимметричные алгоритмы с другой стороны используют ключевую пару: так называемый "публичный ключ" для шифрования и "приватный ключ" для расшифровки данных. Таким образом, мисс Алиса говорит всем: "так, челики, вот вам мой публичный ключ, пишите мне свои секретные сообщения", но приватный ключ держит у себя и никому не показывает. Мистер Боб шифрует свои секретики на публичном ключе мисс Алисы и посылает ей шифр-данные. Мисс Алиса расшифровывает секретики на своем приватном ключе, и никакая ебучая Ева не может узнать секретики, которые Боб переслал Алисе, пока у нее нет доступа к приватному ключу Алисы. В обратную сторону уже Боб может сделать себе публичный и приватный ключи и чувствовать безопасность входящих от Алисы или кого-то другого секретиков. Если вам когда-либо было интересно, почему в криптографии обычно все объясняют с участием Алисы, Боба и Евы, читайте тут, мы традиций не нарушаем.
Можно условно сказать, что в мире асимметричных алгоритмов шифрования существуют только RSA (Ривест, Шамир, Адлеман) и ECC (эллиптические кривые). Слава Летающему Макаронному Монстру, нам с вами не нужно особо много шарить в математике, чтобы использовать эти алгоритмы, вдаваться в подробности о том, как они работают, мы конечно же не будем.
Вроде бы, концепция весьма годная: шифровать сообщения Алисе может кто угодно, а расшифровать их может только сама Алиса. Но почему же тогда асимметричные шифры давным давно не выпилили симметричные из мира практической криптографии. Дело в том, что асимметричные шифры слишком медленные (помимо некоторых других проблем), чтобы их использовать для большого количества данных. Но! Комбинируя асимметричные и симметричные алгоритмы мы можем получить преимущества обоих типов в одном.
Каким же образом их можно объединить? Да очень просто: генерировать ключи симметричного шифрования на новый сеанс связи, а для обмена этими ключами пользоваться асимметричным алгоритмом. Я понимаю, что многим из вас тут я не открыл Америку (сорян, дропами зиродеев не пахнет), тк такой подход используется просто повсеместно в сети Интернет и много где еще. Но давайте посмотрим, как это можно использовать в среде Бенов Стиллеров.
Смоделируем ситуацию
Допустим у нас есть некий новый клиент, который решил купить себе стиллер, будем его так и называть - "Клиент". Так вот, Клиент приходит к Продавцу и говорит, мол "давай мне мой билд". Продавец выдает ему некую тулзу, с помощью которой Клиент генерирует себе ключевую пару какого-то асимметричного алгоритма, допустим RSA. В качестве такой тулзы можно использовать стороннюю программу, типа OpenSSL, или написать кастомную тулзу, но важно, чтобы она поставлялась без обфускации и морфинга, или вообще с исходными кодами в придачу, чтобы Клиент при необходимости мог провести ее аудит (и убедиться, что его нигде не наёбывают).
Публичный ключ Клиент отправляет Продавцу, а приватный хранит у себя и никому не дает. Продавец вшивает публичный ключ Клиента в новый билд Стиллера, который он передает Клиенту. Непосредственно в коде Стиллера после сборки каждого нового лога происходит следующее. Сначала генерируется псевдослучайный ключ для симметрического алгоритма шифрования, допустим AES. Лог зашифровывается с помощью симметричного алгоритма и сгенерированного ранее ключа. Ключ симметричного алгоритма зашифровывается асимметричным алгоритмом с помощью вшитого публичного ключа Клиента и, допустим, дописывается в конец шифр-данных лога.
И получается следующее. Каждый лог зашифрован на каком-то отдельном рандомном ключе симметричного шифрования, который может получить только обладатель приватного ключа, то есть только Клиент (если он, конечно, не был доблоёбом и не давал свой приватный ключ кому ни попадя). Продавец может собирать у себя в панели такие шифр-контейнеры с логами клиентов, при этом ни сам Продавец, ни тот сторонний кулхацкер, который каким-то образом ломанул панель, не сможет эти крипто-контейнеры расшифровать, так как приватные ключи находятся только у Клиентов. Клиенты же скачивают свои логи и расшифровывают их у себя локально с помощью своих приватных ключей.
У такого подхода, безусловно, есть свои недостатки. Например, если Клиент внезапно проебал где-то свой ключ, то все свои логи он тоже уже не сможет расшифровать. Или, например, если особо хитро-выебанный Продавец будет шифровать симметричный ключ не только на ключе Клиента, но и на каком-то своем, и без палева дописывать его к шифр-данным. Или же отбрасывать два разных шифр-контейнера: для Клиента и для Продавца. В целом, эти ситуации при наличии достаточной квалификации можно проверить (например, на предмет того, что в шифр-данных присутствуют только зашифрованные симметричным алгоритмом логи и одна версия зашифрованного асимметричным алгоритмом ключа, или что билд не левачит какими-то дополнительными даннами). И понятно, что тогда Продавец не сможет отображать логи в красивых таблицах в панели, да и расшифровка паролей и кук на сервере панели станет невозможной. Но суммарно этот подход может быть весьма неплохим в плане повышения уровня доверия Клиентов к Продавцу, а также исключить то, что слитые логи будут путешествовать по Интернетам.
Переходим к практике
Я набросал небольшой пример реализации такого подхода на дотнетах и языке программирования C#. Выбор языка обусловлен тем, что на его примере легко показать реализацию подхода, ведь в дотнет фреймворк с бородатых времен встроен и алгоритм RSA (асимметричный) и алгоритм AES (симметричный). Насколько я помню, какие-то из встроенных классов являются полностью managed-реализацией, то есть реализованы непосредственно на C#, а какие-то являются простой прослойкой поверх CryptoAPI. Разбираться, какие именно какие, я конечно же не стал, да и вообще сравнительно мало пишу на C#, так что заранее прошу прощения, если код не оптимальный. Напишите в комментариях, как бы вы его улучшили, если чего.
И как же без подъёба?... Я знаю, что разработчики публичных и приватных стиллеров на С# очень любят друг у друга (ну скажем) "заимствовать" код, поэтому реализация на языке C# для них будет привычнее, штоль. Ей богу, как только я вижу один и тот же пресловутый класс SqLiteHandler, который сначала дизассемблировали из VB.NET кода давным давно, а потом растащили просто по всем стиллерам, мне хочется выколоть себе глаза...
Для начала рассмотрим генерацию ключей. Один из классов в дотнете, который реализует RSA называется RSACryptoServiceProvider. Если ему в конструктор передать размер ключа в битах, то он сгенерирует новую ключевую пару. Хранение RSA ключей в нем сделано довольно странно: в виде XML с BASE64 данными ключей, но окей. Метод для генерации ключей принимает два полных пути на файловой системе, они указывают, куда методу сохранить приватный и публичный ключ соответственно.
C#: Скопировать в буфер обмена
Код:
private static void Generate(string path_private, string path_public) {
using var rsa = new RSACryptoServiceProvider(2048);
var xml_public = rsa.ToXmlString(false);
var xml_private = rsa.ToXmlString(true);
File.WriteAllText(path_public, xml_public, Encoding.ASCII);
File.WriteAllText(path_private, xml_private, Encoding.ASCII);
Console.WriteLine("Public key was written to {0}", path_public);
Console.WriteLine("Private key was written to {0}", path_private);
}
Стоит сделать небольшую ремарку о размере RSA ключей. В принципе, я являюсь сторонником мнения, что в данном конкретном случае хватит ключей размером в 2048 бит, но если вы хотите большей "секьюрности", то можно сделать ключи 4096 или 8192 бита. В зависимости от увеличения размера RSA ключа зашифрованный AES ключ и вектор инициализации будет занимать больше места. То есть для ключа размером 2048 бит, размер дополнительных данных для передачи AES ключа составит 256 байт, для 4096 бит - 512 байт (в одном байте 8 бит, ога?).
Теперь представим, что в исходный код Стиллера добавлен следующий метод для шифрования массива байт, который был получен, допустим, из заранее созданного ZIP-архива с новыми логами. Метод принимает публичный ключ Клиента и массив данных, которые нужно Клиенту зашифровать. Сначала мы инициализируем алгоритмы RSA и AES, алгоритму RSA подпихиваем публичный ключ Клиента.
При инициализации алгоритма AES происходит генерация симметричного ключа и вектора инициализации, из которых мы формируем буфер с ключевой информацией и зашифровываем его с помощью RSA и публичного ключа Клиента. Второй параметр метода шифрования RSA (установленный в истину) указывает на то, что мы будем использовать OAEP (Optimal Asymmetric Encryption Padding) для выравнивания, в противном случае будет использоваться PKCS#1 v1.5, насколько я понимаю. Вдаваться в подробности о различиях двух этих алгоритмов, наверное, не стоит, ограничимся тем, что в интернетах пишут, что OAEP лучше.
Дальше мы устанавливаем режим алгоритма в CBC (Cipher Block Chaining, то есть режим сцепления блоков), при этом шифрование каждого следующего блока будет зависеть от предыдущего. Таким образом, если в открытых данных вдруг находятся длинные последовательности однотипных или же предсказуемых данных, по шифр-данным это будет понять сложно. Алгоритм AES является блочным, в данном случае шифрование происходит блоками по 16 байт. Если размер данных не кратен размеру блока, то нужно применять выравнивание. В качестве алгоритма выравнивания мы выбираем PKCS7 без особых глубоко-философских на то причин.
Далее мы просто производит шифрование данных алгоритмом AES. В дотнетах принято все делать через потоки данных, наверное, это в целом правильно (для учета случая, когда нужно обработать большое количество данных и не сожрать всю память), но для целей шифрования сравнительно небольшого лога - это не удобно, но окей. Для шифр-данных я сделал отдельный буфер, в который происходит шифрование, затем этот буфер объединяется с зашифрованным алгоритмом RSA ключом симметричного шифрования. Если вам вдруг станет нужно обрабатывать таким образом большие данные, то старайтесь не плодить дополнительных буферов в памяти.
C#: Скопировать в буфер обмена
Код:
public static byte[] Encrypt(string public_key, byte[] data) {
using var rsa = new RSACryptoServiceProvider();
using var aes = new AesCryptoServiceProvider();
rsa.FromXmlString(public_key);
var key_buffer = new byte[48];
Array.Copy(aes.Key, 0, key_buffer, 0, 32);
Array.Copy(aes.IV, 0, key_buffer, 32, 16);
key_buffer = rsa.Encrypt(key_buffer, true);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
var mode = CryptoStreamMode.Write;
using var data_buffer = new MemoryStream();
using var encryptor = aes.CreateEncryptor();
using(var crypto_stream = new CryptoStream(data_buffer, encryptor, mode))
{ crypto_stream.Write(data, 0, data.Length); }
var encrypted_data = data_buffer.ToArray();
using var encrypted_buffer = new MemoryStream();
encrypted_buffer.Write(encrypted_data, 0, encrypted_data.Length);
encrypted_buffer.Write(key_buffer, 0, key_buffer.Length);
return encrypted_buffer.ToArray();
}
У Клиента есть тулза для расшифровки логов и его собственный приватный ключ, в этой самой тулзе реализован следующий метод, который по своей сути является просто зеркальным отражением метода шифрования. Мы разделяем данные на зашифрованные логи и зашифрованный алгоритмом RSA симметричный ключ (с вектором инициализации). В данном случае нам нужно знать, какой размер будет у блока данных зашифрованного симметричного ключа, этот размер можно получить после инициализации RSA через свойство KeySize (возвращается размер в битах, поэтому мы приводим его к байтам). Далее мы расшифровываем AES ключ и вектор инициализации и с его помощью расшифровываем и возвращаем данные. Опять же данный подход не совсем оптимальный для больших данных, но для логов - почему бы нет. Важно отметить, что параметры алгоритмов шифрования, такие как режим и выравнивание, очевидным образом должны быть одинаковые при шифровании и расшифровке.
C#: Скопировать в буфер обмена
Код:
public static byte[] Decrypt(string private_key, byte[] data) {
using var rsa = new RSACryptoServiceProvider();
using var aes = new AesCryptoServiceProvider();
rsa.FromXmlString(private_key);
var rsa_length = rsa.KeySize / 8;
var key_buffer = new byte[rsa_length];
var data_buffer = new byte[data.Length - rsa_length];
Array.Copy(data, 0, data_buffer, 0, data.Length - rsa_length);
Array.Copy(data, data.Length - rsa_length, key_buffer, 0, rsa_length);
key_buffer = rsa.Decrypt(key_buffer, true);
var aes_key = new byte[32];
var aes_iv = new byte[16];
Array.Copy(key_buffer, 0, aes_key, 0, 32);
Array.Copy(key_buffer, 32, aes_iv, 0, 16);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = aes_key;
aes.IV = aes_iv;
var mode = CryptoStreamMode.Read;
using var decrypted = new MemoryStream();
using var data_stream = new MemoryStream(data_buffer);
using var decryptor = aes.CreateDecryptor();
var crypto_stream = new CryptoStream(data_stream, decryptor, mode);
crypto_stream.CopyTo(decrypted);
return decrypted.ToArray();
}
Я приложу полный демо-код этого подхода к статье, он должен работать на всех версиях дотнетов от 4.0 до 4.8. Скорее всего он будет работать и на более ранних версиях (если вам такое может быть нужно), но для этого нужно будет заменить вызовы некоторых методов своим кодом (например, метода CopyTo для потоков данных).
Заключение
Итак, мы с вами посмотрели (условно) реализацию старого (как мир) протокола господинов Диффи и Хеллмана применительно к современным стиллерам. Как говорили древние криптографы: "если сударь не хочет, чтобы логи его клиентов спиздили, сударю надобно использовать криптографию с открытыми ключами" (с). Да, у такого подхода есть свои недостатки, которые я предлагаю обсудить в комментариях, но вообще говоря, мне до сих пор не понятно, почему в каждом из стиллеров не применяется что-то такое? Или есть в природе стиллеры, которые так работают (я прост не шарю)? Может быть, все уже привыкли к типичной модели MaaS стиллеров, при которой риск спизженных логов является необходимым злом? В общем, я не знаю, да и не моё это дело по большому счету, но почему бы не обсудить? Пишите в комментариях, что думаете...
Специально для любимого XSS.is.
Автор материала - самый талантливый (в плане написания конкурсных статей) бот в мире XSSBot! (эти ихние американские ЧатыГПТ и китайские ЛЛМки сосац!)