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

412 Views Asked by At

I'm aware of the other thread on this issue (AES decryption error " The input data is not a complete block." Error vb.net), but I'm either not implementing the solutions offered there correctly, or something about my particular variant of this issue isn't covered by those solutions. In any event I'm getting the incomplete block error from the following code

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 is my key, which I'll not be including. It's just a String though, nothing special.

I've tried several other methods to decrypt based on guidance on the MSDN site, DreamInCode, etc. None worked, but they all had different issues (typically returning a blank string). Seeing as this version of code closely mirrors my encryption code, I'd like to stick with it (or at least as close as I can while still having functional code).

1

There are 1 best solutions below

0
On BEST ANSWER

Despite all comments, I still lack understanding of your intentions. Therefore, the sample code below may not provide what you exactly want, but at least should give an idea how to employ cryptographic functions. Particularly, the most notable difference from your approach is that the encryption key and initialization vector are computed once and for all messages, rather than reevaluated on each occasion, because the latter is prone to synchronization errors — such as when you reuse single crypto object to communicate with multiple parties, or when some messages get lost in transmission.

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

Again, please, note that this is just an example. I am not endorsing any kind of protection techniques shown here, especially because your task remains unknown. The code above simply illustrates the syntax and semantics — not how to do it right.