繁体   English   中英

使用Pinvoke调用advapi.dll:CryptDecrypt和CryptEncrypt意外行为

[英]Calling advapi.dll using Pinvoke: CryptDecrypt and CryptEncrypt unexpected behaviour

这是该问题的后续措施。

我正在从VB.net调用WinAPI加密功能,以确保与共享结果数据的旧产品兼容。

该代码可以正常工作很多年,但是最近我在Windows Server 2012上运行时遇到了问题。在查看了各种示例和上一个问题的答案之后,我对代码进行了全面检查,包括更改了以前的字符串变量为字节数组,我认为这是更正确的功能。 我以前不知道它如何与字符串一起工作,但是在解决了原始的Server 2012问题之后,由于字符串的NTE_BAD_LENGTH而失败。

现在,将字符串转换为字节数组后,该代码似乎无法像以前一样进行加密,也不会解密CryptEncrypt生成的内容。

该代码的主要内容如下:

(在此之前调用CryptCreateHash,CryptHashData,CryptDeriveKey)

Dim _encoding As System.Text.ASCIIEncoding = New System.Text.ASCIIEncoding()

Dim data As String = "Testing123" ''define test String
Debug.WriteLine("Test Data: " & data)

''convert data to Byte()
Dim _bigBuffer As Byte() = New Byte(127) {} ''Buffer to be encrypted
Dim _dataBuffer As Byte() = _encoding.GetBytes(data) ''Get the text to be encrypted into a byte()
Buffer.BlockCopy(_dataBuffer, 0, _bigBuffer, 0, _dataBuffer.Length) ''Copy the data into the big buffer
Dim _dataBufferLength As UInteger = Convert.ToUInt32(_dataBuffer.Length) ''Get the length

Debug.Write("PlainText Data in buffer: ")
For Each _b As Byte In _dataBuffer
    Debug.Write(_b & ", ")
Next

''Encrypt data.
If CryptoApi.CryptEncrypt(_hKey, IntPtr.Zero, True, 0, _bigBuffer, _dataBufferLength, _bigBuffer.Length) = False Then
    Dim _error As Integer = Err.LastDllError
    Throw New Exception("Error during CryptEncrypt. Error Code: " & _error.ToString)
End If

''print out the encrypted string
Dim _encryptedDataBuffer As Byte() = New Byte(_dataBufferLength - 1) {} ''Buffer, size is size of the output encrypted string
Buffer.BlockCopy(_bigBuffer, 0, _encryptedDataBuffer, 0, _dataBufferLength) ''copy from output buffer to new buffer
Dim _encryptedStringFromBuffer As String = _encoding.GetString(_encryptedDataBuffer) ''Decode buffer back to string

Debug.WriteLine("")
Debug.WriteLine("Encrypted: " & _encryptedStringFromBuffer) ''Write encrypted string from buffer

Debug.Write("Encrypted Data in buffer: ")
For Each _b As Byte In _encryptedDataBuffer
    Debug.Write(_b & ", ")
Next

''Copy encrypted strings buffer, ready to decrypted
 Dim _encryptedBufferCopy As Byte() = New Byte(127) {} ''new buffer to hold encrypted data
 Buffer.BlockCopy(_bigBuffer, 0, _encryptedBufferCopy, 0, _bigBuffer.Length) ''copy the output of encryption
 Dim _inputLengthCopy As UInteger = _dataBufferLength ''Copy the length of encrypted data

 ''Decrypt data.
 If CryptoApi.CryptDecrypt(_hKey, IntPtr.Zero, True, 0, _encryptedBufferCopy, _encryptedBufferCopy.Length) = False Then
     Dim _error As Integer = Err.LastDllError
     Throw New Exception("Error during CryptDecrypt. Error Code: " & _error.ToString)
 End If

 Dim _outBuffer As Byte() = New Byte(_dataBufferLength - 1) {}
 Buffer.BlockCopy(_bigBuffer, 0, _outBuffer, 0, _dataBufferLength)
 Dim _stringFromBuffer As String = _encoding.GetString(_outBuffer)

 Debug.WriteLine("")
 Debug.Write("Decrypted Data in buffer: ")
 For Each _b As Byte In _outBuffer
     Debug.Write(_b & ", ")
 Next

 Debug.WriteLine("")
 Debug.WriteLine("Decrypted: " & _stringFromBuffer) 

我的方法原型定义为:

