Добрый день!
Прошу Вашего совета в вопросе использования CRYPTO API из среды C#. Применение Шарпея невозможно по причине необходимости использования кода проекта в среде mono Linux. Причем проблемы возникают только с отдельными функциями. Такими как:
1.CryptMsgOpenToEncode (работает через раз, то ошибка - Access Violation с00005, то чисто)
2. и последующий вызов CryptMsgUpdate постоянно
Привожу фрагмент:
CMSG_SIGNER_ENCODE_INFO SingerEncodeInfo = new CMSG_SIGNER_ENCODE_INFO();
SingerEncodeInfo.pCertInfo = CertContext.pCertInfo;
SingerEncodeInfo.hCryptProv = hCryptProv;
SingerEncodeInfo.dwKeySpec = AT_KEYEXCHANGE;
SingerEncodeInfo.HashAlgorithm = HashAlgoritm;
SingerEncodeInfo.pvHashAuxInfo = IntPtr.Zero;
SingerEncodeInfo.cbSize = Convert.ToUInt32(System.Runtime.InteropServices.Marshal.SizeOf(SingerEncodeInfo));
CMSG_SIGNER_ENCODE_INFO[] SingerEncodeInfoArray = new CMSG_SIGNER_ENCODE_INFO[1];
SingerEncodeInfoArray[0] = SingerEncodeInfo;
CERT_BLOB SingerSertBlob = new CERT_BLOB();
SingerSertBlob.cbData = CertContext.cbCertEncoded;
SingerSertBlob.pbData = CertContext.pbCertEncoded;
CERT_BLOB[] SingerSertBlobArray = new CERT_BLOB[1];
SingerSertBlobArray[0] = SingerSertBlob;
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo = new CMSG_SIGNED_ENCODE_INFO();
SignedMsgEncodeInfo.cbSize = Convert.ToUInt32(System.Runtime.InteropServices.Marshal.SizeOf(SignedMsgEncodeInfo));
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = Marshal.AllocHGlobal(sizeof(ulong));
Marshal.StructureToPtr(SingerEncodeInfoArray[0], SignedMsgEncodeInfo.rgSigners, true);
SignedMsgEncodeInfo.cCertEncoded = 0;
SignedMsgEncodeInfo.rgCertEncoded = IntPtr.Zero;
SignedMsgEncodeInfo.rgCrlEncoded = IntPtr.Zero;
uint flags=0;
rgSigners = Marshal.AllocHGlobal(sizeof(long));
Marshal.StructureToPtr(SignedMsgEncodeInfo, rgSigners, false);
uint cbEncodedBlob=CryptMsgCalculateEncodedLength(TYPE_DER, flags, CMSG_SIGNED, rgSigners, "", cbContent);
Console.WriteLine("Длина ЭЦП рассчитана- {0}", cbEncodedBlob);
byte[] pbEncodedBlob = new byte[cbEncodedBlob];
Console.WriteLine("Hmsg do-" + Win32Error.ErrorMessage(Marshal.GetLastWin32Error()));
hMsg = Marshal.AllocHGlobal(sizeof(ulong));
hMsg = CryptMsgOpenToEncode(TYPE_DER,0, CMSG_SIGNED, rgSigners, null, IntPtr.Zero);
Console.WriteLine("Результат CryptMsgOpenToEncode-" + Win32Error.ErrorMessage(Marshal.GetLastWin32Error()));
Console.WriteLine("hMsg-" + hMsg);
cbEncodedBlob = 0;
;
// Получаем длину буфера подписи
pbContentArray = new byte[pbContent.Length];
for (int kk = 0; kk <= pbContent.Length - 1; kk++)
pbContentArray[kk] = (byte)(pbContent[kk]);
unsafe
{
fixed (byte* ptrContentArray = &pbContentArray[0])
{
if //(CryptMsgUpdate(hMsg, pbContentArray, pbContentArray.Length, true))
(CryptMsgUpdate(hMsg, ptrContentArray, 4, true))
{
Console.WriteLine("MsgUpdate-TRUE");
}
else
{
int ik = Marshal.GetLastWin32Error();
//uint error_msg=Convert.ToUInt32( ik);
Console.WriteLine(" CryptMsgUpdate-FALSE- {0}" + Win32Error.ErrorMessage(Convert.ToInt32(ik)), ik);
uint ii = (uint)ik;
switch (ii)
{
case CRYPT_E_INVALID_MSG_TYPE: Console.WriteLine("The message type is not valid."); break;
case CRYPT_E_MSG_ERROR: Console.WriteLine("An error was encountered doing a cryptographic operation."); break;
case CRYPT_E_OID_FORMAT: Console.WriteLine("The object identifier is badly formatted."); break;
case CRYPT_E_UNEXPECTED_ENCODING: Console.WriteLine(" The message is not encoded as expected."); break;
case CRYPT_E_UNKNOWN_ALGO: Console.WriteLine(" The cryptographic algorithm is unknown."); break;
case E_INVALIDARG: Console.WriteLine(" One or more arguments are not valid."); break;
case E_OUTOFMEMORY: Console.WriteLine("Ran out of memory"); break;
case 0xC0000005: Console.WriteLine("Access violation error"); break;
//default: Console.WriteLine("MsgUpdate-FALSE- {0}" + Win32Error.ErrorMessage(Convert.ToInt32(error_msg)), error_msg);
}
}
}
}
uint cbEncodedBlob1 = 0;
if (CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, null, ref cbEncodedBlob1))
{
Console.WriteLine("MsgGetParam-True. cbEncodedBlob={0}", cbEncodedBlob1);
}
else Console.WriteLine("Error CryptMsgGetParam Len- {0}" + Win32Error.ErrorMessage(Marshal.GetLastWin32Error()), Marshal.GetLastWin32Error());
pbEncodedBlob = new byte[cbEncodedBlob];
if (CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pbEncodedBlob, ref cbEncodedBlob))
{
Console.WriteLine("MsgGetParam-true");
}
else Console.WriteLine("Error CryptMsgGetParam- {0}" + Win32Error.ErrorMessage(Marshal.GetLastWin32Error()), Marshal.GetLastWin32Error());
Описание функций:
#if OS
[DllImport("crypt32.dll", SetLastError = true)]
#else
[DllImport("/opt/cprocsp/lib/ia32/libcapilite.so")]
#endif
unsafe public static extern bool CryptMsgUpdate(
IntPtr hCryptMsg,
byte *pbData,
int cbData,
bool fFinal
);
#if OS
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
#else
[DllImport("/opt/cprocsp/lib/ia32/libcapilite.so")]
#endif
public static extern IntPtr CryptMsgOpenToEncode(
uint dwMsgEncodingType,
uint dwFlags,
uint dwMsgType,
IntPtr pvMsgEncodeInfo,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszInnerContentObjID,
IntPtr pStreamInfo
Возможно есть особенности. Пробывал различные варианты. В том числе со всеми найденными описаниями указанных функций.
С уважением, Андрей