AlexMAS / GostCryptography

.NET driver for ViPNet CSP and CryptoPro CSP
MIT License
132 stars 42 forks source link

2.0.2 + ГОСТ-2001 #12

Closed bor2001 closed 5 years ago

bor2001 commented 5 years ago

здравствуйте, Александр! очень благодарен вам за такую библиотеку, особенно за примеры кода к ней! мой проект - реализация взаимодействия с ФСС по ЭЛН со стороны медицинских организаций. (https://cabinets-test.fss.ru/eln.html) у меня появились трудности её применения при переходе на новый ГОСТ и новую версию вашей разработки.

  1. При шифровании запроса публичным ключом уполномоченного лица ФСС ГОСТ2012 - в ответ приходит ошибка о невозможности расшифровать. При использовании для шифрования сертификата уполн.лица фсс с ГОСТ2001 - проходит нормально. Этот вопрос ещё задам в ФСС.
  2. При использовании для формирования подписи (врача или МО) сертификата ГОСТ2001 - на вызове GostCryptography.Xml.GostSignedXmlImpl.ComputeSignatureGost() получаю ошибку "System.Security.Cryptography.CryptographicException: Ошибка исполнения функции.".2parse_2019-01-30T07-24-37--5796.log Если использовать ГОСТ2012 - подпись формируется и при отправке принимается сервисом.
bor2001 commented 5 years ago

с версией вашей библиотеки 1,0,1 и использовании сертификатов с ГОСТ2001 всё работало год. я в коде динамически вычисляю алгоритмы из выбранного сертификата по вашим примерам. хочется доделать одну программу для работы с гостами обоих типов)) поможете советом? или таки ошибка найдётся ваша?

AlexMAS commented 5 years ago

Здрарвствуйте. Спасибо за отзыв. :) Постараюсь посмотреть в ближайшее время. Можете приложить пример кода, который не работает, т.к. все мои unit-тесты проходят успешно со всеми версиями сертификатов.

AlexMAS commented 5 years ago

Проверил еще раз, вот эти конфигурации должны работать:

capture

Единственный момент - не смог проверить работоспособность функционала на сертификатах 2001 года на базе ViPNet, т.к. тестовый центр сертификации ViPNet уже отказывается выдавать такие сертификаты. Но на базе CryptoPro все работает.

Поэтому жду от вас примера с воспроизведением ошибки и описание окружения (ОС, CSP, версии).

Uriel6575 commented 5 years ago

Коллега по несчастью. Тоже ФСС и тоже ЭЛН. :) Они, кстати, сами используют GostCryptography в официальной софтине для обмена электронными больничными. Из Javа. Засунув туда COM-компонент. Но это уже другая тема. Так вот, подсмотрел, что они там делают и таки удалось отправить запрос, зашифрованный на их сертификат по 2012-ым ГОСТам. А всего лишь надо вместо корректного названия алгоритма "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2012-256" положить название от старого "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001" в EncryptionMethod EncryptedKey. Как это сделать чисто на API библиотеки - не скажу. Мы всю обвязку генерируем руками, используя библиотеку только для получения зашифрованных данных и зашифрованного ключа.

rdn1969 commented 5 years ago

Всем привет! Проблема та же: при использовании сертификатов ГОСТ 34.10-2012 при отправке запроса в ФСС на получение ЭЛН получаю сообщение: "<?xml version='1.0' encoding='UTF-8'?>S:Serverru.ibs.cryptoprto.jcp.wrapper.eln.ws.client.generated.CryptoException_Exception: Не удалось расшифровать сообщение. Возможно сообщение зашифровано на ключе отличном от ключа уполномоченного лица ФСС. Проверьте правильность и актуальность ключа уполномоченного лица ФСС.</S:Fault></S:Body></S:Envelope>". У меня 64-разрядная Windows10, установлена Крипто Про версии 4.0.9963. Для подписания, шифрования и расшифровывания сообщений использую GostCryptography 2.0.2. Установлены сертификаты, поддерживающие ГОСТ 34.10-2012. Сертификаты проверены на АРМ ФСС - там все работает. После анализа кода был выявлен участок, предположительно приводящий к ошибке (здесь certificate - сертификат ФСС):

                using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm())
                {
                    elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);

                    // Шифрация элемента с использованием симметричного ключа
                    var encryptedElement = encryptedXml.EncryptData(element, sessionKey, false);

                    foreach (var certificate in certificates)
                    {
                        // Шифрация сессионного ключа с использованием открытого ключа сертификата
                        var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm());

                        // Формирование информации о зашифрованном сессионном ключе
                        var encryptedSessionKey = new EncryptedKey();
                        encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
                        encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl);
                        encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
                        encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(certificate));

                        // Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
                        elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
                    }

                    // Установка зашифрованных данных у объекта EncryptedData
                    elementEncryptedData.CipherData.CipherValue = encryptedElement;
                }

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