Friend Declare Function CryptEncrypt Lib "advapi32.dll" _
                            (ByVal hKey As IntPtr, _
                             ByVal hHash As IntPtr, _
                             <MarshalAs(UnmanagedType.Bool)> ByVal final As Boolean, _
                             ByVal dwFlags As Integer, _
                             ByVal data As Byte(), _
                             ByRef pdwDataLen As Integer, _
                             ByVal dwBufLen As Integer) _
                          As <MarshalAs(UnmanagedType.Bool)> Boolean


Friend Declare Function CryptDecrypt Lib "advapi32.dll" _
                              (ByVal hKey As IntPtr, _
                              ByVal hHash As IntPtr, _
                              <MarshalAs(UnmanagedType.Bool)> ByVal final As Boolean, _
                              ByVal dwFlags As Integer, _
                              ByVal data As Byte(), _
                              ByRef pdwDataLen As Integer) _
                            As <MarshalAs(UnmanagedType.Bool)> Boolean

示例输出如下:
测试数据:Testing123
缓冲区中的PlainText数据:84、101、115、116、105、110、103、49、50、51,
加密:CW? ??? _
缓冲区中的加密数据:12、67、87、133、158、9、139、250、255、95,
缓冲区中的解密数据:12,67,87,133,158,9,139,250,255,95,
解密:CW? ??? _

如您所见,解密后缓冲区保持完全相同。

我不知道为什么会这样,我唯一的理论是,这与我用来编码Byte()的字符集有关,尽管我尝试了几次,但没有区别。 这也可能适用于密码参数(传递给CryptHashData Byte())。

任何帮助是极大的赞赏。

编辑1:感谢您的帮助,我今天早些时候意识到缓冲区复制问题,我试图在我的测试应用程序中隔离问题,但最终导致变量变复杂,是的。

实际上,VB中的数组是使用最高索引实例化的,所以127创建了一个长度为128的数组,这让我感到困惑。

正如您所讨论的,我相信我的问题现在出在编码上。 以前,数据是作为.NET字符串传递到CryptEncrypt / CryptDecrypt ,而不是像我现在所做的那样首先转换为byte()。 但是我不知道非托管代码将如何处理该字符串,大概是默认的.NET编码还是Windows编码?

我已经尝试了UTF8和Unicode,但是它们都不会镜像原始代码的行为,也不会将以前存储的字符串加密/解密为原始值。 这也是我要继续使用非托管方法以完全反映旧行为的原因(使用非托管方法的VB6应用程序用于在.NET中解密之前生成加密数据)。

我的代码现在可以加密和解密,但是,正如我所说,尽管使用了相同的加密技术,但输出的值与原始数据不匹配。 感谢您一直以来的帮助。

解密后的数据看起来与加密后的数据相同的原因是因为您显示了错误的缓冲区。 您正在解密到_encryptedBufferCopy ,然后将_bigBuffer复制到_outBuffer ,并将其显示为解密的数据。 但是_bigBuffer包含加密的数据。

您有太多的临时缓冲区。 另外,看到您使用dataBufferLength - 1分配数组有点令人不安。 我试图弄清楚为什么-1 还是因为VB坚持认为参数是最高索引而不是长度?

您还应该注意, CryptDecrypt的最后一个参数是ByRef 当函数返回时,该函数应包含已解密明文中的字节数。 您对CryptDecrypt调用传递了_encryptedBufferCopy.Length ,这似乎应该是一个错误。 无论如何,该功能将无法设置解密长度。

您将要遇到的一个问题是您正在使用ASCII编码。 ASCII是一种7位编码,这意味着如果您有任何字符的代码超过127,则调用encoding.GetBytes(textString)将为您提供? 高位设置的字符。

最好的选择是使用Encoding.UTF8

数据加密后,就无法通过调用encoding.GetString可靠地将其转换为字符串。 该数据缓冲区可以包含任何字节值,包括可能不显示的控制字符,可能绘制有趣的字符或谁知道的字符。 所以你有:

''print out the encrypted string
Dim _encryptedDataBuffer As Byte() = New Byte(_dataBufferLength - 1) {} ''Buffer, size is size of the output encrypted string
Buffer.BlockCopy(_bigBuffer, 0, _encryptedDataBuffer, 0, _dataBufferLength) ''copy from output buffer to new buffer
Dim _encryptedStringFromBuffer As String = _encoding.GetString(_encryptedDataBuffer) ''Decode buffer back to string

几乎可以肯定会创建一个无法显示的字符串。 ? 您在此处看到的字符表示字符值大于127的字节,您的ASCII编码将无法正确解释这些字符。

考虑到所有问题,我想知道为什么您不仅仅使用System.Security.Cryptography命名空间中的托管API。 我认为您会发现它容易得多,而且您不必担心句柄和32/64位问题等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM