2017-07-31 48 views
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 

無論如何,感謝大家花時間閱讀本文並幫助我解決問題。真誠。

+1

msEncrypt.ToArray()太快執行,內存流完全寫入之前。它需要在Using語句之後去*。或者你需要明確地使用csEncrypt.FlushFinalBlock()。 –

回答

0

好的。我發現。

寫數據到csEncrypt(CryptoStream類)後,

csEncrypt.Write(plainByte, 0, plainByte.Length) 

我們應該關閉流,這讓淨知道「這一切,你已經得到了所有的數據。」

csEncrypt.Close() 

然後,最後的不完整塊得到填充和加密。目前,我們可以讀取結果。

encrypted = msEncrypt.ToArray() 

所以,總的代碼是這樣的:

csEncrypt.Write(plainByte, 0, plainByte.Length) 
    csEncrypt.Close() 
    encrypted = msEncrypt.ToArray() 
相關問題