Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline po_saa  
#1 Оставлено : 26 января 2018 г. 13:28:43(UTC)
po_saa

Статус: Активный участник

Группы: Участники
Зарегистрирован: 20.08.2015(UTC)
Сообщений: 90
Российская Федерация
Откуда: Москва

Сказал(а) «Спасибо»: 6 раз
Подскажите пожалуйста

Не отрабатывает CryptMsgUpdate - возвращает пустой Result
Перерыл уже весь MSDN - вроде бы (!) всё верно, но не работает
Код:
        // File stream to use in callback function
        private FileStream m_callbackFile;

        // Streaming callback function for encoding
        private Boolean StreamOutputCallback(IntPtr pvArg, IntPtr pbData, uint cbData, Boolean fFinal)
        {
            // Write all bytes to encoded file
            Byte[] bytes = new Byte[cbData];
            Marshal.Copy(pbData, bytes, 0, (int)cbData);
            m_callbackFile.Write(bytes, 0, (int)cbData);

            if (fFinal)
            {
                // This is the last piece. Close the file
                m_callbackFile.Flush();
                m_callbackFile.Close();
                m_callbackFile = null;
            }

            return true;
        }

        // Кодирование CMS больших файлов
        public void Encode(X509Certificate2Collection certsCollection, FileStream inFile, FileStream outFile)
        {
            // Variables
            Win32.CMSG_ENVELOPED_ENCODE_INFO EnvelopedEncodeInfo;
            Win32.CMSG_STREAM_INFO StreamInfo;
            Win32.CERT_CONTEXT[] CertContexts = null;

            IntPtr CertInfoPtr = IntPtr.Zero;       //указатель на массив Win32.CERT_INFO для EnvelopedEncodeInfo.rgpRecipients
            IntPtr CertInfoArraysPtr = IntPtr.Zero;  //указатель на массив структур CERT_INFO
            IntPtr CertInfoPointersPtr = IntPtr.Zero;  //указатель на массив указателей структур CERT_INFO

            Win32.BLOB[] CertBlobs;
            IntPtr[] CertInfoPointersArray = null;  //массив указателей на структуры CERT_INFO

            Win32.CERT_INFO[] certInfoStructuresArray = null;

            Gost3410CryptoServiceProvider GHOSTkey = null;  //криптосервис провайдер

            BinaryReader stream = null;
            GCHandle gchandle = new GCHandle();

            IntPtr hProv = IntPtr.Zero;
            IntPtr SignerInfoPtr = IntPtr.Zero;
            IntPtr EnvelopedEncodeInfoPtr = IntPtr.Zero;

            IntPtr CertBlobsPtr = IntPtr.Zero;
            IntPtr hMsg = IntPtr.Zero;
            IntPtr pbPtr = IntPtr.Zero;

            Byte[] pbData;
            int dwFileSize;
            int dwRemaining;
            int dwSize;
            Boolean bResult = false;

            try
            {
                // получить данные для кодирования
                dwFileSize = (int)inFile.Length;
                stream = new BinaryReader(inFile);  //поток исходных данных
                pbData = stream.ReadBytes(dwFileSize);

                m_callbackFile = outFile;       //поток для закодированной инфо

                // Получить контекст всех сертификатов в цепочке
                // Получаем Win32 контексты сертификатов
                CertContexts = new Win32.CERT_CONTEXT[certsCollection.Count];
                // Массив сертификатов в виде байтов 
                CertBlobs = new Win32.BLOB[CertContexts.Length];

                CertInfoPointersArray = new IntPtr[CertContexts.Length];            //массив указателей на структуры CERT_INFO
                certInfoStructuresArray = new Win32.CERT_INFO[CertContexts.Length];   //иассив структур CERT_INFO

                int certCounter = 0;
                foreach (var cert in certsCollection)
                {
                    CertContexts[certCounter] = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(cert.Handle, typeof(Win32.CERT_CONTEXT));
                    //CertBlobs[certCounter].cbData = CertContexts[certCounter].cbCertEncoded;
                    //CertBlobs[certCounter].pbData = CertContexts[certCounter].pbCertEncoded;
                    CertInfoPointersArray[certCounter] = CertContexts[certCounter].pCertInfo;
                    certInfoStructuresArray[certCounter] = (Win32.CERT_INFO)Marshal.PtrToStructure(CertContexts[certCounter].pCertInfo, typeof(Win32.CERT_INFO));
                    certCounter++;
                }

                // Получить провайдер для сертификата (Get CSP of client certificate)
                GHOSTkey = (Gost3410CryptoServiceProvider)certsCollection[0].PrivateKey;

                bResult = Win32.CryptAcquireContext(
                    ref hProv,
                    GHOSTkey.CspKeyContainerInfo.KeyContainerName,
                    GHOSTkey.CspKeyContainerInfo.ProviderName,
                    GHOSTkey.CspKeyContainerInfo.ProviderType,
                    0
                );

                if (!bResult)
                {
                    throw new Exception("CryptAcquireContext error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Заполнить структуру CMSG_ENVELOPED_ENCODE_INFO
                EnvelopedEncodeInfo = new Win32.CMSG_ENVELOPED_ENCODE_INFO();
                EnvelopedEncodeInfo.cbSize = (uint)Marshal.SizeOf(EnvelopedEncodeInfo);
                EnvelopedEncodeInfo.hCryptProv = hProv;
                EnvelopedEncodeInfo.ContentEncryptionAlgorithm.pszObjId = Win32.szOID_CP_GOST_GOST89;

                //EnvelopedEncodeInfo.cRecipients = (uint)CertBlobs.Length;  //это количество сертификатов. Если открыть, почему-то не отрабатывает CryptMsgOpenToEncode

                //Если rgpRecipients не NULL, rgCmsRecipients должен быть NULL.
                //CertInfoArraysPtr = Marshal.AllocHGlobal(
                //    Marshal.SizeOf(certInfoStructuresArray[0]) * CertBlobs.Length);   //указатель на массив структур CERT_INFO
                CertInfoPointersPtr = Marshal.AllocHGlobal(
                    Marshal.SizeOf(CertInfoPointersArray[0]) * CertBlobs.Length);   //указатель на массив указателей структур CERT_INFO
                EnvelopedEncodeInfo.rgpRecipients = CertInfoPointersPtr;


                //распределяем память под структуру - ПОСЛЕ ЗАПОЛНЕНИЯ СТРУКТУРЫ
                EnvelopedEncodeInfoPtr = Marshal.AllocHGlobal(
                    Marshal.SizeOf(EnvelopedEncodeInfo));
                Marshal.StructureToPtr(EnvelopedEncodeInfo, EnvelopedEncodeInfoPtr, false);
                

                // Заполняем структуру StreamInfo
                StreamInfo = new Win32.CMSG_STREAM_INFO(
                    (uint)dwFileSize,
                    new Win32.PFN_CMSG_STREAM_OUTPUT(StreamOutputCallback), 
                    IntPtr.Zero
                    );

                if (dwFileSize > Int32.MaxValue)
                    StreamInfo.cbContent = (uint)0xffffffff; // Basic Encoding Rules (BER)
                else
                    StreamInfo.cbContent = (uint)dwFileSize; // Используем Distinguished Encoding Rules (DER)   ASN1

                //определяем функцию записи
                //Функция Обратного вызова для потоковой кодировки вызывает CryptMsgUpdate для кодирования упаковываемого сообщения.
                //Обратный вызов для упаковываемого сообщения принимает закодированные байты вложенного подписанного сообщения.
                //StreamInfo.pfnStreamOutput = new
                //    Win32.PFN_CMSG_STREAM_OUTPUT(StreamOutputCallback);

                // Открываем сообщение для кодирования
                //см. https://www.cryptopro.ru/forum2/default.aspx?g=posts&t=6714

                hMsg = Win32.CryptMsgOpenToEncode(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    0,
                    Win32.CMSG_ENVELOPED,
                    ref EnvelopedEncodeInfo,
                    null,
                    ref StreamInfo
                );

                if (hMsg.Equals(IntPtr.Zero))
                {
                    throw new Exception("CryptMsgOpenToEncode error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // обработать всё сообщение
                gchandle = GCHandle.Alloc(pbData, GCHandleType.Pinned);
                pbPtr = gchandle.AddrOfPinnedObject();
                dwRemaining = dwFileSize;
                dwSize = (dwFileSize < 1024 * 1000 * 100) ? dwFileSize : 1024 * 1000 * 100;
                while (dwRemaining > 0)
                {
                    // дополнить сообщение по частям
                    bResult = Win32.CryptMsgUpdate(
                        hMsg,
                        pbPtr,
                        dwSize,
                        (dwRemaining <= dwSize)
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptMsgUpdate error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }

                    // Перейти к следующему куску
                    pbPtr = new IntPtr(pbPtr.ToInt64() + dwSize);
                    dwRemaining -= dwSize;
                    if (dwRemaining < dwSize)
                    {
                        dwSize = dwRemaining;
                    }
                }
            }
            finally
            {
                // очистка
                if (gchandle.IsAllocated)
                {
                    gchandle.Free();
                }
                if (stream != null)
                {
                    stream.Close();     //поток исходных данных
                }
                if (m_callbackFile != null)
                {
                    m_callbackFile.Close();     //поток зашифрованных данных
                }

                if (!CertInfoArraysPtr.Equals(IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(CertInfoArraysPtr);
                }
                if (!SignerInfoPtr.Equals(IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(SignerInfoPtr);
                }

                if (!hProv.Equals(IntPtr.Zero))
                {
                    Win32.CryptReleaseContext(hProv, 0);
                }
                if (!hMsg.Equals(IntPtr.Zero))
                {
                    Win32.CryptMsgClose(hMsg);
                }
            }
        }
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.