我正在尝试在新的Windows Server 2012环境中托管Web应用程序,但是我收到一个意外错误。该代码已存在于我们的代码库中多年,并且在任何其他平台上均未遇到任何问题。
有问题的代码调用advapi32.dll的CryptCreateHash函数-Microsoft加密库。当调用函数时,我返回0表示调用失败,随后Err.LastDllError返回错误代码87,即ERROR_INVALID_PARAMETER。
就像我之前说过的那样,该代码已经在多种环境下运行了很多年,包括开发人员使用的Windows Server 2012测试机。但是,当放置在也可以运行Server 2012的实时环境中(尽管在负载平衡系统的环境中稍微复杂些),我会收到错误消息。这两个服务器都尚未更新到Windows Server 2012 R2,它正在运行现成的操作系统版本。
在使用以下方法创建隐窝提供程序的句柄之后:
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
从实时和开发环境将数据传递给方法的一些示例:
开发:
hCryptProv = 4966968
CALG_MD5 = 32771
hHash = 0
实时:
hCryptProv = 1587622576
CALG_MD5 = 32771
hHash = 0
尽管服务器的hCryptProv往往要大很多(可能是因为它有更多的RAM?),但看起来这两组参数基本上是相同的。
我试图使用SHA1而不是MD5,但是发生了相同的错误。
可能这是一个32/64位相关的问题,假设advapi32.dll是32bit?
任何建议,将不胜感激,谢谢。
编辑:
所需的原型:
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
如果有类型ULONG_PTR
,则需要IntPtr
在.NET中进行定义。您还需要一个DllImportAttribute,您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
参数是字节缓冲区的长度,而不是字符串的长度。
您应该查看pinvoke.net,该站点已管理了大多数Windows API调用的原型和示例。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句