这是这个问题的后续。
我从 VB.net 调用 WinAPI Cryptography 函数,以确保与共享结果数据的旧产品兼容。
代码多年来一直运行良好,但是我最近在 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
缓冲区中的纯文本数据: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() 有关,尽管我已经尝试了几个并且没有区别。这也可能适用于密码参数(Byte() 传递给CryptHashData
)。
任何帮助是极大的赞赏。
编辑1: 感谢您的帮助,我今天早些时候意识到缓冲区复制问题,我试图在我的测试应用程序中隔离问题,但最终使我的变量复杂化,是的。
事实上,VB 中的数组是用最高索引实例化的,所以 127 创建了一个长度为 128 的数组,我知道这很混乱。
正如您所讨论的,我相信我现在的问题在于编码。以前,数据作为 .NET 字符串传递到CryptEncrypt
/CryptDecrypt
中,而不是像我现在所做的那样首先转换为 byte()。但是我不知道非托管代码将如何处理这个字符串,大概是默认的 .NET 编码或 Windows 编码?
我已经尝试过 UTF8 和 Unicode,但是它们都不会反映原始代码的行为,也不会将以前存储的字符串加密/解密为原始值。这也是我想继续使用非托管方法以准确反映遗留行为的原因(使用非托管方法的 VB6 应用程序用于在 .NET 中解密之前生成加密数据)。
我的代码现在加密和解密,但是,正如我所说,尽管使用了相同的加密技术,但输出的值与原始数据不匹配。感谢您一直以来的帮助。