Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Как расшифровать текст при помощи алгоритма ассиметричного ключа #51

Closed
IverCold opened this issue Apr 15, 2024 · 17 comments
Assignees

Comments

@IverCold
Copy link

Добрый день! Я не смог найти в примерах возможности расшифровки текста ассиметричным ключом. Как это можно сделать?

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 15, 2024

Здравствуйте!

Полагаю, что вам подойдёт этот пример. Основную роль играют KeyExchangeFormatter/KeyExchangeDeformatter, экземпляры которых создаются на основе асимметричного ключа. Симметричный ключ может быть как постоянным (например, храниться в конфигурациионном файле приложения), так и случайным (если будет организован способ передачи параметров симметричного ключа от отправителя к получателю зашифрованных данных).

@IverCold
Copy link
Author

Я пробовал реализовать этот пример. Дело в том, что я отправляю открытый ключ в Контур, и они возвращают мне строку, которую я должен расшифровать с помощью закрытой части сертификата.
Это выглядит вот так:

            var encryptedStr = "здесь_длинная_полученная_строка";
            var encryptedBytes = Convert.FromBase64String(encryptedStr);
            var encryptedStream = new MemoryStream(encryptedBytes);
            var privateKeyAlgorithm = (GostAsymmetricAlgorithm)cert.GetPrivateKeyAlgorithm();
           
            var deformatter = privateKeyAlgorithm.CreateKeyExchangeDeformatter();
            using (var receiverSessionKey = deformatter.DecryptKeyExchangeAlgorithm(encryptedBytes))
            {
                var decryptedString = receiverSessionKey.ToString();
            }

Но на строке using код падает в ошибки:
CryptographicException: ASN.1 encoded byte array contains invalid structure 'Gost_R3410_KeyTransport'.
CryptographicException: ASN.1 decode error. SEQUENCE or SET is missing a required element. Offset: 2.

В чём тут может быть проблема?

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 16, 2024

Вам нужно внимательней посмотреть на указанный пример.

Метод DecryptKeyExchangeAlgorithm() делает дешифрацию общего секретного ключа, т.е. на вход он получает зашифрованный симметричный ключ. Как я понял, вы передаете ему не ключ, а зашифрованные данные. Для шифрации/дешифрации данных используется поток CryptoStream.

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

@IverCold
Copy link
Author

Я просто подумал, что есть вариант как-то выдернуть часть реализации расшифровки сообщения. Если я правильно понимаю, то речь идёт о расшифровке сообщения, зашифрованного открытым ключом сертификата. А значит его можно расшифровать закрытым ключом сертификата.
Подобно объекту RSACryptoServiceProvider, в котором есть методы .Encrypt(byte[]), .Decrypt(byte[]).

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 18, 2024

Да, действительно, RSA имеет методы Encrypt()/Decrypt(). Однако примечательно, что его нет среди методов базового класса AsymmetricAlgorithm. Судя по коду RSACryptoServiceProvider, внутри вызываются методы EncryptKey()/DecryptKey(), что наводит на мысль, что под данными подразумевается все-таки ключ (симметричного) шифрования, а не сами данные. Вам действительно не передают зашифрованный симметричный ключ, только зашифрованные данные? Если так, то я попробую изучить тему глубже, может что-то и получится. :)

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 23, 2024

@IverCold Если вопрос решен, предлагаю поделиться решением и закрыть задачу. :)

@IverCold
Copy link
Author

@AlexMAS Я лучше приложу инструкцию Контура, которую они мне дали. Нужно получить Access Token. Его можно получить по логину-паролю (как мы делаем сейчас), а можно по сертификату (так должно быть безопаснее). Чтобы получить токен по сертификату расшифровать случайный контент, который присылает Контур. Сам же инструкция вот здесь:
https://developer.testkontur.ru/doc/openidconnect?about=2

@IverCold
Copy link
Author

IverCold commented Apr 24, 2024

@IverCold Если вопрос решен, предлагаю поделиться решением и закрыть задачу. :)

Ну, я не настолько хорош, чтобы предложить решение в рамках вашей библиотеки = )
Но невероятная благодарность от меня за её существование. Без неё мы бы просто не взлетели - мы используем реализацию raw подписи для Контура/СФР как раз.

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 24, 2024

Спасибо за обратную связь! :)

Понятно, то есть вам не удалось выполнить аутентификацию по сертификату. А можете прикрепить файл с base64 этого encrypted_key, я попробую посмотреть ее через ASN.1-редактор. Может что-то прояснится, что они присылают в ответ. :)

@AlexMAS
Copy link
Owner

AlexMAS commented Apr 29, 2024

@IverCold Здравствуйте! У вас нет примера encrypted_key? :)

@IverCold
Copy link
Author

IverCold commented Aug 23, 2024

И снова здравствуйте! Я приношу извинения за пропажу на столь длительный срок. Но порой такова жизнь -_-

В прикреплённом архиве открытый сертификат, его 64base версия и то сообщение, которое нужно расшифровать и отправить обратно в Контур. Может быть есть какая-то возможность выделить методы Encrypt()/Decrypt() как в RSA, про что мы говорили выше.

Decipher_EncryptedKey.zip

@AlexMAS AlexMAS self-assigned this Aug 30, 2024
@AlexMAS
Copy link
Owner

