vb.net AES 解密returns "data is incomplete block"

vb.net AES decryption returns "data is incomplete block"

我知道关于这个问题的另一个话题 (AES decryption error " The input data is not a complete block." Error vb.net),但我要么没有正确实施那里提供的解决方案,要么没有涵盖我对这个问题的特定变体通过这些解决方案。无论如何,我从以下代码中得到了不完整的块错误

Private GD As System.Security.Cryptography.Aes = System.Security.Cryptography.Aes.Create
Private PDB As New System.Security.Cryptography.Rfc2898DeriveBytes(EK, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, &H65, &H64, &H76, &H65, &H64, &H65, &H76})

Public Function Decrypt(ByVal val As String) As String
    Dim ret As String = Nothing
    Dim TTB As New System.Text.UTF8Encoding

    Try
        Dim input() As Byte = TTB.GetBytes(val)

        Using ms As New System.IO.MemoryStream(input)
            Using cs As New System.Security.Cryptography.CryptoStream(ms, GD.CreateDecryptor(PDB.GetBytes(32), PDB.GetBytes(16)), Security.Cryptography.CryptoStreamMode.Read)
                Using sr As New System.IO.StreamReader(cs)
                    ret = sr.ReadToEnd()
                End Using
            End Using
        End Using

        input = nothing
    Catch ex As Exception
        EL.AddErr("Encountered an error while decrypting the provided text for " & FName & ". Error Details: " & ex.Message, path)
    End Try

    Return ret
End Function

EK 是我的密钥,我不会包括在内。不过它只是一个字符串,没什么特别的。

我已经根据 MSDN 站点、DreamInCode 等上的指导尝试了其他几种解密方法。None 有效,但它们都有不同的问题(通常返回空白字符串)。鉴于此版本的代码与我的加密代码非常相似,我想坚持使用它(或者至少在仍然具有功能代码的情况下尽可能接近)。

尽管有很多评论,但我仍然不了解您的意图。因此,下面的示例代码可能无法提供您真正想要的,但至少应该让您了解如何使用加密函数。特别是,与您的方法最显着的区别是,加密密钥和初始化向量是为所有消息一次性计算的,而不是每次都重新计算,因为后者容易出现同步错误——例如当您重用单个加密对象来与多方通信,或某些消息在传输过程中丢失。

Public Shared Sub Test()

    ' Note: You should not actually hard-code any sensitive information in your source files, ever!
    Dim sKeyPreimage As String = "MySuperPassword"
    Dim oMyCrypto As New MyCrypto(sKeyPreimage)

    Dim sPlaintext As String = "My super secret data"
    Dim sEncrypted As String = oMyCrypto.EncryptText(sPlaintext)
    Dim sDecrypted As String = oMyCrypto.DecryptText(sEncrypted)

    Console.Out.WriteLine("Plaintext: {0}", sPlaintext) ' "My super secret data"
    Console.Out.WriteLine("Encrypted: {0}", sEncrypted) ' "72062997872DC4B4D1BCBF48D5D30DF0D498B20630CAFA28D584CCC3030FC5F1"
    Console.Out.WriteLine("Decrypted: {0}", sDecrypted) ' "My super secret data"

End Sub

