AlexMAS / GostCryptography

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

Интеграция с ФСС #26

Closed AshurkovAV closed 5 years ago

AshurkovAV commented 5 years ago

Добрый день, подскажите есть пример шифрования запроса на сервис ФСС под ГОСТ 2012

AlexMAS commented 5 years ago

Здравствуйте. Лично у меня нет, но какие-то примеры были в Issues. Посмотрите, может что-то найдете.

AshurkovAV commented 5 years ago

Спасибо, за ответ. Пока не могу найти. Возможно нужно еще покопаться. Подскажите еще одни вопрос. Как явно установить . Т.к. у фсс на транспорте так и не изменен гост

AshurkovAV commented 5 years ago

Вопрос снят разобрался

AlexMAS commented 5 years ago

Здесь было обсуждение ФСС. Если вопрос решен, закройте задачу. ;)

alexnur commented 4 years ago

Добрый день. Не получается отправить зашифрованное подписанное сообщение в ФСС. Сертификат - ГОСТ-2012 256 бит. Отправить тестовое подписанное сообщение - получается. Тестовое зашифрованное - нет. При отправке из кода C# получаю 500 ошибку. Если отправлять через SoapUI, выдается:

ru.ibs.cryptoprto.jcp.wrapper.eln.ws.client.generated.CryptoException_Exception: Не удалось расшифровать сообщение. Возможно сообщение зашифровано на ключе отличном от ключа уполномоченного лица ФСС. Проверьте правильность и актуальность ключа уполномоченного лица ФСС.

Теперь пробую через GostCryptography с описанным тут примером. Подскажите, пожалуйста, что не так с шифрованием?

 public static XmlDocument EncryptionXML(XmlDocument document, X509Certificate2 cert)
        {
            document.PreserveWhitespace = true;
            XmlNode elementBody = document.GetElementsByTagName("Envelope", Vars.xmlns_soapenv)[0];
            // Создаем новый XML документ.
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
            ns.AddNamespace("soapenv", Vars.xmlns_soapenv);
            ns.AddNamespace("xenc", Vars.xmlns_xenc);
            ns.AddNamespace("ds", Vars.xmlns_ds);
            ns.AddNamespace("sch", Vars.xmlns_sch);
            ns.AddNamespace("wsse", Vars.xmlns_wsse);
            ns.AddNamespace("wsu", Vars.xmlns_wsu);
            MemoryStream newRequestStream = new MemoryStream();
            XmlWriter writer = XmlWriter.Create(newRequestStream, new XmlWriterSettings { Encoding = Encoding.UTF8 });
            writer.WriteStartDocument();
            // Envelope 
            writer.WriteStartElement("soapenv", "Envelope", Vars.xmlns_soapenv);
            //Header 
            writer.WriteStartElement("soapenv", "Header", Vars.xmlns_soapenv);
            writer.WriteEndElement(); // Header
            writer.WriteStartElement("soapenv", "Body", Vars.xmlns_soapenv); // Body
            // ************************************************************* EncryptedData ************************************************************************** /
            writer.WriteRaw(elementBody.OuterXml);
            // ******************************************************************************************************************************************************* /
            writer.WriteEndElement(); // Body
            writer.WriteEndElement(); // Envelope
            writer.WriteEndDocument();
            writer.Flush();
            string xmlText = Encoding.GetEncoding("UTF-8").GetString(newRequestStream.ToArray());
            XmlDocument xml = new XmlDocument();
            newRequestStream.Position = 0;
            xml.Load(newRequestStream);
            writer.Close();
            // Ищем заданный элемент для зашифрования. Envelope
            XmlElement elementToEncrypt = xml.GetElementsByTagName("Envelope", Vars.xmlns_soapenv)[1] as XmlElement;
            if (elementToEncrypt == null)
                throw new XmlException("Узел не найден");
            // Создаем объект EncryptedData и заполняем его необходимой информацией.
            EncryptedData elementEncryptedData = new EncryptedData();
            elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
            // Созданный элемент помечаем EncryptedElement1
            //elementEncryptedData.Id = "EncryptedElement1";
            elementEncryptedData.KeyInfo = new KeyInfo();
            // Созданный элемент помечаем EncryptedElement1
            // edElement.Id = "EncryptedElement1";
            using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm(ProviderType.CryptoPro_2012_512))
            {
                EncryptedXml encryptedXml = new EncryptedXml();
                // Шифрация элемента с использованием симметричного ключа
                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.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
                encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(cert));
                // Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
                elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
                // Установка зашифрованных данных у объекта EncryptedData
                elementEncryptedData.CipherData.CipherValue = encryptedElement;
            }

            // Заменяем исходный узел на зашифрованный.
            EncryptedXml.ReplaceElement(elementToEncrypt, elementEncryptedData, false);

            return xml;
        }
