GostCryptography
GostCryptography copied to clipboard
Как расшифровать текст при помощи алгоритма ассиметричного ключа
Добрый день! Я не смог найти в примерах возможности расшифровки текста ассиметричным ключом. Как это можно сделать?
Здравствуйте!
Полагаю, что вам подойдёт этот пример. Основную роль играют KeyExchangeFormatter
/KeyExchangeDeformatter
, экземпляры которых создаются на основе асимметричного ключа. Симметричный ключ может быть как постоянным (например, храниться в конфигурациионном файле приложения), так и случайным (если будет организован способ передачи параметров симметричного ключа от отправителя к получателю зашифрованных данных).
Я пробовал реализовать этот пример. Дело в том, что я отправляю открытый ключ в Контур, и они возвращают мне строку, которую я должен расшифровать с помощью закрытой части сертификата. Это выглядит вот так:
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.
В чём тут может быть проблема?
Вам нужно внимательней посмотреть на указанный пример.
Метод DecryptKeyExchangeAlgorithm()
делает дешифрацию общего секретного ключа, т.е. на вход он получает зашифрованный симметричный ключ. Как я понял, вы передаете ему не ключ, а зашифрованные данные. Для шифрации/дешифрации данных используется поток CryptoStream
.
Помимо зашифрованных данных вы должны как-то получить вектор инициализации и зашифрованный симметричный ключ. На основе ассиметричного алгоритма вы расшифруете симметричный ключ, а потом уже симметричным ключом расшифруете данные. Обычно это делается так.
Я просто подумал, что есть вариант как-то выдернуть часть реализации расшифровки сообщения. Если я правильно понимаю, то речь идёт о расшифровке сообщения, зашифрованного открытым ключом сертификата. А значит его можно расшифровать закрытым ключом сертификата. Подобно объекту RSACryptoServiceProvider, в котором есть методы .Encrypt(byte[]), .Decrypt(byte[]).
Да, действительно, RSA имеет методы Encrypt()
/Decrypt()
. Однако примечательно, что его нет среди методов базового класса AsymmetricAlgorithm
. Судя по коду RSACryptoServiceProvider
, внутри вызываются методы EncryptKey()
/DecryptKey()
, что наводит на мысль, что под данными подразумевается все-таки ключ (симметричного) шифрования, а не сами данные. Вам действительно не передают зашифрованный симметричный ключ, только зашифрованные данные? Если так, то я попробую изучить тему глубже, может что-то и получится. :)
@IverCold Если вопрос решен, предлагаю поделиться решением и закрыть задачу. :)
@AlexMAS Я лучше приложу инструкцию Контура, которую они мне дали. Нужно получить Access Token. Его можно получить по логину-паролю (как мы делаем сейчас), а можно по сертификату (так должно быть безопаснее). Чтобы получить токен по сертификату расшифровать случайный контент, который присылает Контур. Сам же инструкция вот здесь: https://developer.testkontur.ru/doc/openidconnect?about=2
@IverCold Если вопрос решен, предлагаю поделиться решением и закрыть задачу. :)
Ну, я не настолько хорош, чтобы предложить решение в рамках вашей библиотеки = ) Но невероятная благодарность от меня за её существование. Без неё мы бы просто не взлетели - мы используем реализацию raw подписи для Контура/СФР как раз.
Спасибо за обратную связь! :)
Понятно, то есть вам не удалось выполнить аутентификацию по сертификату. А можете прикрепить файл с base64 этого encrypted_key
, я попробую посмотреть ее через ASN.1-редактор. Может что-то прояснится, что они присылают в ответ. :)
@IverCold Здравствуйте! У вас нет примера encrypted_key
? :)
И снова здравствуйте! Я приношу извинения за пропажу на столь длительный срок. Но порой такова жизнь -_-
В прикреплённом архиве открытый сертификат, его 64base версия и то сообщение, которое нужно расшифровать и отправить обратно в Контур. Может быть есть какая-то возможность выделить методы Encrypt()/Decrypt() как в RSA, про что мы говорили выше.
Здравствуйте!
Я попробую повторить то, что есть в RSA.
В общем, выяснилось следующее.
Как я и предполагал, CryptoPro CSP поддерживает шифрование произвольных блоков данных только на симметричных ключах. Подозреваю, что и с VipNet CSP ситуация аналогична, но мне не удалось проверить - нет технической возможности. Кстати, недавно была добавлена поддержка алгоритмов Магма и Кузнечик. Возможно, шифрование вышеуказанных данных было с участием этих новых алгоритмов.
Любые попытки использовать асимметричные ключи CryptoPro CSP для шифрования приводят к ошибкам. Криптопровайдер явно говорит: Invalid algorithm specified
. Иначе говоря, повторить то, что умеет RSA, к сожалению, не получится.
Судя по тому, что мне удалось найти на форумах, есть какие-то серьезные сложности в реализации шифрования произвольных объемов данных с помощью асимметричных алгоритмов ГОСТ. Или сама философия шифрования по ГОСТ этого не предусматривает, не могу сказать. CryptoPro CSP поддерживает только подпись хэшей фиксированных размеров, то есть реализует только возможность цифровой подписи. Что же касается шифрования произвольных объемов данных, то в этом случае используются сессионные симметричные ключи. Алгоритм обмена примерно такой.
Отправляющая сторона:
- Удаленная сторона создает сессионный симметричный ключ.
- Шифрует данные сессионным ключом.
- С помощью публичного асимметричного ключа шифрует сессионный ключ.
- Отправляет получателю зашифрованный сессионный ключ и зашифрованные данные.
Получающая сторона:
- Получает зашифрованный сессионный ключ и зашифрованные данные.
- С помощью приватного асимметричного ключа расшифровывает сессионный ключ.
- Расшифровывает данные сессионным ключом.
Я посмотрел ваше зашифрованное base64-сообщение. Могу сказать, что это сообщение в каком-то странном и неизвестном мне формате. В бинарном представлении сообщение имеет странноватый размер - 970 байт. Это точно не ASN.1 формат. Самое интересное, что часть данных в этом сообщение представлена в открытом виде. Например, в явном виде представлен email сервиса сертификации.
По совокумности данных я бы сказал, что это какой-то кастомный формат сообщения, но это не точно. Возможно, какое-то подобие JWT, раз в контексте документации к сервису речь идет об OpenId Connect. Однако я пересмотрел документацию и не нашел описание формата этого зашифрованного сообщения.
Попробуйте связаться с разработчиками или еще с кем-то. Пусть они вам расскажут, как декодировать это сообщение. Сделав это, вы там должны обнаружить зашифрованные данные и зашифрованный симметричный ключ. А далее процесс расшифровки сделать просто. Я думаю, что как-то так должно быть.
@IverCold Дадите обратную связь, если что-то получится или не получится? ;)
@IverCold Дадите обратную связь, если что-то получится или не получится? ;)
Да, я как раз сегодня передал информацию нашему "связному" в Контуре. Может быть он сможет прояснить ситуацию. Большое спасибо за столь быстрый и развёрнутый ответ!
Возвращаюсь с результатом. Всё оказалось неожиданно просто. Хватило встроенного класса 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 - шифрование и дешифровка сообщения отработали. Интересно просто как это так? Он обращается к криптопровайдеру, определив алгоритм из сертификата?
Круто! Рад, что у вас всё получилось. Я тогда закрываю эту задачу. Если будут вопросы, обращайтесь.
Интересно просто как это так? Он обращается к криптопровайдеру, определив алгоритм из сертификата?
Тут как раз всё вышло так, как я и предполагал. Я почему-то не подумал про EnvelopedCms
, что сообщение передано в этом формате. Вызов метод EnvelopedCms.Decode()
декодирует сообщение, то есть десериализует его в объект, в котором есть: 1) зашифрованный сессионный ключ; 2) алгоритм шифрации сессионного ключа; 3) зашифрованные данные. А далее метод EnvelopedCms.Decrypt()
расшифровывает данные, используя эту информацию и указанный сертификат с приватным ключом. Фактически EnvelopedCms
инкапсулирует логику обмена, которую я описал выше.