Esempio n. 1
0
        /// <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);
            }
        }
Esempio n. 2
0
        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();
            }
        }