locked
This makes no sense. Why are these strings not equal? RRS feed

  • Question

  • Hi all,

    Am hoping to find help here, after hours of banging my head against a wall.

    I encrypt/decrypt strings within my WinForm visual basic application. After a round trip (clearText -> encrypted -> clearText) it looks like I get back what I started with, but the strings do not evaluate as equal.  What's going on?

    My code:

    Dim key As String = "47577faf804155f93e3e1469cbecfaeb"
    Dim iv As String = "28d6a53467354ba8a8882f2004af5893"
    Dim startString As String = "hello"
    Dim cryptText As String = Encrypt(key, iv, startString)
    Dim endString As String = Decrypt(key, iv, cryptText)
    WriteLine(startString) ' "hello"
    WriteLine(IIf(TypeOf startString Is String, "True", "False")) ' "True"
    WriteLine(endString) ' "hello"
    WriteLine(IIf(TypeOf endString Is String, "True", "False")) ' "True"
    WriteLine(IIf(startString = endString, "Equal", "Not equal")) ' "Not equal"
    
    Friend Shared Function Encrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_encrypt As String) As String
    
            Dim sToEncrypt As String = prm_text_to_encrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim encrypted() As Byte
            Dim toEncrypt() As Byte
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Dim encryptor As ICryptoTransform = myRijndael.CreateEncryptor(key, IV)
    
            Dim msEncrypt As New MemoryStream()
            Dim csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
    
            toEncrypt = System.Text.Encoding.ASCII.GetBytes(sToEncrypt)
    
            csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
            csEncrypt.FlushFinalBlock()
    
            encrypted = msEncrypt.ToArray()
    
            Return (Convert.ToBase64String(encrypted))
    
        End Function
    
    Friend Shared Function Decrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_decrypt As String) As String
    
            Dim sEncryptedString As String = prm_text_to_decrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Dim decryptor As ICryptoTransform = myRijndael.CreateDecryptor(key, IV)
    
            Dim sEncrypted As Byte() = Convert.FromBase64String(sEncryptedString)
    
            Dim fromEncrypt() As Byte = New Byte(sEncrypted.Length) {}
    
            Dim msDecrypt As New MemoryStream(sEncrypted)
            Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
    
            csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length)
    
            Return (System.Text.Encoding.ASCII.GetString(fromEncrypt))
    
        End Function

    How come startString and endString have the same value and the same type but they are not equal?? This is breaking my ability to check at run-time whether Decrypt is producing expected results.

    thanks for your time,

    -Patrick


    • Edited by Patrick_999 Tuesday, August 19, 2014 1:27 PM
    Tuesday, August 19, 2014 1:26 PM

Answers

  • Since all those classes are IDisposable, you should really use "Using" to declare them !!!

    Also this code gives you both string equals

    Also in the decript, Use a streamReader to read your stream, ... Here it is not really necessary, but it can save you to have to deal with some strange errors sometimes

    Imports System.Security.Cryptography
    Imports System.IO
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Debug.WriteLine(startString) ' "hello"
            Debug.WriteLine(IIf(TypeOf startString Is String, "True", "False")) ' "True"
            Debug.WriteLine(endString) ' "hello"
            Debug.WriteLine(IIf(TypeOf endString Is String, "True", "False")) ' "True"
            Debug.WriteLine(IIf(startString = endString, "Equal", "Not equal")) ' "Not equal"
        End Sub
    
    
        Dim key As String = "47577faf804155f93e3e1469cbecfaeb"
        Dim iv As String = "28d6a53467354ba8a8882f2004af5893"
        Dim startString As String = "hello"
        Dim cryptText As String = Encrypt(key, iv, startString)
        Dim endString As String = Decrypt(key, iv, cryptText)
    
    
        Friend Shared Function Encrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_encrypt As String) As String
    
            Dim sToEncrypt As String = prm_text_to_encrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim toEncrypt() As Byte
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Using encryptor As ICryptoTransform = myRijndael.CreateEncryptor(key, IV)
                Using msEncrypt As New MemoryStream()
                    Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
                        toEncrypt = System.Text.Encoding.ASCII.GetBytes(sToEncrypt)
                        csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
                        csEncrypt.FlushFinalBlock()
                        Return (Convert.ToBase64String(msEncrypt.ToArray))
                    End Using
                End Using
            End Using
        End Function
    
        Friend Shared Function Decrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_decrypt As String) As String
    
            Dim sEncryptedString As String = prm_text_to_decrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Dim sEncrypted As Byte() = Convert.FromBase64String(sEncryptedString)
    
            Using decryptor As ICryptoTransform = myRijndael.CreateDecryptor(key, IV)
                Using msDecrypt As New MemoryStream(sEncrypted)
                    Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
                        Using SR As New IO.StreamReader(csDecrypt)
                            Return SR.ReadToEnd.Trim(Chr(0))
                        End Using
                    End Using
                End Using
            End Using
        End Function
    
    End Class



    • Edited by Crazypennie Tuesday, August 19, 2014 4:12 PM 231654
    • Marked as answer by Patrick_999 Tuesday, August 19, 2014 6:29 PM
    Tuesday, August 19, 2014 4:07 PM
  •  You could try this. At the end of the Decrypt function make a temp string of the bytes and then return the string that you remove the end from like this.

            Dim str As String = System.Text.Encoding.ASCII.GetString(fromEncrypt)
    
            Return str.Remove(str.IndexOf(Chr(0)))
    
        End Function
    


    If you say it can`t be done then i`ll try it

    • Marked as answer by Patrick_999 Tuesday, August 19, 2014 5:51 PM
    Tuesday, August 19, 2014 2:32 PM

