Использование криптографической библиотеки 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.