AshurkovAV commented 4 years ago

Добрый день. Не получается отправить зашифрованное подписанное сообщение в ФСС.

Отравил вам на почту пример шифрования

alexnur commented 4 years ago

Алексей, здравствуйте! В этом письме нет приложенного файла. Отправьте, пожалуйста, еще раз. Заранее спасибо!

 

Воскресенье, 3 ноября 2019, 0:42 +05:00 от AshurkovAV notifications@github.com:   Добрый день. Не получается отправить зашифрованное подписанное сообщение в ФСС. Отравил вам на почту пример шифрования — You are receiving this because you commented. Reply to this email directly, view it on GitHub , or unsubscribe .    

Александр D.  

AshurkovAV commented 4 years ago
 private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, Gost_28147_89_SymmetricAlgorithmBase sharedKey, 
            X509Certificate2 certificateEncryption,
            X509Certificate2 certificateOpen)
        {
            // Ищем заданный элемент для заширования. Envelope
            XmlElement elementToEncrypt = xmlDocument.GetElementsByTagName("Envelope", Constants.xmlns_soapenv)[1] as XmlElement;
            // Создаем объект EncryptedData и заполняем его необходимой информацией.
            EncryptedData edElement = new EncryptedData();
            edElement.Type = EncryptedXml.XmlEncElementUrl;
            // Созданный элемент помечаем EncryptedElement1
            //edElement.Id = "EncryptedElement1";
            // Заполняем алгоритм зашифрования данных.  Он будет использован при расшифровании.
            edElement.EncryptionMethod = new EncryptionMethod(Gost_28147_89_SymmetricAlgorithm.AlgorithmNameValue);

            // Создаем новую ссылку на ключ.
            edElement.KeyInfo = new KeyInfo();
            // Создаем случайный симметричный ключ.
            // В целях безопасности удаляем ключ из памяти после использования.

            using (Gost_28147_89_SymmetricAlgorithm sessionKey = new Gost_28147_89_SymmetricAlgorithm(sharedKey.ProviderType))
            {
                //При генерации сессионного ключа 28147 всегда используется 2001 провайдер(TypeId = 75).
                //Соответственно параметры CIPHER_OID ключа всегда берутся для указанного провайдера.
                //И если при шифровании ключа используется новый сертификат ФСС(уполномоченного лица) с
                //2012 ключом получается нехорошо:
                //                -(.
                //В обернутом ключе параметры алгоритма прописываются
                //1.2.643.2.2.31.1
                //когда как ФСС ожидает
                //1.2.643.7.1.2.5.1.1
                // Создаем объект класса EncryptedXml

                EncryptedXml eXml = new EncryptedXml();
                // Зашифроваем узел на симметричном ключе.
                byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
                // Зашифровываем сессионный ключ и добавляем эти зашифрованные данные к узлу EncryptedKey.
                EncryptedKey ek = new EncryptedKey();

                byte[] encryptedKey = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificateEncryption.GetPublicKeyAlgorithm());
                ek.CipherData = new CipherData(encryptedKey);
                ek.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001");

                KeyInfoX509Data data = new KeyInfoX509Data(certificateOpen);
                ek.KeyInfo.AddClause(data);
                // Добавляем ссылку на зашифрованный ключ к зашифрованным данным.
                edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
                // Добавляем зашифрованные данные к объекту EncryptedData.
                edElement.CipherData.CipherValue = encryptedElement;
            }

            // Заменяем исходный узел на зашифрованный.
            EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

            return xmlDocument;
        }
