Автор: maxdm Постараюсь посмотреть на днях.
Прикрепите то, что получилось (не получилось) у вас.
не отрабатывает запись - возвращает почему-то Result == 0
// 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;
EncryptDecryptStream1.zip
(274kb) загружен 2 раз(а).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....aspx?g=posts&t=6714hMsg = 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);
}
}
}
EncryptDecryptStream1.zip
(274kb) загружен 4 раз(а).