All replies

  • Works fine for me.


    La vida loca

    Tuesday, August 19, 2014 1:53 PM
  • Hi,

     If you inspect the length of the startString and the endString you will see that the startString is 5 chars in length and the endString is 33 chars in length. If i do this to cut the end of the endString off at the first index of Chr(0) then it works fine. The returned endString is not null terminated.

            endString = endString.Remove(endString.IndexOf(Chr(0)))
    
            If startString = endString Then
                MessageBox.Show("Same")
            End If
    


    If you say it can`t be done then i`ll try it

    • Proposed as answer by Cor Ligthert Tuesday, August 19, 2014 4:13 PM
    Tuesday, August 19, 2014 2:15 PM
  •  You could try this. At the end of the Decrypt function make a temp string of the bytes and then return the string that you remove the end from like this.

            Dim str As String = System.Text.Encoding.ASCII.GetString(fromEncrypt)
    
            Return str.Remove(str.IndexOf(Chr(0)))
    
        End Function
    


    If you say it can`t be done then i`ll try it

    • Marked as answer by Patrick_999 Tuesday, August 19, 2014 5:51 PM
    Tuesday, August 19, 2014 2:32 PM
  • Since all those classes are IDisposable, you should really use "Using" to declare them !!!

    Also this code gives you both string equals

    Also in the decript, Use a streamReader to read your stream, ... Here it is not really necessary, but it can save you to have to deal with some strange errors sometimes

    Imports System.Security.Cryptography
    Imports System.IO
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Debug.WriteLine(startString) ' "hello"
            Debug.WriteLine(IIf(TypeOf startString Is String, "True", "False")) ' "True"
            Debug.WriteLine(endString) ' "hello"
            Debug.WriteLine(IIf(TypeOf endString Is String, "True", "False")) ' "True"
            Debug.WriteLine(IIf(startString = endString, "Equal", "Not equal")) ' "Not equal"
        End Sub
    
    
        Dim key As String = "47577faf804155f93e3e1469cbecfaeb"
        Dim iv As String = "28d6a53467354ba8a8882f2004af5893"
        Dim startString As String = "hello"
        Dim cryptText As String = Encrypt(key, iv, startString)
        Dim endString As String = Decrypt(key, iv, cryptText)
    
    
        Friend Shared Function Encrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_encrypt As String) As String
    
            Dim sToEncrypt As String = prm_text_to_encrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim toEncrypt() As Byte
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Using encryptor As ICryptoTransform = myRijndael.CreateEncryptor(key, IV)
                Using msEncrypt As New MemoryStream()
                    Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
                        toEncrypt = System.Text.Encoding.ASCII.GetBytes(sToEncrypt)
                        csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
                        csEncrypt.FlushFinalBlock()
                        Return (Convert.ToBase64String(msEncrypt.ToArray))
                    End Using
                End Using
            End Using
        End Function
    
        Friend Shared Function Decrypt(ByVal prm_key As String, ByVal prm_iv As String, ByVal prm_text_to_decrypt As String) As String
    
            Dim sEncryptedString As String = prm_text_to_decrypt
    
            Dim myRijndael As New RijndaelManaged
            myRijndael.Padding = PaddingMode.Zeros
            myRijndael.Mode = CipherMode.CBC
            myRijndael.KeySize = 256
            myRijndael.BlockSize = 256
    
            Dim key() As Byte
            Dim IV() As Byte
    
            key = System.Text.Encoding.ASCII.GetBytes(prm_key)
            IV = System.Text.Encoding.ASCII.GetBytes(prm_iv)
    
            Dim sEncrypted As Byte() = Convert.FromBase64String(sEncryptedString)
    
            Using decryptor As ICryptoTransform = myRijndael.CreateDecryptor(key, IV)
                Using msDecrypt As New MemoryStream(sEncrypted)
                    Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
                        Using SR As New IO.StreamReader(csDecrypt)
                            Return SR.ReadToEnd.Trim(Chr(0))
                        End Using
                    End Using
                End Using
            End Using
        End Function
    
    End Class



    • Edited by Crazypennie Tuesday, August 19, 2014 4:12 PM 231654
    • Marked as answer by Patrick_999 Tuesday, August 19, 2014 6:29 PM
    Tuesday, August 19, 2014 4:07 PM

  • IronRazerz


    Thank you so much for your solution.  If you understand what was going on in the Decrypt function, could you share your insight please? I have never run into this problem before. If the Decrypt result (endString) is 33 in length, how come the IDE inserts the closing double quote (") immediately after the hello text? Is this a bug or is the function just following instructions exactly?

    -Patrick

    Tuesday, August 19, 2014 5:55 PM
  • Crazypennie,

    Your code works well (I'm sure you knew that); thank you for taking the time to respond.  I have so much to learn from all you guys. What is this Chr(0) character that was padding the end of my endString and where did it come from?

    What is the point of using "using"? doesn't the garbage collector free up resources once a function returns its result?

    -Patrick

    Tuesday, August 19, 2014 6:29 PM
  • @ Patrick,

     Your Welcome.  8)

     To tell you the truth, i didn`t really study what your code was doing. I just pasted your code in a new project and tested the length of both strings because, i have run into the same type of problem with strings before. If i did study the code, i would recommend doing the same thing as Crazypennie suggested. You need to close and dispose of any new streams that you create. The Using/End Using blocks are real nice for doing this but, you can use the Stream.Close / Stream.Dispose methods.   8)


    If you say it can`t be done then i`ll try it

    Tuesday, August 19, 2014 6:37 PM
  • Patrick, When a object has a "Dispose" method, you should always call the "Dispose" when you are done with the object. Not doing it will most likely prevent the Garbage collector from freeing the memory used by the object. 

    This said, calling Dispose may be a problem, as some exception, or other reason may prevent the "Dispose from being called.

    When using the Using keyword, the Dispose method is guaranty to be called, no matter what !!!

    If you which not to use Using, but dispose instead, you should use this code pattern. (This also guaranty that "Dispose will be called

            Dim MS As IO.MemoryStream = Nothing
            Try
                MS = New IO.MemoryStream(New Byte(2) {})
            Finally
                MS.Dispose()
            End Try


    Like I say, this work also, but it gets to look like a plate of spaghetti when  you have several object that need to be disposed 

    Here an example of how to write your code with "Try" instead of "Using" (It works, but it look bad)

    Dim decryptor As ICryptoTransform = Nothing Dim msDecrypt As MemoryStream = Nothing Dim csDecrypt New CryptoStream = nothing Dim SR As IO.StreamReader = Nothing Try decryptor = ICryptoTransform = myRijndael.CreateDecryptor(key, IV) Try msDecrypt = New MemoryStream(sEncrypted) Try csDecrypt = New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read) Try SR = New IO.StreamReader(csDecrypt)

    'Do Something Finally SR.Dispose() End Try Finally csDecrypt.dispose() End Try Finally msDecrypt.dispose() End Try Finally decryptor.dispose End Try


    .

    Basicaly, It is better to do like I did in the other post and use Using



    • Edited by Crazypennie Tuesday, August 19, 2014 9:15 PM 132465
    Tuesday, August 19, 2014 7:02 PM
  • Thanks for the code and the lesson Crazypennie. I'll try to adopt good coding habits.
    • Edited by Patrick_999 Tuesday, August 19, 2014 9:09 PM
    Tuesday, August 19, 2014 9:08 PM
  • Crazypennie,

    Your code works well (I'm sure you knew that); thank you for taking the time to respond.  I have so much to learn from all you guys. What is this Chr(0) character that was padding the end of my endString and where did it come from?


    -Patrick

    Sorry, I forgot your first question, the padding

    the Rijndael algorithm to work need to have the input/output string length to be a multiple of 32.

    So, when you pass a string that is not a multiple of 32, a padding is added to the string to change the length to a size it can work with.

    Therefore, after decryption, you need to remove the padding that was added

    Tuesday, August 19, 2014 9:43 PM