/// <summary> /// Метод получения алгоритма хэширования /// </summary> /// <param name="signatureAlgOid"></param> /// <returns></returns> private uint GetHashAlg(string publicKeyAlg) { string signatureAlgOid = SignServiceUtils.GetSignatureAlg(publicKeyAlg); if (SignServiceUtils.IsUnix) { log.LogDebug("Получаем алгоритм хэширования под Unix платформой."); var cryptOidInfo = SignServiceUnix.GetHashAlg(signatureAlgOid); return(cryptOidInfo.Algid); } else { log.LogDebug("Получаем алгоритм хэширования под Windows платформой."); var cryptOidInfo = SignServiceWin.GetHashAlg(signatureAlgOid); return(cryptOidInfo.Algid); } }
internal static byte[] Sign(byte[] data, IntPtr hCert) { // Структура содержит информацию для подписания сообщений с использованием указанного контекста сертификата подписи CApiExtConst.CRYPT_SIGN_MESSAGE_PARA pParams = new CApiExtConst.CRYPT_SIGN_MESSAGE_PARA { // Размер этой структуры в байтах cbSize = (uint)Marshal.SizeOf(typeof(CApiExtConst.CRYPT_SIGN_MESSAGE_PARA)), // Используемый тип кодирования dwMsgEncodingType = CApiExtConst.PKCS_7_OR_X509_ASN_ENCODING, // Указатель на CERT_CONTEXT, который будет использоваться при подписании. // Для того чтобы контекст предоставил доступ к закрытому сигнатурному ключу, // необходимо установить свойство CERT_KEY_PROV_INFO_PROP_ID или CERT_KEY_CONTEXT_PROP_ID pSigningCert = hCert, // Количество элементов в rgpMsgCert массиве CERT_CONTEXT структур.Если установлено ноль, // в подписанное сообщение не включаются сертификаты. cMsgCert = 1 }; CApiExtConst.CERT_CONTEXT contextCert = Marshal.PtrToStructure <CApiExtConst.CERT_CONTEXT>(hCert); CApiExtConst.CERT_INFO certInfo = Marshal.PtrToStructure <CApiExtConst.CERT_INFO>(contextCert.pCertInfo); var signatureAlg = SignServiceUtils.GetSignatureAlg(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); var cryptOidInfo = GetHashAlg(signatureAlg); //Содержащий алгоритм хеширования, используемый для хеширования данных, подлежащих подписке. pParams.HashAlgorithm.pszObjId = cryptOidInfo.pszOID; // Массив указателей на буферы, содержащие содержимое, подлежащее подписке. IntPtr rgpbToBeSigned = Marshal.AllocHGlobal(data.Length); // Выделяем память под хранение сертификата GCHandle pGC = GCHandle.Alloc(hCert, GCHandleType.Pinned); try { // Массив указателей на контексты сертификатов для включения в подписанное сообщение. // Если хотим использовать сертификат для подписания, указатель на него должен быть в массиве rgpMsgCert. pParams.rgpMsgCert = pGC.AddrOfPinnedObject(); Marshal.Copy(data, 0, rgpbToBeSigned, data.Length); // Указатель, определяющий размер в байтах буфера signArray . // Когда функция возвращается, эта переменная содержит размер в байтах подписанного и закодированного сообщения. uint signArrayLength = 0; // Указатель на буфер , для получения кодированного подписанного хэш, если detached является значение TRUE , // или как кодированного контента и подписанного хэша , если detached является FALSE. byte[] signArray = null; // TRUE, если это должна быть отдельная подпись, Если для этого параметра установлено значение TRUE , в pbSignedBlob кодируется только подписанный хеш . // В противном случае кодируются как rgpbToBeSigned, так и подписанный хеш. bool detached = true; // Количество элементов массива в rgpbToBeSigned. // Этот параметр должен быть установлен в единицу, если для параметра fDetachedSignature установлено значение TRUE uint cToBeSigned = 1; // Подписываем данные // new uint[1] { (uint)data.Length } - Массив размеров в байтах буферов содержимого, на которые указывает rgpbToBeSigned if (!CApiExtWin.CryptSignMessage(ref pParams, detached, cToBeSigned, new IntPtr[1] { rgpbToBeSigned }, new uint[1] { (uint)data.Length }, signArray, ref signArrayLength)) { throw new CryptographicException($"Ошибка при подписании данных. Первый вызов CryptSignMessage вернул false. Код ошибки: {Marshal.GetLastWin32Error()}."); } signArray = new byte[signArrayLength]; if (!CApiExtWin.CryptSignMessage(ref pParams, detached, cToBeSigned, new IntPtr[1] { rgpbToBeSigned }, new uint[1] { (uint)data.Length }, signArray, ref signArrayLength)) { throw new CryptographicException($"Ошибка при подписании данных. Второй вызов CryptSignMessage вернул false. Код ошибки: {Marshal.GetLastWin32Error()}."); } return(signArray); } finally { Marshal.FreeHGlobal(rgpbToBeSigned); pGC.Free(); } }