Использование криптографической библиотеки MS на сервере 2012 - код ошибки CryptCreateHash 87: ERROR_INVALID_PARAMETER

Я пытаюсь разместить веб-приложение в новой среде Windows Server 2012, однако получаю непредвиденную ошибку. Этот код существует в нашей кодовой базе в течение многих лет, и на любой другой платформе проблем не было.

Данный код вызывает функцию CryptCreateHash в advapi32.dll - криптографической библиотеке Microsoft. При вызове функции мне возвращается 0 для обозначения сбоя вызова, впоследствии Err.LastDllError возвращает код ошибки 87, который равен ERROR_INVALID_PARAMETER.

Как я уже говорил, этот код отлично работал в течение многих лет в различных средах, в том числе на тестовой машине Windows Server 2012, используемой разработчиками. Однако, когда я включаю живую среду, в которой также работает Server 2012 (хотя и в несколько более сложном контексте системы с балансировкой нагрузки), я получаю сообщение об ошибке. Ни один из серверов еще не был обновлен до Windows Server 2012 R2, на нем запущена готовая версия ОС.

После создания дескриптора для провайдера Crypt с помощью:

CryptAcquireContext(hCryptProv, vbNullString, SERVICE_PROVIDER, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)

Я использую hCryptProv для вызова функции CryptCreateHas.

  If CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, hHash) = 0 Then
      Dim _error As Integer = Err.LastDllError
      Throw New CryptoException("Error during CryptCreateHash. Error Code: " & _error.ToString)
  End If

Некоторые примеры данных, передаваемых методу как из реальной среды, так и из среды разработки:

Dev:
hCryptProv = 4966968
CALG_MD5 = 32771
hHash = 0

Жить:
hCryptProv = 1587622576
CALG_MD5 = 32771
hHash = 0

Похоже, что оба этих набора параметров в основном идентичны, хотя hCryptProv сервера имеет тенденцию быть намного большим числом (возможно, потому что у него намного больше ОЗУ?).

Я попытался использовать SHA1 вместо MD5, но произошла та же ошибка.

Возможно, это проблема 32/64 бит, предполагая, что advapi32.dll является 32-битной?

Любые предложения будут оценены, спасибо.

РЕДАКТИРОВАТЬ:

Прототипы по запросу:

Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" _
    (ByRef phProv As IntPtr, _
     ByVal pszContainer As String, _
     ByVal pszProvider As String, _
     ByVal dwProvType As Integer, _
     ByVal dwFlags As Integer) As Integer


Private Declare Function CryptCreateHash Lib "advapi32.dll" _
    (ByVal hProv As IntPtr, _
     ByVal Algid As Integer, _
     ByVal hKey As Integer, _
     ByVal dwFlags As Integer, _
     ByRef phHash As Integer) As Integer

Я играл с типом данных phProvРанее это было Integer, я еще не тестировал с использованием IntPtr. Я пытался использовать ULong, потому что это как HCRYPTPROV тип данных определен в документах MSDN.

typedef ULONG_PTR HCRYPTPROV; 

Также вот значения дескриптора, возвращаемого CryptAcquireContext в различных конфигурациях:

LIVE 32: hCryptProv = 606412672 
LIVE 64: hCryptProv = -1480179632 
LOCAL: hCryptProv = 4966968 
DEV 32: hCryptProv = 99009648 
DEV 64: hCryptProv = 918798256 

Это когда я использовал Integer в качестве типа данных, обратите внимание на переполнение в реальном времени.

РЕДАКТИРОВАТЬ 2

Это возможно исправлено. Теперь, когда я вызываю CryptDecrypt, я получаю ошибку -2146893820 (NTE_BAD_LEN). возможно, делать с *pdwDataLen переменная.

Вот определение метода:

Private Declare Function CryptDecrypt Lib "advapi32.dll" _
                              (ByVal hKey As IntPtr, _
                              ByVal hHash As IntPtr, _
                              ByVal Final As Boolean, _
                              ByVal dwFlags As Integer, _
                              ByVal pbData As String, _
                              ByRef pdwDataLen As Integer) _
                            As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

И звонок:

lLength = Len(strData)
If CryptDecrypt(_hKey, 0, 1, 0, sTemp, lLength) = False Then
                Dim _error As Integer = Err.LastDllError
                Throw New CryptoException("Error during CryptDecrypt. Error Code: " & _error.ToString)
            End If

1 ответ

Решение

Если у вас есть тип ULONG_PTR, это должно быть определено как IntPtr в.NET. Вам также понадобится DllImportAttribute Your CryptCreateHash должно быть:

Declare Auto Function CryptCreateHash Lib "advapi32.dll" _
    (ByVal hProv As IntPtr, _
     ByVal algId As Integer, _
     ByVal hKey As IntPtr, _
     ByVal dwFlags As Integer, _
     ByRef phHast As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean

Кроме того, убедитесь, что вы сказали, чтобы установить последнюю ошибку. В C# мы используем DllImportAttribute и убедитесь, что SetLastError=true, В противном случае звонит Marshal.GetLastWin32Error не возвращает то, что ожидалось.

Обновить

Ваш CryptDecrypt Прототип должен быть:

Declare Function CryptDecrypt Lib "advapi32.dll" 
    (ByVal hkey As IntPtr, _
     ByVal hHash As IntPtr, _
     <MarshalAs(UnmanagedType.Bool)> ByVal final As Boolean, _
     ByVal flags As Integer, _
     ByVal data As Byte(), 
     ByRef dataLen As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean

Вам нужно будет преобразовать вашу строку в байтовый массив. Также обратите внимание, что dataLen Параметр - это длина байтового буфера, а не длина строки.

Вы должны проверить http://www.pinvoke.net/, который управлял прототипами и примерами для большинства вызовов Windows API.

Другие вопросы по тегам