为什么在.Net中由AesCryptoServiceProvider加密时尾部块已丢失?

时间:2017-07-31 08:35:20

标签: .net vb.net visual-studio encryption cryptography

我尝试使用AesCryptoServiceProvider来加密数据,并通过字节数组传递。

运行此代码,您将看到默认数据长度为32 * 8bit,这是我设置的,运行完美。

然后,您可以将长度设置为您想要的任何其他长度。例如,33,表示数据的总长度(33 * 8bit)不是128bit的整数倍。

所以在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 个答案:

答案 0 :(得分:0)

确定。我发现了。

将数据写入csEncrypt(CryptoStream类)后,

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

我们应该关闭流,让.Net知道&#34;全部,你已经获得了所有数据。&#34;

    csEncrypt.Close()

然后,最后一个不完整的块被填充和加密。这时,我们可以阅读结果。

    encrypted = msEncrypt.ToArray()

所以,总代码是这样的:

    csEncrypt.Write(plainByte, 0, plainByte.Length)
    csEncrypt.Close()
    encrypted = msEncrypt.ToArray()