AshurkovAV commented 4 years ago
 /// <summary>
        /// Расшифровываем полученные данные от ФСС
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        public string DecryptXmlDocument(string document)
        {
            // Создаем объект XmlDocument.
            XmlDocument xmlDoc = new XmlDocument();

            // Загружаем XML файл в объект XmlDocument.
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.LoadXml(document);

            // Ищем все зашифрованные данные.
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
            nsmgr.AddNamespace("enc", "http://www.w3.org/2001/04/xmlenc#");
            XmlNodeList list = xmlDoc.SelectNodes("//enc:EncryptedData", nsmgr);

            // Создаем объект EncryptedXml.
            GostEncryptedXml exml = new GostEncryptedXml(xmlDoc);

            if (list != null)
            {
                // Для всех зашифрованных данных.
                foreach (XmlNode node in list)
                {
                    XmlElement element = node as XmlElement;
                    EncryptedData encryptedData = new EncryptedData();
                    encryptedData.LoadXml(element);

                    // Находим подходящий ключ для расшифрования.
                    SymmetricAlgorithm decryptionKey = GetDecryptionKeyVipNet(encryptedData);
                    if (decryptionKey == null)
                    {
                        throw new Exception("Ключ для расшифрования сообщения не найден.");
                    }

                    // И на нем расшифровываем данные.
                    byte[] decryptedData = exml.DecryptData(encryptedData, decryptionKey);
                    exml.ReplaceData(element, decryptedData);
                }
            }
            return xmlDoc.OuterXml;
        }

        private static SymmetricAlgorithm GetDecryptionKeyVipNet(EncryptedData encryptedData)
        {
            IEnumerator encryptedKeyEnumerator = encryptedData.KeyInfo.GetEnumerator();
            // Проходим по всем KeyInfo
            while (encryptedKeyEnumerator.MoveNext())
            {
                // пропускам все что неизвестно.
                KeyInfoEncryptedKey current = encryptedKeyEnumerator.Current as KeyInfoEncryptedKey;
                if (current == null) continue;
                // до первого EncryptedKey
                EncryptedKey encryptedKey = current.EncryptedKey;
                if (encryptedKey == null)
                    continue;
                KeyInfo keyinfo = encryptedKey.KeyInfo;
                // Проходим по всем KeyInfo зашифрования ключа.
                IEnumerator srcKeyEnumerator = keyinfo.GetEnumerator();
                while (srcKeyEnumerator.MoveNext())
                {
                    // пропускам все что неизвестно.
                    KeyInfoX509Data keyInfoCert = srcKeyEnumerator.Current
                        as KeyInfoX509Data;
                    if (keyInfoCert == null)
                        continue;
                    var keyContainer = Constants.CertificateMo.GetPrivateKeyInfo();
                    // Приватный ключ, открытый ключ которого мы отправляли при шифровании запроса
                    var privateKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(keyContainer);
                    // Приватный ключ, открытый ключ которого мы отправляли при шифровании запроса
                    Gost_R3410_2012_256_AsymmetricAlgorithm myKey = privateKey as Gost_R3410_2012_256_AsymmetricAlgorithm;
                    if (myKey == null)
                        continue;
                    return GostEncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, myKey);
                }
            }
            return null;
        }

Это расшифровка

alexnur commented 4 years ago

Спасибо! Мир не без добрых людей. Неделю мучаюсь. Во вторник попробую отправить в ФСС. sharedKey — это откуда можно взять? certificateEncryption — это личный сертификат? certificateOpen — это сертификат уполномоченного ФСС?

