1
我試圖使用AesCryptoServiceProvider加密數據,通過字節數組傳遞。爲什麼在通過.Net加密AesCryptoServiceProvider時尾部塊已經丟失?
運行這段代碼,你會看到默認的數據長度是32 * 8bit這就是我設置的,它運行的很完美。
然後,您可以將長度設置爲您想要的任何其他值。例如,33表示數據的總長度(33 * 8位)不是128位的整數倍。
所以在AES之前,它需要被填充到48 * 8bit。
但是,.Net丟棄了最後一個不完整塊。我認爲這就是解密時遇到異常的原因。
那麼,當我處理AesCryptoServiceProvider類時,有什麼不對嗎? 或者這是一個需要避免的問題? 我該如何解決這個問題並使用AES來加密數據?
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Module Module1
Private intKeySize As Integer = 256
Private Const c_intBlockSize As Integer = 128 'AES ONLY use 128bit block
Private pdmPaddingMode As PaddingMode = PaddingMode.PKCS7
Private cpmCipherMode As CipherMode = CipherMode.CFB
Private Const c_strDefault As String = "D49303DCDF5AAE2B128001EA48D19D04"
Sub Main()
prpPaddingMode = PaddingMode.ANSIX923 'you can set differen padding to test
Dim setlength As Integer = 32
tgA:
Dim objRandom As New System.Random(Now.Millisecond)
Dim inp(setlength - 1) As Byte
For i As Integer = 0 To inp.GetUpperBound(0) 'Random data generated as test data
inp(i) = CByte(objRandom.Next(0, 255))
Next i
BytesShow(inp, "Input")
Dim outp() As Byte = EncryptString_Aes(inp, NewKey(c_strDefault), Hex2Byte(c_strDefault)) 'I use c_strDefault as the IV and Key
BytesShow(outp, "Encrypted")
'The two lines below meet an exception probably becuase the final block lost in encryption
'Dim dep() As Byte = DecryptString_Aes(outp, NewKey(c_strDefault), Hex2Byte(c_strDefault))
'BytesShow(dep, "Decrypted")
Console.WriteLine("===========" & vbCrLf & "Finished, please press any key to continue:")
Console.ReadKey()
Console.WriteLine("===========" & vbCrLf & "===========" & vbCrLf & "What's Next Test Data Length?")
setlength = CInt(Console.ReadLine())
GoTo tgA
End Sub
Public Function EncryptString_Aes(ByVal plainByte() As Byte, ByVal Key() As Byte, ByVal IV() As Byte) As Byte()
Dim encrypted As Byte()
Using aesAlg As New AesCryptoServiceProvider()
aesAlg.Mode = prpCipherMode
aesAlg.Padding = prpPaddingMode
aesAlg.BlockSize = prpBlockSize
aesAlg.Key = Key
If aesAlg.Mode <> CipherMode.ECB Then
aesAlg.IV = IV
End If
Dim encryptor As ICryptoTransform = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV)
Dim msEncrypt As New MemoryStream()
Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
'Using swEncrypt As New StreamWriter(csEncrypt, Encoding.UTF8)
' swEncrypt.Write(plainText)
'End Using
Debug.WriteLine(aesAlg.Mode.ToString)
Debug.WriteLine(aesAlg.Padding.ToString)
csEncrypt.Write(plainByte, 0, plainByte.Length)
encrypted = msEncrypt.ToArray()
End Using
End Using
Return encrypted
End Function
Public Function DecryptString_Aes(ByVal cipherByte() As Byte, ByVal Key() As Byte, ByVal IV() As Byte) As Byte()
Dim msOut As New MemoryStream()
Using aesAlg As New AesCryptoServiceProvider()
aesAlg.Mode = prpCipherMode
aesAlg.Padding = prpPaddingMode
aesAlg.BlockSize = prpBlockSize
aesAlg.Key = Key
If aesAlg.Mode <> CipherMode.ECB Then
aesAlg.IV = IV
End If
Dim decryptor As ICryptoTransform = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV)
Using msDecrypt As New MemoryStream(cipherByte)
Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
'Using srDecrypt As New StreamReader(csDecrypt, Encoding.UTF8)
' decrypted = srDecrypt.ReadToEnd()
'End Using
Debug.WriteLine(aesAlg.Mode.ToString)
Debug.WriteLine(aesAlg.Padding.ToString)
Dim bytBuffer(1023) As Byte
Dim intCount As Integer
Do
intCount = csDecrypt.Read(bytBuffer, 0, bytBuffer.Length)
msOut.Write(bytBuffer, 0, intCount)
Debug.WriteLine("intCount = " & intCount.ToString)
Loop While intCount > 0
End Using
End Using
'Dim msDecrypt As New MemoryStream()
'Using csEncrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write)
' 'Using swEncrypt As New StreamWriter(csDecrypt, Encoding.UTF8)
' ' swEncrypt.Write(plainText)
' 'End Using
' csEncrypt.Write(cipherByte, 0, cipherByte.Length)
' decrypted = msDecrypt.ToArray()
'End Using
End Using
Return msOut.ToArray()
End Function
Public Sub BytesShow(ByRef bytin() As Byte)
BytesShow(bytin, "ByteArray_Show_End")
End Sub
Public Sub BytesShow(ByRef bytin() As Byte, ByRef msg As String)
For i As Integer = 0 To bytin.GetUpperBound(0) '測試用的數據用隨機數值
Select Case (i Mod 16)
Case 0
Console.Write(i.ToString.PadLeft(5) & "#) " & bytin(i).ToString("x2"))
Case 15
Console.WriteLine(" " & bytin(i).ToString("x2"))
Case Else
Console.Write(" " & bytin(i).ToString("x2"))
End Select
Next i
Console.WriteLine(" (#Total: " & (bytin.GetUpperBound(0) + 1).ToString & "#)" & vbCrLf & "===================" & msg)
End Sub
Public Function getSha512HashBytes(ByVal strInput As String) As Byte()
Dim bytData As Byte()
Using Sha512Hasher As New SHA512CryptoServiceProvider
bytData = Sha512Hasher.ComputeHash(Encoding.UTF8.GetBytes(strInput))
End Using
Return bytData
End Function
Public Function NewKey(ByVal StringKey As String) As Byte()
Dim objRfc2898 As New Rfc2898DeriveBytes(StringKey, getSha512HashBytes(StringKey), 1000)
Dim bytKey As Byte() = objRfc2898.GetBytes(CInt(prpKeySize/8))
objRfc2898.Reset()
objRfc2898.Dispose()
Return bytKey
End Function
Public Function Hex2Byte(ByVal StringValue As String) As Byte()
Dim bytValue((StringValue.Length \ 2) - 1) As Byte
For i As Integer = 0 To ((StringValue.Length \ 2) - 1)
bytValue(i) = CByte("&H" & Microsoft.VisualBasic.Mid(StringValue, ((i * 2) + 1), 2))
Next i
Return bytValue
End Function
Friend Property prpKeySize() As Integer
Get
Return intKeySize
End Get
Set(value As Integer)
Select Case value
Case 128, 192, 256
intKeySize = value
Case Else
Throw New CryptographicException("The key size is not one of the KeySize values.")
End Select
End Set
End Property
Friend ReadOnly Property prpBlockSize As Integer
Get
Return c_intBlockSize
End Get
End Property
Friend Property prpPaddingMode As PaddingMode
Get
Return pdmPaddingMode
End Get
Set(value As PaddingMode)
Select Case value
Case PaddingMode.ANSIX923, PaddingMode.ISO10126, PaddingMode.PKCS7, PaddingMode.Zeros, PaddingMode.None
pdmPaddingMode = value
Case Else
Throw New CryptographicException("The padding mode is not one of the supported PaddingMode values.")
End Select
End Set
End Property
Friend Property prpCipherMode As CipherMode
Get
Return cpmCipherMode
End Get
Set(value As CipherMode)
Select Case value
Case CipherMode.CBC, CipherMode.CFB, CipherMode.ECB
cpmCipherMode = value
Case Else
Throw New CryptographicException("The cipher mode is not one of the supported CipherMode values.")
End Select
End Set
End Property
End Module
無論如何,感謝大家花時間閱讀本文並幫助我解決問題。真誠。
msEncrypt.ToArray()太快執行,內存流完全寫入之前。它需要在Using語句之後去*。或者你需要明確地使用csEncrypt.FlushFinalBlock()。 –