Public Class MyCrypto

    Private Shared TextEncoding As Text.Encoding = Text.Encoding.UTF8

    Private CipherEngine As System.Security.Cryptography.SymmetricAlgorithm

    ' Note: Unlike in the question, same key and IV are reused for all messages.
    Private CipherKey() As Byte
    Private CipherIV() As Byte

    Public Sub New(ByVal sKeyPreimage As String)

        Dim abKeyPreimage() As Byte = TextEncoding.GetBytes(sKeyPreimage)
        Dim abKeySalt() As Byte = TextEncoding.GetBytes("Ivan Medvedev")

        Const KeyDerivationRounds As Integer = 1 << 12
        Dim oKeyDerivationEngine As New System.Security.Cryptography.Rfc2898DeriveBytes(abKeyPreimage, abKeySalt, KeyDerivationRounds)

        Me.CipherEngine = System.Security.Cryptography.Aes.Create()
        Me.CipherEngine.Padding = Security.Cryptography.PaddingMode.PKCS7
        Me.CipherKey = oKeyDerivationEngine.GetBytes(Me.CipherEngine.KeySize >> 3)
        Me.CipherIV = oKeyDerivationEngine.GetBytes(Me.CipherEngine.BlockSize >> 3)

    End Sub

    Public Function Encrypt(ByVal abPlaintext() As Byte) As Byte()

        Dim abCiphertext() As Byte

        Using hStreamSource As New System.IO.MemoryStream(abPlaintext),
                hStreamCipher As New System.Security.Cryptography.CryptoStream(
                    hStreamSource,
                    Me.CipherEngine.CreateEncryptor(Me.CipherKey, Me.CipherIV),
                    Security.Cryptography.CryptoStreamMode.Read),
                hStreamTarget As New System.IO.MemoryStream

            hStreamCipher.CopyTo(hStreamTarget)
            abCiphertext = hStreamTarget.ToArray()

        End Using

        Return abCiphertext
    End Function

    Public Function Decrypt(ByVal abCiphertext() As Byte) As Byte()

        Dim abPlaintext() As Byte

        Using hStreamSource As New System.IO.MemoryStream(abCiphertext),
                hStreamCipher As New System.Security.Cryptography.CryptoStream(
                    hStreamSource,
                    Me.CipherEngine.CreateDecryptor(Me.CipherKey, Me.CipherIV),
                    Security.Cryptography.CryptoStreamMode.Read),
                hStreamTarget As New System.IO.MemoryStream

            hStreamCipher.CopyTo(hStreamTarget)
            abPlaintext = hStreamTarget.ToArray()

        End Using

        Return abPlaintext
    End Function

    Public Function EncryptText(ByVal sPlaintext As String) As String
        Dim abPlaintext() As Byte = TextEncoding.GetBytes(sPlaintext)
        Dim abCiphertext() As Byte = Me.Encrypt(abPlaintext)
        Dim sCiphertext As String = Hex.Format(abCiphertext)
        Return sCiphertext
    End Function

    Public Function DecryptText(ByVal sCiphertext As String) As String
        Dim abCiphertext() As Byte = Hex.Parse(sCiphertext)
        Dim abPlaintext() As Byte = Me.Decrypt(abCiphertext)
        Dim sPlaintext As String = TextEncoding.GetChars(abPlaintext)
        Return sPlaintext
    End Function

End Class

Public Class Hex

    Public Shared Function Format(ByVal abValue() As Byte) As String
        Dim asChars(0 To abValue.Length * 2 - 1) As Char
        Dim ndxChar As Integer = 0
        For ndxByte As Integer = 0 To abValue.Length - 1
            Dim bNibbleHi As Byte = abValue(ndxByte) >> 4, bNibbleLo As Byte = CByte(abValue(ndxByte) And &HFUS)
            asChars(ndxChar) = Convert.ToChar(If(bNibbleHi <= 9, &H30US + bNibbleHi, &H37US + bNibbleHi)) : ndxChar += 1
            asChars(ndxChar) = Convert.ToChar(If(bNibbleLo <= 9, &H30US + bNibbleLo, &H37US + bNibbleLo)) : ndxChar += 1
        Next
        Return New String(asChars)
    End Function

    Public Shared Function Parse(ByVal sValue As String) As Byte()

        If String.IsNullOrEmpty(sValue) Then Return New Byte() {}
        If (sValue.Length Mod 2) > 0 Then Return Nothing

        Dim ndxText As Integer = 0
        Dim ndxByteMax As Integer = (sValue.Length \ 2) - 1
        Dim abValue(0 To ndxByteMax) As Byte

        Try
            For ndxByte As Integer = 0 To ndxByteMax
                abValue(ndxByte) = Convert.ToByte(sValue.Substring(ndxText, 2), 16)
                ndxText += 2
            Next
        Catch ex As Exception
            Return Nothing
        End Try

        Return abValue
    End Function

End Class

再次请注意,这只是一个示例。我不赞成此处显示的任何类型的保护技术,尤其是因为您的任务仍然未知。上面的代码只是说明了语法和语义——而不是如何正确地做。