Воскресенье, 3 ноября 2019, 0:55 +05:00 от AshurkovAV notifications@github.com:   private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, Gost_28147_89_SymmetricAlgorithmBase sharedKey, X509Certificate2 certificateEncryption, X509Certificate2 certificateOpen) { // Ищем заданный элемент для заширования. Envelope XmlElement elementToEncrypt = xmlDocument.GetElementsByTagName("Envelope", Constants.xmlns_soapenv)[1] as XmlElement; // Создаем объект EncryptedData и заполняем его необходимой информацией. EncryptedData edElement = new EncryptedData(); edElement.Type = EncryptedXml.XmlEncElementUrl; // Созданный элемент помечаем EncryptedElement1 //edElement.Id = "EncryptedElement1"; // Заполняем алгоритм зашифрования данных. Он будет использован при расшифровании. edElement.EncryptionMethod = new EncryptionMethod(Gost_28147_89_SymmetricAlgorithm.AlgorithmNameValue);

       // Создаем новую ссылку на ключ.
       edElement.KeyInfo = new KeyInfo();
       // Создаем случайный симметричный ключ.
       // В целях безопасности удаляем ключ из памяти после использования.

       using (Gost_28147_89_SymmetricAlgorithm sessionKey = new Gost_28147_89_SymmetricAlgorithm(sharedKey.ProviderType))
       {
           //При генерации сессионного ключа 28147 всегда используется 2001 провайдер(TypeId = 75).
           //Соответственно параметры CIPHER_OID ключа всегда берутся для указанного провайдера.
           //И если при шифровании ключа используется новый сертификат ФСС(уполномоченного лица) с
           //2012 ключом получается нехорошо:
           //                -(.
           //В обернутом ключе параметры алгоритма прописываются
           //1.2.643.2.2.31.1
           //когда как ФСС ожидает
           //1.2.643.7.1.2.5.1.1
           // Создаем объект класса EncryptedXml

           EncryptedXml eXml = new EncryptedXml();
           // Зашифроваем узел на симметричном ключе.
           byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
           // Зашифровываем сессионный ключ и добавляем эти зашифрованные данные к узлу EncryptedKey.
           EncryptedKey ek = new EncryptedKey();

           byte[] encryptedKey = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificateEncryption.GetPublicKeyAlgorithm());
           ek.CipherData = new CipherData(encryptedKey);
           ek.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostNamespaceUrl + "transport-gost2001");

           KeyInfoX509Data data = new KeyInfoX509Data(certificateOpen);
           ek.KeyInfo.AddClause(data);
           // Добавляем ссылку на зашифрованный ключ к зашифрованным данным.
           edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
           // Добавляем зашифрованные данные к объекту EncryptedData.
           edElement.CipherData.CipherValue = encryptedElement;
       }

       // Заменяем исходный узел на зашифрованный.
       EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

       return xmlDocument;
   }

— You are receiving this because you commented. Reply to this email directly, view it on GitHub , or unsubscribe .    

Александр D.  

AshurkovAV commented 4 years ago

ProviderType providerType = ProviderType.VipNet; var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType); X509Certificate2 certificateEncryption, - сертификат фсс X509Certificate2 certificateOpen - сертификат медицинской организации

alexnur commented 4 years ago

Спасибо!

 

Воскресенье, 3 ноября 2019, 22:11 +05:00 от AshurkovAV notifications@github.com:   ProviderType providerType = ProviderType.VipNet; var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType); X509Certificate2 certificateEncryption, - сертификат фсс X509Certificate2 certificateOpen - сертификат медицинской организации — You are receiving this because you commented. Reply to this email directly, view it on GitHub , or unsubscribe .    

Александр D.  

das511 commented 4 years ago

Добрый день. Не получается отправить зашифрованное подписанное сообщение в ФСС.

Отравил вам на почту пример шифрования Добрый день, можно мне тоже отправить пример ?

Slobodskoy commented 3 years ago

Gost_28147_89_SymmetricAlgorithm

Я не нашел отличий в вашем коде и @alexnur
В чем фишка? У меня таже проблема с сертификатом фсс 2012 Можно код в почту?

AshurkovAV commented 3 years ago

Gost_28147_89_SymmetricAlgorithm

Я не нашел отличий в вашем коде и @alexnur В чем фишка? У меня таже проблема с сертификатом фсс 2012 Можно код в почту?

Добрый день, данную тему хорошо осветили в новой ветке

AshurkovAV commented 3 years ago

https://github.com/AlexMAS/GostCryptography/issues/39

Gost_28147_89_SymmetricAlgorithm

Я не нашел отличий в вашем коде и @alexnur В чем фишка? У меня таже проблема с сертификатом фсс 2012 Можно код в почту?

https://github.com/AlexMAS/GostCryptography/issues/39