在服务器2012上使用MS加密库 – CryptCreateHash错误代码87:ERROR_INVALID_PARAMETER

我试图在新的Windows Server 2012环境中托管Web应用程序,但是我收到了一个未经证实的错误。 此代码已存在于我们的代码库中多年,并且在任何其他平台上都没有遇到任何问题。

有问题的代码调用advapi32.dll的CryptCreateHash函数 – 一个Microsoft加密库。 调用函数时,我返回0表示调用失败,随后Err.LastDllError返回错误代码87,即ERROR_INVALID_PARAMETER。

正如我之前所说的,这段代码在各种环境中都运行了很多年 – 包括开发人员使用的Windows Server 2012测试机。 但是当放在也运行Server 2012的实时环境时(尽管在负载平衡系统的稍微复杂的上下文中),我收到错误。 这两台服务器都没有更新到Windows Server 2012 R2,它运行的是开箱即​​用的操作系统版本。

使用以下命令创建Crypt Provider的句柄后:

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 

从live和dev环境传递给该方法的数据的一些示例:

开发:
hCryptProv = 4966968
CALG_MD5 = 32771
hHash = 0

生活:
hCryptProv = 1587622576
CALG_MD5 = 32771
hHash = 0

似乎这两组参数基本相同,尽管服务器的hCryptProv往往是一个更大的数字(可能是因为它有更多的RAM?)。

我试图使用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的数据类型, phProv它是Integer,我还没有使用IntPtr进行测试。 我尝试使用ULong,因为这是在MSDN文档中定义HCRYPTPROV数据类型的方式。

 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作为数据类型时,注意live溢出。

编辑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  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 ,则需要在.NET ULONG_PTR其定义为IntPtr 。 你还需要一个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  Boolean 

另外,请务必告诉它设置上一个错误。 在C#中,我们使用DllImportAttribute并确保SetLastError=true 。 否则,调用Marshal.GetLastWin32Error不会返回预期的内容。

更新

你的CryptDecrypt原型应该是:

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

您需要将字符串转换为字节数组。 另请注意, dataLen参数是字节缓冲区的长度,而不是字符串的长度。

你应该看看pinvoke.net ,它有大多数Windows API调用的托管原型和示例。