AlexMAS commented 5 years ago

@Uriel6575 Спасибо за информацию.

А всего лишь надо вместо корректного названия алгоритма "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2012-256" положить название от старого "urn:ietf:params:xml:ns:cpxmlsec:algorithms:transport-gost2001" в EncryptionMethod EncryptedKey.

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

Как это сделать чисто на API библиотеки - не скажу.

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

В примерах/тестах много мест, где производится установка этого параметра, например, тут. (Незнаю, правда, насколько приведенный пример подходит к данному контексту.)

На крайний вариант, да, можно сформировать XML вручную, или скорректировать полученный результат, но зачем, если есть стандартное API для этого. (Возможно, я что-то не до конца понял.)

После анализа кода был выявлен участок, предположительно приводящий к ошибке

@rdn1969 Я думаю, что проблема все та же, подозреваю, что тут:

encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl);

они ждут какой-то другой идентификатор, возможно, тот, который указал @Uriel6575 выше.

a13xg0 commented 5 years ago

Я так понимаю, что здесь идёт перепись разработчиков программ для ЭЛН :) Я тоже отмечусь :) @rdn1969 нужно просто подставить ожидаемые имена алгоритмолв, дальше всё будет работать :

elementEncryptedData.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "gost28147");

и

encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001");
AlexMAS commented 5 years ago

@a13xg0 Спасибо.

Могу только добавить, что вместо выражения:

GostEncryptedXml.XmlEncGostNamespaceUrl + "gost28147"

можно использовать вот эту константу:

Gost_28147_89_SymmetricAlgorithm.AlgorithmNameValue

а вместо выражения:

GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001"

вот эту:

Gost_R3410_2001_AsymmetricAlgorithm.KeyExchangeAlgorithmValue

@bor2001 Есть вопрос исчерпан, предлагаю закрыть задачу.

rdn1969 commented 5 years ago

@a13xg0 Подставил имена алгоритмов, как вы советовали - не помогло.((( Ошибка та же. Какой вы используете сертификат при шифровании? У меня ошибка возникает при использовании ГОСТ 34.10.2012. На ГОСТ 34.10-2001 все работает.

a13xg0 commented 5 years ago

@rdn1969

using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm(providerType))
            {
                // Шифрация элемента с использованием симметричного ключа
                var encryptedElement = encryptedXml.EncryptData(elementToEncrypt, sessionKey, false);

                // Шифрация сессионного ключа с использованием открытого ключа сертификата
                var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)Cert.GetPublicKeyAlgorithm());

                // Формирование информации о зашифрованном сессионном ключе
                var encryptedSessionKey = new EncryptedKey();
                encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
                encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001");
                //encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl);
                encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });

                encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(GetDecryptCertificate()));

                // Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
                elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));

                // Установка зашифрованных данных у объекта EncryptedData
                elementEncryptedData.CipherData.CipherValue = encryptedElement;
            }

Для нашего случая

providerType = ProviderType.CryptoPro_2012_512;
rdn1969 commented 5 years ago

@rdn1969 Спасибо!!! Заработало.

bor2001 commented 5 years ago

спасибо, всем, коллеги, за такую живую реакцию! по моим начальным вопросам :

  1. по сертификату лица фсс: буду использовать шифрование гост 2001 пока не поправят сервис, свои доработки не хочу подгонять под чужую криворукость, своей достаточно.
  2. по подписи 2,0,2+гост2001: проверил случайно на вин10 - работает!!!!!!! а на 7/8 (проверял только на одной, щ нет туда доступа) - нет!!!!!! ошибка криптопро.
bor2001 commented 5 years ago

хотя, с версией библиотеки 1.0.1 - подписание работает по гост2001 на криптопро 3.9...

AlexMAS commented 5 years ago

хотя, с версией библиотеки 1.0.1 - подписание работает по гост2001 на криптопро 3.9...

Здравствуйте, @bor2001. Спасибо за информацию. Версия v2 не тестировалась на CryptoPro v3.9, т.к. по большей части нацелена на поддержку стандартов 2012 года, а CryptoPro до версии 4.0.9963 содержит критические для этого ошибки. Если функционирование на CryptoPro v3.9 важно для вас, пожалуйста, заведите отдельную задачу, я постораюсь воспроизвести ситуацию. Также приложите полный stack trace исключения и описание того, что вы пытаетесь сделать.