AlexMAS commented Aug 30, 2024

Здравствуйте!

Я попробую повторить то, что есть в RSA.

@AlexMAS
Copy link
Owner

AlexMAS commented Sep 1, 2024

В общем, выяснилось следующее.

Как я и предполагал, CryptoPro CSP поддерживает шифрование произвольных блоков данных только на симметричных ключах. Подозреваю, что и с VipNet CSP ситуация аналогична, но мне не удалось проверить - нет технической возможности. Кстати, недавно была добавлена поддержка алгоритмов Магма и Кузнечик. Возможно, шифрование вышеуказанных данных было с участием этих новых алгоритмов.

Любые попытки использовать асимметричные ключи CryptoPro CSP для шифрования приводят к ошибкам. Криптопровайдер явно говорит: Invalid algorithm specified. Иначе говоря, повторить то, что умеет RSA, к сожалению, не получится.

Судя по тому, что мне удалось найти на форумах, есть какие-то серьезные сложности в реализации шифрования произвольных объемов данных с помощью асимметричных алгоритмов ГОСТ. Или сама философия шифрования по ГОСТ этого не предусматривает, не могу сказать. CryptoPro CSP поддерживает только подпись хэшей фиксированных размеров, то есть реализует только возможность цифровой подписи. Что же касается шифрования произвольных объемов данных, то в этом случае используются сессионные симметричные ключи. Алгоритм обмена примерно такой.

Отправляющая сторона:

  1. Удаленная сторона создает сессионный симметричный ключ.
  2. Шифрует данные сессионным ключом.
  3. С помощью публичного асимметричного ключа шифрует сессионный ключ.
  4. Отправляет получателю зашифрованный сессионный ключ и зашифрованные данные.

Получающая сторона:

  1. Получает зашифрованный сессионный ключ и зашифрованные данные.
  2. С помощью приватного асимметричного ключа расшифровывает сессионный ключ.
  3. Расшифровывает данные сессионным ключом.

Я посмотрел ваше зашифрованное base64-сообщение. Могу сказать, что это сообщение в каком-то странном и неизвестном мне формате. В бинарном представлении сообщение имеет странноватый размер - 970 байт. Это точно не ASN.1 формат. Самое интересное, что часть данных в этом сообщение представлена в открытом виде. Например, в явном виде представлен email сервиса сертификации.

ZholudevaMA_EncryptedKey

По совокумности данных я бы сказал, что это какой-то кастомный формат сообщения, но это не точно. Возможно, какое-то подобие JWT, раз в контексте документации к сервису речь идет об OpenId Connect. Однако я пересмотрел документацию и не нашел описание формата этого зашифрованного сообщения.

Попробуйте связаться с разработчиками или еще с кем-то. Пусть они вам расскажут, как декодировать это сообщение. Сделав это, вы там должны обнаружить зашифрованные данные и зашифрованный симметричный ключ. А далее процесс расшифровки сделать просто. Я думаю, что как-то так должно быть.

@AlexMAS
Copy link
Owner

AlexMAS commented Sep 3, 2024

@IverCold Дадите обратную связь, если что-то получится или не получится? ;)

@IverCold
Copy link
Author

IverCold commented Sep 3, 2024

@IverCold Дадите обратную связь, если что-то получится или не получится? ;)

Да, я как раз сегодня передал информацию нашему "связному" в Контуре. Может быть он сможет прояснить ситуацию.
Большое спасибо за столь быстрый и развёрнутый ответ!

@IverCold
Copy link
Author

IverCold commented Sep 4, 2024

Возвращаюсь с результатом. Всё оказалось неожиданно просто. Хватило встроенного класса EnvelopedCms из пространства имён System.Security.Cryptography.Pkcs;
Код:

        public static byte[] Decrypt(byte[] encryptedContent, X509Certificate2 cert)
        {
            var envelopedCms = new EnvelopedCms();
            envelopedCms.Decode(encryptedContent);
            envelopedCms.Decrypt(new X509Certificate2Collection(cert));
            return envelopedCms.ContentInfo.Content;
        }

Я даже ради любопытства проверил Encrypt - шифрование и дешифровка сообщения отработали. Интересно просто как это так? Он обращается к криптопровайдеру, определив алгоритм из сертификата?

@AlexMAS
Copy link
Owner

AlexMAS commented Sep 4, 2024

Круто! Рад, что у вас всё получилось. Я тогда закрываю эту задачу. Если будут вопросы, обращайтесь.

Интересно просто как это так? Он обращается к криптопровайдеру, определив алгоритм из сертификата?

Тут как раз всё вышло так, как я и предполагал. Я почему-то не подумал про EnvelopedCms, что сообщение передано в этом формате. Вызов метод EnvelopedCms.Decode() декодирует сообщение, то есть десериализует его в объект, в котором есть: 1) зашифрованный сессионный ключ; 2) алгоритм шифрации сессионного ключа; 3) зашифрованные данные. А далее метод EnvelopedCms.Decrypt() расшифровывает данные, используя эту информацию и указанный сертификат с приватным ключом. Фактически EnvelopedCms инкапсулирует логику обмена, которую я описал выше.

@AlexMAS AlexMAS closed this as completed Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants