none
The input is not a valid Base-64 string

    Question

  • I'm attempting to retrieve encrypted values from a TextFile. When I save the values with the code below, it rewrites everything on file. So, I was forced to Append text with the WriteLine() Function. Here is the code that is working, but not causing the error:

            My.Computer.FileSystem.WriteAllText( 
                My.Computer.FileSystem.SpecialDirectories.MyDocuments & 
                "\cipherFile.txt", cipherText, False)

    This is the code that am using, and want to Append text to the file instead of rewriting everything all the time! I want to use this code to encrypt usernames, and passwords on the database once it is completed. Here is the code with the error, but is the one I want to use:

            Dim File1 As StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(
        My.Computer.FileSystem.SpecialDirectories.MyDocuments &
            "\cipherFile.txt", True)
            File1.WriteLine(cipherusername)
            File1.WriteLine(cipherpassword)
            ''''' Cleanup the system
            File1.Close()
            File1.Dispose()

    When I press the Decrypt button, I get the error:

    An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll
    
    Additional information: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. 

    Here is the Decryption Function where the problem is highlighted on the first line of the code:

    Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)

    Here is the decryption function code:

    Public Function DecryptData(
            ByVal encryptedtext As String) As String
    
                ' Convert the encrypted text string to a byte array.
                Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
    
                ' Create the stream.
                Dim ms As New System.IO.MemoryStream
                ' Create the decoder to write to the stream.
                Dim decStream As New CryptoStream(ms,
                    TripleDes.CreateDecryptor(),
                    System.Security.Cryptography.CryptoStreamMode.Write)
    
                ' Use the crypto stream to write the byte array to the stream.
                decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
                decStream.FlushFinalBlock()
    
                ' Convert the plaintext stream to a string.
                Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
            End Function



    Friday, April 7, 2017 4:29 PM

All replies

  • Please consider using the IDE debugger, step through the code line by line in the offending function, see which line the issue is and also what are the values before the offending line fails and report back so those here to help can better assist.

    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Friday, April 7, 2017 4:42 PM
    Moderator
  • KarenInstructor,

    I know the line, and have put it there. Here is the code that is working, but I don't want to use it because I cannot update TextFile contents, but it replaces everything.

        My.Computer.FileSystem.WriteAllText( 
                My.Computer.FileSystem.SpecialDirectories.MyDocuments & 
                "\cipherFile.txt", cipherText, False)

    This is the code I want to use, because I want to update the TextFile items instead of rewriting everything. Check the code:

    Dim File1 As StreamWriter = My.Computer.FileSystem.OpenTextFileWriter( My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\cipherFile.txt", True) File1.WriteLine(cipherusername) File1.WriteLine(cipherpassword) ''''' Cleanup the system File1.Close() File1.Dispose()


    Friday, April 7, 2017 4:56 PM
  • Common,

    There are a few suggestions that I'd suggest but in my opinion, I think you're better off to start this again - and I'll help if you're interested?

    Am I correct that you want to take a string and from that, use string encryption and write it to a file? If the file exists, you want to append from it and of course along with that, you want a method to decrypt the text in the path back into a string again?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, April 7, 2017 6:43 PM
  • First, it's much easier to encrypt and decrypt using a Stream since that Class (inherited by FileStream, CrytpoStream, etc.) is incorporated into almost all, if not all, of the cryptographic libraries. I don't see what purpose is served by writing encrypted information to a file, line by line, when you can encrypt/write and read/decrypt in one shot.

    If you want to use the symmetric algorithm TripleDes the below article explains the correct way to do it. Attempting to encrypt piecemeal is probably going to cause you some issues when you read the file back differently than the way it was written out.

    Walkthrough: Encrypting and Decrypting Strings in Visual Basic


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Friday, April 7, 2017 7:41 PM
  • Common,

    I hope the following small class might help, whichever way you go:

    Code For Class:

    Option Strict On Option Explicit On Option Infer Off Imports System.Text Public NotInheritable Class TextOperations Public Shared Function _ GetBase64String(ByVal textToConvert As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToConvert) Then Dim b() As Byte = Encoding.UTF8.GetBytes(textToConvert) retVal = Convert.ToBase64String(b) End If Return retVal End Function Public Shared Function _ GetStringFromBase64(ByVal base64String As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(base64String) Then Dim b() As Byte = Convert.FromBase64String(base64String) retVal = Encoding.UTF8.GetString(b) End If Return retVal End Function Public Shared Function _ GetEncryptedString(ByVal textToEncrypt As String, _ ByVal encryptionKey As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToEncrypt) AndAlso _ Not String.IsNullOrWhiteSpace(encryptionKey) Then Using s3d As New Simple3Des(encryptionKey) retVal = s3d.EncryptData(textToEncrypt) End Using End If Return retVal End Function Public Shared Function _ GetDecryptedString(ByVal textToDecrypt As String, _ ByVal encryptionKey As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToDecrypt) AndAlso _ Not String.IsNullOrWhiteSpace(encryptionKey) Then Using s3d As New Simple3Des(encryptionKey) retVal = s3d.DecryptData(textToDecrypt) End Using End If Return retVal End Function ''' <summary> ''' Based on: https://msdn.microsoft.com/en-us/library/ms172831.aspx ''' </summary> ''' <remarks></remarks> Private NotInheritable Class Simple3Des Implements IDisposable Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider Sub New(ByVal key As String) ' Initialize the crypto provider. If Not String.IsNullOrWhiteSpace(key) Then TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) End If End Sub Public Function EncryptData(ByVal plaintext As String) _ As String ' Convert the plaintext string to a byte array. Dim plaintextBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(plaintext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the encoder to write to the stream. Dim encStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateEncryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. encStream.Write(plaintextBytes, 0, plaintextBytes.Length) encStream.FlushFinalBlock() ' Convert the encrypted stream to a printable string. Return Convert.ToBase64String(ms.ToArray) End Function Public Function DecryptData(ByVal encryptedtext As String) _ As String ' Convert the encrypted text string to a byte array. Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the decoder to write to the stream. Dim decStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateDecryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. decStream.Write(encryptedBytes, 0, encryptedBytes.Length) decStream.FlushFinalBlock() ' Convert the plaintext stream to a string. Return System.Text.Encoding.Unicode.GetString(ms.ToArray) End Function Private Function TruncateHash(ByVal key As String, _ ByVal length As Integer) _ As Byte() Dim sha1 As New Security.Cryptography.SHA1CryptoServiceProvider ' Hash the key. Dim keyBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(key) Dim hash() As Byte = sha1.ComputeHash(keyBytes) ' Truncate or pad the hash. ReDim Preserve hash(length - 1) Return hash End Function Public Sub Dispose() Implements IDisposable.Dispose If TripleDes IsNot Nothing Then TripleDes.Dispose() TripleDes = Nothing End If End Sub End Class End Class


    You can test it with this:

    Form1

    Option Strict On Option Explicit On Option Infer Off Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) Handles MyBase.Load Const text As String = "Apple Of My Eye" Const encryptionKey As String = "My Secret Password" Dim textTo64 As String = _ TextOperations.GetBase64String(text) Stop Dim textFrom64 As String = _ TextOperations.GetStringFromBase64(textTo64) Stop Dim encryptedText As String = _ TextOperations.GetEncryptedString(text, encryptionKey) Stop Dim decryptedText As String = _ TextOperations.GetDecryptedString(encryptedText, encryptionKey) Stop End Sub End Class


    If you'll give that a try then each time it gets to "Stop", hover your mouse over the variables that are then in scope.

    I hope that helps. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, April 7, 2017 8:14 PM
  • Frank L. Smith,

    Its been a long time since you part-took into one of my questions. Thanks, I've seen Paul P. Clement too trying to help from my previous questions. Its a great honor to work with you guys, and if possible, Frank Smith, I would want a solution that doesn't cause any more problems. I want this encrypted usernames and passwords to be stored like:

    usernameEcryptedVersion|PasswordEncryptedVersion

    The | is used to distinguish the two items that one is a username, while the other is a password on a different column. They should not be overwritten. Also. just to mention, I want to update the text with WriteLine() instead of WriteAllText() which overwrites everything.




    Friday, April 7, 2017 8:24 PM
  • Common,

    Just call me Frank please. ;-)

    *****

    Try the example that I just posted. Do you see how that's working?

    It has nothing to do with files at this point.

    Also: You don't have to use a streamwriter - you can use other built-in methods (that use a streamwriter under the hood) and then you don't have to fool with closing and disposing.

    First though, try the example above. It won't take but a few seconds.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, April 7, 2017 8:28 PM
  • Common,

    If you'll run the example, at each "Stop" you'll see this:

    Do understand please that those two ways are very different. Conversion to and from base64 is encoding, not encrypting.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, April 7, 2017 9:03 PM
  • Frank L. Smith,

    Its been a long time since you part-took into one of my questions. Thanks, I've seen Paul P. Clement too trying to help from my previous questions. Its a great honor to work with you guys, and if possible, Frank Smith, I would want a solution that doesn't cause any more problems. I want this encrypted usernames and passwords to be stored like:

    usernameEcryptedVersion|PasswordEncryptedVersion

    The | is used to distinguish the two items that one is a username, while the other is a password on a different column. They should not be overwritten. Also. just to mention, I want to update the text with WriteLine() instead of WriteAllText() which overwrites everything.




    I think you might need to use ReadLine or one of the other file I/O methods for reading a line at a time if you use WriteLine to write encrypted text line by line. Haven't tested, but I suspect that unencrypted line terminators (e.g. carriage return/line feed), will result in decryption problems when reading the file in to decrypt as a whole.

    Paul ~~~~ Microsoft MVP (Visual Basic)

    Friday, April 7, 2017 9:03 PM
  • I want this encrypted usernames and passwords to be stored like:

    usernameEcryptedVersion|PasswordEncryptedVersion

    Before you continue down that route, have you absolutely proved that '|' can never appear in the encrypted string?

    Friday, April 7, 2017 9:33 PM
  • Frank,

    Thanks, I will test how it works, then I'll reply tomorrow. Acamar, thanks for your heads up. I will leave that for now.

    Friday, April 7, 2017 9:55 PM
  • Frank,

    Thanks, I will test how it works, then I'll reply tomorrow. Acamar, thanks for your heads up. I will leave that for now.

    I want that you understand what's going on. Writing and reading files is a different thing but it's not hard once you get a handle on it (no pun intended).

    *****

    At the end of all that, if you want something that results in a file that's [pretty well] proprietary, then I can do that, but start with testing what I show and if you have time, look into encoding and encrypting. They're not at all the same.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, April 7, 2017 10:06 PM
  • Frank

    Thanks you for your help, but there are two things I've understood! You're trying to Encode Strings to bytes in UTF8 Encoding before you convert them into Base64 Strings. Then do it vice verse on the other Function?

    This section here, converts String to bytes into UTF8 Encoding and then into ToBase64String

    Public NotInheritable Class TextOperations
        Public Shared Function _
            GetBase64String(ByVal textToConvert As String) As String
    
            Dim retVal As String = Nothing
    
            If Not String.IsNullOrWhiteSpace(textToConvert) Then
                Dim b() As Byte = Encoding.UTF8.GetBytes(textToConvert)
    
                retVal = Convert.ToBase64String(b)
            End If
    
            Return retVal
    
        End Function

    I see here it is converting the Base64String back to UTF8 Encoding that was converted into bytes before it was converted into Base64String. Am I right?

            Public Shared Function _
            GetStringFromBase64(ByVal base64String As String) As String
    
            Dim retVal As String = Nothing
    
            If Not String.IsNullOrWhiteSpace(base64String) Then
                Dim b() As Byte = Convert.FromBase64String(base64String)
    
                retVal = Encoding.UTF8.GetString(b)
            End If
    
            Return retVal
    
        End Function

     

    I see here is how we can encrypt text, although we have not provided the strings to be encrypted.  

        Public Shared Function _
            GetEncryptedString(ByVal textToEncrypt As String, _
                               ByVal encryptionKey As String) As String
    
            Dim retVal As String = Nothing
    
            If Not String.IsNullOrWhiteSpace(textToEncrypt) AndAlso _
                Not String.IsNullOrWhiteSpace(encryptionKey) Then
    
                Using s3d As New Simple3Des(encryptionKey)
                    retVal = s3d.EncryptData(textToEncrypt)
                End Using
    
            End If
    
            Return retVal
    
        End Function

    Here is the Decryption part without the Encrypted Data.

        Public Shared Function _
            GetDecryptedString(ByVal textToDecrypt As String, _
                               ByVal encryptionKey As String) As String
    
            Dim retVal As String = Nothing
    
            If Not String.IsNullOrWhiteSpace(textToDecrypt) AndAlso _
               Not String.IsNullOrWhiteSpace(encryptionKey) Then
    
                Using s3d As New Simple3Des(encryptionKey)
                    retVal = s3d.DecryptData(textToDecrypt)
                End Using
            End If
    
            Return retVal
    
        End Function


    Saturday, April 8, 2017 7:54 AM
  • Frank,

    I now understand that my code was more about Encoding and Decoding from String to UTF8 bytes into Base64Strings, and than Encrypting the Strings. This code here calls the Encryption Function


            Dim cipherusername As String = wrapper.EncryptData(username)
            Dim cipherpassword As String = wrapper.EncryptData(userpassword)

    This is the Function that is being called here EncryptData(username) and here EncryptData(userpassword):

            Public Function EncryptData(
            ByVal plaintext As String) As String
    
                ' Convert the plaintext string to a byte array.
                Dim plaintextBytes() As Byte =
                    System.Text.Encoding.Unicode.GetBytes(plaintext)
    
                ' Create the stream.
                Dim ms As New System.IO.MemoryStream
                ' Create the encoder to write to the stream.
                Dim encStream As New CryptoStream(ms,
                    TripleDes.CreateEncryptor(),
                    System.Security.Cryptography.CryptoStreamMode.Write)
    
                ' Use the crypto stream to write the byte array to the stream.
                encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
                encStream.FlushFinalBlock()
    
                ' Convert the encrypted stream to a printable string.
                Return Convert.ToBase64String(ms.ToArray)
            End Function




    Saturday, April 8, 2017 8:20 AM
  • Common,

    I think you have it now.

    Tell me more about your goal. It sounds like you want to use encryption here and depending on just what you're trying to save, you might want to consider an XML file where the contents are encrypted.

    It's not that tough to do really and I'll show you, but tell me more about what you're trying to persist and we'll go from there.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, April 8, 2017 11:03 AM
  • Frank,

    XML is good. But I was considering to implement a tighter security not like the simpleDes security, and SHA1 that is being offered on that code. I was wondering if this code could somehow be optimized to implement tight security like SHA3, and a more complex security than simpleDes. I know Des was developed in the 70s with 64 bits of Keys, then I hear that AES is unbreakable. But 3Des is still being used after it was improved to be 3 Times stronger than the original Des. So, how can we proceed from there?

    Saturday, April 8, 2017 11:48 AM
  • Frank,

    XML is good. But I was considering to implement a tighter security not like the simpleDes security, and SHA1 that is being offered on that code. I was wondering if this code could somehow be optimized to implement tight security like SHA3, and a more complex security than simpleDes. I know Des was developed in the 70s with 64 bits of Keys, then I hear that AES is unbreakable. But 3Des is still being used after it was improved to be 3 Times stronger than the original Des. So, how can we proceed from there?

    I won't disagree there are "tighter" ways but tell me this: Is this text file only going to be a local file on the user's computer? If so, then I question what's wrong with this.

    I was just putting this together so have a look. I've modified the class from yesterday:

    Code For Class

    Option Strict On Option Explicit On Option Infer Off Imports System.Text Imports System.IO Public NotInheritable Class TextOperations Public Shared Function _ GetBase64String(ByVal textToConvert As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToConvert) Then Dim b() As Byte = Encoding.UTF8.GetBytes(textToConvert) retVal = Convert.ToBase64String(b) End If Return retVal End Function Public Shared Function _ GetStringFromBase64(ByVal base64String As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(base64String) Then Dim b() As Byte = Convert.FromBase64String(base64String) retVal = Encoding.UTF8.GetString(b) End If Return retVal End Function Public Shared Function _ GetEncryptedString(ByVal textToEncrypt As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToEncrypt) Then Using s3d As New Simple3Des() retVal = s3d.EncryptData(textToEncrypt) End Using End If Return retVal End Function Public Shared Function _ GetDecryptedString(ByVal textToDecrypt As String) As String Dim retVal As String = Nothing If Not String.IsNullOrWhiteSpace(textToDecrypt) Then Using s3d As New Simple3Des() retVal = s3d.DecryptData(textToDecrypt) End Using End If Return retVal End Function Public Shared Sub _ SaveUserPass(ByVal userName As String, _ ByVal password As String, _ ByVal filePath As String) If String.IsNullOrWhiteSpace(userName) Then MessageBox.Show("The username cannot be null or empty.") ElseIf String.IsNullOrWhiteSpace(password) Then MessageBox.Show("The password cannot be null or empty.") ElseIf String.IsNullOrWhiteSpace(filePath) Then MessageBox.Show("The file path cannot be null or empty.") ElseIf userName.Contains(" "c) Then MessageBox.Show("The username cannot contain any space characters.") ElseIf password.Contains(" "c) Then MessageBox.Show("The password cannot contain any space characters.") Else Dim fi As New FileInfo(filePath) If fi.Exists Then fi.Delete() End If Using s3d As New Simple3Des Dim xDoc As XElement = _ <Data> <%= New XAttribute("Field1", s3d.EncryptData(userName)) %> <%= New XAttribute("Field2", s3d.EncryptData(password)) %> </Data> xDoc.Save(fi.FullName) End Using End If End Sub Public Shared Function _ GetUserPass(ByVal filePath As String) As ReturnData Dim retVal As ReturnData = Nothing If String.IsNullOrWhiteSpace(filePath) Then MessageBox.Show("The file path cannot be null or empty.") Else Dim fi As New FileInfo(filePath) If Not fi.Exists Then MessageBox.Show("The file path could not be located.") Else Using s3d As New Simple3Des Dim xDoc As XElement = XElement.Load(fi.FullName) retVal = New ReturnData _ With {.UserName = s3d.DecryptData(xDoc.@Field1), _ .Password = s3d.DecryptData(xDoc.@Field2)} End Using End If End If Return retVal End Function Public Class ReturnData Public Property UserName As String Public Property Password As String End Class ''' <summary> ''' Based on: https://msdn.microsoft.com/en-us/library/ms172831.aspx ''' </summary> ''' <remarks></remarks> Private NotInheritable Class Simple3Des Implements IDisposable Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider Sub New() ' Initialize the crypto provider. Const key As String = "!a3r@Ra8eSpa#tuMj_tras8E" If Not String.IsNullOrWhiteSpace(key) Then TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) End If End Sub Public Function EncryptData(ByVal plaintext As String) _ As String ' Convert the plaintext string to a byte array. Dim plaintextBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(plaintext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the encoder to write to the stream. Dim encStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateEncryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. encStream.Write(plaintextBytes, 0, plaintextBytes.Length) encStream.FlushFinalBlock() ' Convert the encrypted stream to a printable string. Return Convert.ToBase64String(ms.ToArray) End Function Public Function DecryptData(ByVal encryptedtext As String) _ As String ' Convert the encrypted text string to a byte array. Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the decoder to write to the stream. Dim decStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateDecryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. decStream.Write(encryptedBytes, 0, encryptedBytes.Length) decStream.FlushFinalBlock() ' Convert the plaintext stream to a string. Return System.Text.Encoding.Unicode.GetString(ms.ToArray) End Function Private Function TruncateHash(ByVal key As String, _ ByVal length As Integer) _ As Byte() Dim sha1 As New Security.Cryptography.SHA1CryptoServiceProvider ' Hash the key. Dim keyBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(key) Dim hash() As Byte = sha1.ComputeHash(keyBytes) ' Truncate or pad the hash. ReDim Preserve hash(length - 1) Return hash End Function Public Sub Dispose() Implements IDisposable.Dispose If TripleDes IsNot Nothing Then TripleDes.Dispose() TripleDes = Nothing End If End Sub End Class End Class


    Back in Form1 where I tested it:

    Form1.vb

    Option Strict On Option Explicit On Option Infer Off Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) Handles MyBase.Load Dim desktop As String = _ Environment.GetFolderPath(Environment.SpecialFolder.Desktop) Dim filePath As String = _ IO.Path.Combine(desktop, "TestMe.xml") TextOperations.SaveUserPass("ExampleUser", "AlphabetSoup", filePath) Stop Dim result As TextOperations.ReturnData = _ TextOperations.GetUserPass(filePath) MessageBox.Show(String.Format("Username: {0}{1}Password: {2}", _ result.UserName, vbCrLf, _ result.Password), "Result") Stop End Sub End Class


    It wrote an XML file out to the file path that I gave it (a file on my desktop) and the contents look like this:

    <?xml version="1.0" encoding="utf-8"?> <Data Field1="7GIvTzGHtVEGw7or4BdrLKC8rBiX9TUb" Field2="tYAMAaskJfnbrAtmM+Il/9rObr1+PpyIsOqPxiD1tTI=" />


    Then the flip side - reading it back in - will return an instance of a simple class. To make sure it worked, I have it showing a MessageBox:

    If you want to "do it right" then it won't store the password; only a hash of the password. It can then be saved as a binary file with AES encryption and man that's a lot of work!

    Look at the contents that I showed there. Could you guess at what that was or what it meant? I couldn't. ;-)

    *****

    Notice also that I changed the Simple3Des class as shown here:

    Sub New() ' Initialize the crypto provider. Const key As String = "!a3r@Ra8eSpa#tuMj_tras8E" If Not String.IsNullOrWhiteSpace(key) Then TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) End If End Sub


    I don't pass the key in; it's set in the code. If you're going to use it then change that to whatever you want it to have.

    Your thoughts?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, April 8, 2017 12:01 PM
  • Common,

    I don't mind putting together something that's 'better'. It'd take a few hours but it's not that bad really.

    I have to ask this though:

    Do you obfuscate your program? If you don't then no matter how you go about it, anyone who wants to figure out what you have can do it without a lot of fanfare.

    Even if I built a really 'tight' assembly (a .dll file that I'd give you), someone who wants to figure it out won't bother trying to disassemble mine because they don't need to: They'd pull yours apart, see how you're using it, swipe the .dll file and off they go.

    Give it some thought. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, April 8, 2017 12:35 PM
  • Frank,

    So, in this scenario we're even reusing the previous code from the link you've provided? Give me time to Digest it then I'll get back to you! I want to test it first to see how it works.


    Saturday, April 8, 2017 12:37 PM
  • Frank,

    So, in this scenario we're even reusing the previous code from the link you've provided? Give me time to Digest it then I'll get back to you! I want to test it first to see how it works.


    Well I just put things into the first one. You don't need the encoding at all, but it might come in handy down the road so I just kept it there.

    *****

    You might want to try what I posted and put a breakpoint in. For me at least, once I step through the code line-by-line, it starts to make sense.

    :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, April 8, 2017 12:42 PM
  • Frank

    Thanks for your support. I'll test it.

    Saturday, April 8, 2017 1:04 PM
  • Frank

    Thanks for your support. I'll test it.

    In case this helps, you wanted to use AES and this does.

    I have the project directory zipped up and uploaded here:

    https://fls.exavault.com/share/view/gymx-67suetnp

    Download that, extract it somewhere, then open it with Visual Studio. When you do you'll be prompted to change it to your version so just follow the prompts and it should work ok.

    Inside the demo program there's a reference to a class library that I put together over the last few hours:

    It's really simple but I think you'll find it effective. You can add as many users as you want so long as they don't have the same UserName/Password combination.

    As I said earlier, it does NOT store the password anywhere. Instead, it creates a HashValue using SHA256.

    So what is this "hash" thing? Why use it?

    https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm(v=vs.110).aspx

    A cryptographic hash value is a one-way function; You cannot generate the source from the hash.

    Given a particular algorithm, the length of the hash value will always be the same and for this one using SHA256 (that's SecureHashAlgorithm) it will generate 32 bytes.

    The fact that it can't be reversed is a big deal; if your data is compromised, they'll have the UserNames but they will only have the resultant values of the hashing of their password.

    Now, to make it even more difficult, "add salt to taste":

    https://en.wikipedia.org/wiki/Salt_(cryptography)

    At the end of the day, they still don't have much even if your data has been compromised.

    To test to see if a user's entered data is valid, generate the Hash using the same thing that it used to start with and see if they match.

    In essence, that's what this assembly does. Not much else, but it does all that I described above.

    *****

    When you run what I uploaded, you'll see the following. I'll show screenshots following it (plus a link that wouldn't fit in the comments):

    Option Strict On Option Explicit On Option Infer Off Imports LocalUserPass.Credentials Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) _ Handles MyBase.Load Test() End Sub Private Sub Test() Try ' First, create an instance of the class named ' "UserCredentials". ' ' In your actual use, you may want to scope it ' higher than I am here, but it all starts with ' this: Dim uc As New UserCredentials ' Now I'll add a new user and password. ' ' Note that neither can contain a space character. ' ' You might want test this by changing what I'll ' show and put a space in; it will throw an ' exception if you do: uc.Add("FrankSmith", "123456") ' Remember that part of the concept here is that ' the password is NEVER saved. ' ' The class has to figure out if it's a duplicate* ' though, so that makes the routine that does that ' a bit involved. Nevertheless, it does. ' ' In this I'll add another user but in yours when ' you run this, change it so that they're both ' identical then run it and you'll see that it ' recognizes that it's a duplicate entry. ' ' The technique used is actually the same one ' that's used to test whether a username and ' password are valid: ' ' ' ' * Duplicate entry being defined as a username ' (to lower) being duplcated *AND* the password ' being duplicated. That is, two users can have ' the same username or the same password, but not ' both. uc.Add("FrankSmith", "12345") Stop ' When the code gets to "Stop" above, execution ' will halt just like with a breakpoint. When it ' does, hover your mouse over the local variable ' "uc" and expand "InnerList". ' ' When you do, you'll see the ID (the string value ' of a GUID, actually), the user's UserName, then ' the HashValue that it generated from the ' password. ' ' Notice how very different the HashValue is even ' though the passwords are very similar. That's ' the way that a hash works: Even a small change ' in the source will generate a pretty large ' change in the result. ' Now I'll show you how you can remove a user: uc.Remove("FrankSmith", "123456") Stop ' Once again, hover your mouse over "uc" to ' confirm that it worked. ' The next part will save the data to a file that ' will be on your desktop. ' ' The file's name will be "Test.bin". When it ' stops, minimize (or stop) Visual Studio and go ' have a look. Try to open it and if nothing else, ' open the file with a text editor like NotePad: Dim desktop As String = _ Environment.GetFolderPath(Environment.SpecialFolder.Desktop) Dim filePath As String = _ IO.Path.Combine(desktop, "Test.bin") uc.Save(filePath) Stop ' Go have a look. ' Not a lot to see huh? ;-) ' For loading it back in, use the "Load" method: uc.Load(filePath) Stop ' Finally then, this is how you would test to see ' if a person's credentials are valid (i.e., that ' they're in the local data that's stored in the ' binary file): ' ' Use the ".IsValidUserPass" method: Dim testCredentials As Boolean = _ uc.IsValidUserPass("FrankSmith", "12345") Stop ' Hover your mouse over "testCredentials" above ' and you'll see the result as a boolean. ' ' Change what's being tested any way that you want ' and try it all again. ' ' This is a very simplistic little class library ' (fewer than 500 lines total), but for what you ' want, I think it does really well. ' ' Do note that the file is compressed and then ' encrypted using AES encryption. ' ' I won't tell you anything more about the ' encryption (including the key) for obvious ' reasons: It would then no longer be a secret, ' but you can get a good idea about it from ' something that I posted about a half-year ago: ' ' {The URL is too long for this - I'll post it in ' the forum instead} ' ' The links don't work as I've closed that site ' but if you want anything from it, let me know ' and I'll upload it again. ' ' ***** ' ' Nothing is impossible to break through, but I ' think you'll find that it's pretty tough to get ' to the data that's on the inside. ' ' :-) Catch ex As Exception MessageBox.Show(String.Format("An error occurred:{0}{0}{1}", _ vbCrLf, ex.Message), _ "Exception Thrown", _ MessageBoxButtons.OK, _ MessageBoxIcon.Warning) End Try End Sub End Class


    These are some of the screenshots described in the code above.

    When I first add the two users, this is what "uc" looks like when you hover your mouse over the variable:

    Notice please that the hash values are quite a bit different even though the input value (the passwords) are similar. Once I then remove one of those, you can verify that it worked:

    The way that you'd test if someone's data typed in matches what's on file is shown near the bottom of all of that. Hover your mouse over the variable and you'll see the result:

    If you open the binary file with NotePad, what do you suppose you'd see? Let's have a look:

    If you can make out much of anything there then you're a mutant and will go far in the world of computing!

    Lastly, the class diagram is shown below:

    One of these should surely fit the task at hand I hope. :)

    ***** EDIT *****

    I forgot the link:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/8222cb3e-99e7-48a7-9bfa-aa1cd913d9fa/binary-serializationdeserialization-a-library-to-compress-and-encrypt-the-data?forum=vbgeneral

    The links in that are no longer valid but let me know if you want it and I'll upload them.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    • Edited by Frank L. Smith Saturday, April 8, 2017 11:31 PM ...found and corrected an issue with the ID of the internal collection
    Saturday, April 8, 2017 5:50 PM