none
VB non-text parameter file RRS feed

  • Question

  • At present I have a text file where I keep my parameter information. On open my software looks at this file for the parameter info.

    I am looking to use a non-text parameter file, possibly encrypted so that a user cannot read the parameters, such as database name, IP address of services etc.

    Any ideas?

    Friday, September 15, 2017 1:56 PM

All replies

  • At present I have a text file where I keep my parameter information. On open my software looks at this file for the parameter info.

    I am looking to use a non-text parameter file, possibly encrypted so that a user cannot read the parameters, such as database name, IP address of services etc.

    Any ideas?

    John,

    One idea is to set up a serializable class and use an assembly that I use frequently:

    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

    It's a binary file that's both compressed and encrypted. I'd suggest that you have your program create an ApplicationData directory (which is tagged hidden by default) and put it in there.

    You might also want to set the class up as a Singleton considering that it's settings.


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

    Friday, September 15, 2017 2:16 PM
  • Thanks Frank,

    Will have a closer look. Looks promising.

    John

    Friday, September 15, 2017 2:19 PM
  • Thanks Frank,

    Will have a closer look. Looks promising.

    John

    Let me know if you need me to help you with it.

    The following is similar. I'm not using the assembly in this one (there's no real need here) but the class is set up as a Singleton and is serialized to/from a binary file in the ApplicationData directory:

    <Serializable()> _
    Public Class EFI_DisplayProps
        Private _showCreationDateTime As Boolean = True
        Private _showCreationDateTimeUTC As Boolean = True
        Private _showDirectoryPath As Boolean = True
        Private _showFileExtension As Boolean = True
        Private _showFilePath As Boolean = True
        Private _showFileSize As Boolean = True
        Private _showLastAccessDateTime As Boolean = True
        Private _showLastAccessDateTimeUTC As Boolean = True
        Private _showLastWriteDateTime As Boolean = True
        Private _showLastWriteDateTimeUTC As Boolean = True
    
        Private Shared _instance As EFI_DisplayProps = Nothing
    
        Private Sub New()
        End Sub
    
        Public Shared ReadOnly Property Instance As EFI_DisplayProps
            Get
                If _instance Is Nothing Then
                    _instance = New EFI_DisplayProps
                End If
    
                Return _instance
            End Get
        End Property
    
        Public Sub SaveToBinary()
    
            Try
                Utilities.CreateProgramDataFolder()
    
                Dim thisInstance As EFI_DisplayProps = Instance
    
                Dim fi As New FileInfo(Utilities.GridViewDisplayBinaryPath)
    
                If fi.Exists Then
                    fi.Delete()
                End If
    
                Utilities.SaveBinaryData(thisInstance, fi.FullName)
    
            Catch ex As Exception
                Throw
            End Try
    
        End Sub
    
        Public Sub LoadFromBinary()
    
            Try
                Dim fi As New FileInfo(Utilities.GridViewDisplayBinaryPath)
    
                If fi.Exists Then
                    Dim thisInstance As EFI_DisplayProps = Instance
    
                    Dim savedInstance As EFI_DisplayProps = DirectCast(Utilities.LoadBinaryData(fi.FullName), EFI_DisplayProps)
    
                    If savedInstance IsNot Nothing Then
                        thisInstance.ShowCreationDateTime = savedInstance.ShowCreationDateTime
                        thisInstance.ShowCreationDateTimeUTC = savedInstance.ShowCreationDateTimeUTC
                        thisInstance.ShowDirectoryPath = savedInstance.ShowDirectoryPath
                        thisInstance.ShowFileExtension = savedInstance.ShowFileExtension
                        thisInstance.ShowFilePath = savedInstance.ShowFilePath
                        thisInstance.ShowLastAccessDateTime = savedInstance.ShowLastAccessDateTime
                        thisInstance.ShowLastAccessDateTimeUTC = savedInstance.ShowLastAccessDateTimeUTC
                        thisInstance.ShowLastWriteDateTime = savedInstance.ShowLastWriteDateTime
                        thisInstance.ShowLastWriteDateTimeUTC = savedInstance.ShowLastWriteDateTimeUTC
                    End If
                End If
    
            Catch ex As Exception
                Throw
            End Try
    
        End Sub
    
        Public Property ShowCreationDateTime As Boolean
            Get
                Return _showCreationDateTime
            End Get
    
            Set(ByVal value As Boolean)
                _showCreationDateTime = value
            End Set
        End Property
    
        Public Property ShowCreationDateTimeUTC As Boolean
            Get
                Return _showCreationDateTimeUTC
            End Get
    
            Set(ByVal value As Boolean)
                _showCreationDateTimeUTC = value
            End Set
        End Property
    
        Public Property ShowDirectoryPath As Boolean
            Get
                Return _showDirectoryPath
            End Get
    
            Set(ByVal value As Boolean)
                _showDirectoryPath = value
            End Set
        End Property
    
        Public Property ShowFileExtension As Boolean
            Get
                Return _showFileExtension
            End Get
    
            Set(ByVal value As Boolean)
                _showFileExtension = value
            End Set
        End Property
    
        Public Property ShowFilePath As Boolean
            Get
                Return _showFilePath
            End Get
    
            Set(ByVal value As Boolean)
                _showFilePath = value
            End Set
        End Property
    
        Public Property ShowFileSize As Boolean
            Get
                Return _showFileSize
            End Get
    
            Set(ByVal value As Boolean)
                _showFileSize = value
            End Set
        End Property
    
        Public Property ShowLastAccessDateTime As Boolean
            Get
                Return _showLastAccessDateTime
            End Get
    
            Set(ByVal value As Boolean)
                _showLastAccessDateTime = value
            End Set
        End Property
    
        Public Property ShowLastAccessDateTimeUTC As Boolean
            Get
                Return _showLastAccessDateTimeUTC
            End Get
    
            Set(ByVal value As Boolean)
                _showLastAccessDateTimeUTC = value
            End Set
        End Property
    
        Public Property ShowLastWriteDateTime As Boolean
            Get
                Return _showLastWriteDateTime
            End Get
    
            Set(ByVal value As Boolean)
                _showLastWriteDateTime = value
            End Set
        End Property
    
        Public Property ShowLastWriteDateTimeUTC As Boolean
            Get
                Return _showLastWriteDateTimeUTC
            End Get
    
            Set(ByVal value As Boolean)
                _showLastWriteDateTimeUTC = value
            End Set
        End Property
    End Class

    The ApplicationData directory is set up using this:

        Friend NotInheritable Class Utilities
            Private Sub New()
            End Sub
    
            Public Shared ReadOnly ProgramDataFolderPath As String = _
                Combine(GetFolderPath(SpecialFolder.ApplicationData), _
                        My.Application.Info.AssemblyName)
    
            Public Shared ReadOnly GridViewDisplayBinaryPath As String = _
                Combine(ProgramDataFolderPath, "GridViewDisplay.bin")
    
            Public Shared Sub CreateProgramDataFolder()
    
                Try
                    Dim di As New DirectoryInfo(ProgramDataFolderPath)
    
                    If Not di.Exists Then
                        di.Create()
                    End If
    
                Catch ex As Exception
                    Throw
                End Try
    
            End Sub
        End Class


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


    Friday, September 15, 2017 2:26 PM
  • Tried loading the files and it gave me a problem

    Friday, September 15, 2017 2:26 PM
  • Tried loading the files and it gave me a problem

    I don't know. I updated that not too long ago.

    When you open the solution in VisualStudio, is that when you got that? Did it ever prompt you to convert it to your version?


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

    Friday, September 15, 2017 2:31 PM
  • Hi Frank,

    Maybe you can help me through an example.

    I need access to the database number say "2"

    and a URL such as "http://111.111.11.11/Service.abc"

    Can you please point out where in you code I would be able to put and get this data?

    Thanks,John

    Friday, September 15, 2017 2:36 PM
  • I got the error when I double clicked on the .sln

    Did not prompt me to convert.

    Friday, September 15, 2017 2:38 PM
  • I got the error when I double clicked on the .sln

    Did not prompt me to convert.

    I don't know. I downloaded it myself, extracted it and opened it fine. I then ran it.

    By the way, this is the result if someone opens it with NotePad:

    If they recognize it as a zip file - which is what it is - trying to open with a compression program like WinZip won't cooperate: It's internally encrypted.

    *****

    If you want, I'll just write it for you and that might be the best example yet.

    You have two fields it looks like? Give me a name and type for each entry that you want persisted. Also, give me a name to use for the class please?


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

    Friday, September 15, 2017 2:45 PM
  • Hi Frank,

    I have a text file whose content looks like the following. For each user this will specify the name of the database and other information that is used. At present there are 5 lines. In the future there may be more

    Server=.;Initial Catalog=1;Trusted_Connection=Yes;
    DB = 2
    http://50.160.252.87/VDWS/Service.asmx
    http://50.160.252.87/VDFILE/FileUploader.asmx
    http://www.VisualDentist.com.cy/SmsWebService/SmsWebService.asmx

    I need to be able to GET the contents of each line as a string, that is

       String1   "Server=.;Initial Catalog=1;Trusted_Connection=Yes;"

       String2   "2"

       String3   "http://50.160.252.87/VDWS/Service.asmx"

       String4   "http://50.160.252.87/VDFILE/FileUploader.asmx"

       String5   "http://www.VisualDentist.com.cy/SmsWebService/SmsWebService.asmx"

    I also need to be able to SET the contents in the same manner

    The Class may be called clsUserValidation

    Many thanks in advance.

    John


    • Edited by JohnPapa05 Saturday, September 16, 2017 1:19 PM
    Saturday, September 16, 2017 1:00 PM
  • John,

    I'm having some internet connection issues so don't think anything if I'm long in replying back.

    *****

    The fact that it has to be able to be freely added to later (or did that requirement change?), what we might do is to create a collection class and I'll build a Save and Load method in it. The data will be saved using the CAE assembly that we talked about yesterday.

    The issue would be how would you know which "entry" you wanted though? The entry number?

    If you don't need it to be modifiable then tell me the names to use. String1 through String5? If you think you might add to it though, let's do that on the front end with a collection.

    Hopefully my internet will last long enough that I can send this!

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

    Saturday, September 16, 2017 1:49 PM
  • Frank, your Internet lasted long enough..

    String1 to String 5 is fine.

    Just to help a bit, I intend to use the contents of this binary file to allow the user to connect to the correct database and also provide other functionality, such as the url for sending sms messages. If for example, the user needs to connect to db = 2 then the number 2 will appear in the db. If the user needs to connect to db = 3 and so on.

    At the end of the day I need to be able to read this binary file and extract the various lines in strings, which I later manipulate.

    So it would be nice if there was an easy way to change to db number or in general edit the file.

    John

    PS I need to automate the process, that is why editing/creating the file is a good idea.


    • Edited by JohnPapa05 Saturday, September 16, 2017 2:15 PM
    Saturday, September 16, 2017 2:14 PM
  • John,

    Do you not want a way to add to it though? I can do that pretty easily - it's just a different way than I'd originally talked about is all.

    The ability to edit it isn't a problem. Would you ever need to delete an entry though? If so, how would you want the name (String 3, for example) to be treated? Just skip it?

    I think you'll like it better if I give you the ability to have as many as you want. I just need something to be unique per entry so that the class will know which one you mean. "String 3" is fine if you want, or just the number as an Int32? The number will be smaller to store and faster to work with (although it'll be plenty fast unless you were in the hundreds of thousands).


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

    Saturday, September 16, 2017 2:21 PM
  • Frank,

    It would be great if I can add to it.

    Deleting would not be a great problem. There will be a few entries only and it may be good to know what was available before.

    All entries will be unique

    Thanks,
    John

    Saturday, September 16, 2017 3:06 PM
  • Frank,

    It would be great if I can add to it.

    Deleting would not be a great problem. There will be a few entries only and it may be good to know what was available before.

    All entries will be unique

    Thanks,
    John

    I've gotten started on it but I didn't want to take it too far until I showed you so that if it's not what you want then I'll change it.

    I'm putting this whole thing together as a class library (a .dll file) which will have the CAE assembly embedded inside it. I'm doing that also so that I can obfuscate parts of it so that even if someone pulls apart my assembly with a disassembler, some parts of it (like where it's saved and what's being saved and how it's being saved) still won't be exposed.

    Anyway, moving ahead: It's based on collection class so there's a nested class in the main one. The nested class ("CollectionItems") is where the actual data is and the main class has methods that work with that nested class:

    I'm just starting on it, and "Save" and "Load" are empty right now. You might notice above what the data consists of: A read-only property named "EntryNumber" which is an Integer and a string property named "Info". Info isn't read-only but the setter has the Friend modifier so only the main class can change it; you can't change it from outside the assembly.

    The method named "Modify" will do that though.

    Notice also that in the main class, there's a read-only property named "LastEntryNumber" and I'll explain that forthwith:

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Imports JP_UserValidation.Data
    
    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            Dim userData As New clsUserValidation
    
            With userData
                .Add("Server=.;Initial Catalog=1;Trusted_Connection=Yes;")
                .Add("DB = 2")
                .Add("http://50.160.252.87/VDWS/Service.asmx")
                .Add("http://50.160.252.87/VDFILE/FileUploader.asmx")
                .Add("http://www.VisualDentist.com.cy/SmsWebService/SmsWebService.asmx")
            End With
    
            Stop
    
            Dim sb As New System.Text.StringBuilder
    
            For i As Integer = 0 To userData.Count - 1
                sb.AppendLine(userData(i).ToString)
    
                If i < userData.Count - 1 Then
                    sb.AppendLine()
                    sb.AppendLine("----------")
                    sb.AppendLine()
                End If
            Next
    
            MessageBox.Show(sb.ToString)
    
            Stop
    
        End Sub
    End Class
    

    When it gets to the first "Stop", I hover my mouse over and expand "userData":

    You can see the information that it has in there. Just as a quick check, the next part uses .ToString and I take that and put it into a StringBuilder so I can see it:

    Now: This is what I was talking about when I asked what should happen if you delete an entry. I'm persisting the "LastEntryNumber" and that's used for the assignment. If I were to delete the third entry, for example, what would be remaining would be 1,2,4 and 5. If I then added a new one, it would 6. 3 is forever gone - not reused.

    How does that sound so far?


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

    Saturday, September 16, 2017 3:27 PM
  • A bit overwhelmed.

    Can we simplify matters? What do I need to add in my code. Once it is working we can go back and understand the logic.

    Thanks,

    John

    Saturday, September 16, 2017 3:37 PM
  • A bit overwhelmed.

    Can we simplify matters? What do I need to add in my code. Once it is working we can go back and understand the logic.

    Thanks,

    John


    I thought I was making it easier on you, not harder. All you'd need to do would be to use it, but if you want then I'll leave the class to you and give you a link to the CAE assembly?

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

    Saturday, September 16, 2017 3:40 PM
  • If I have a brand new project which project do I include?
    Saturday, September 16, 2017 3:44 PM
  • If I have a brand new project which project do I include?

    You'll add a reference to the assembly. When you build your project, my .dll file will be in the output so be sure to include that in what you distribute. Other than that, just use it.

    *****

    Give me a half-hour or so to continue setting it up then we can talk about it. I'll show the code here if you want.

    Be patient please...


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

    Saturday, September 16, 2017 3:48 PM
  • OK have to leave in a second. We can continue tomorrow if available.

    Using a dll would be a problem. Need the actual code to proceed.

    Thanks,

    John

    Saturday, September 16, 2017 3:52 PM
  • Using a dll would be a problem. Need the actual code to proceed.

    The CAE assembly is just that: A .dll file.

    I'm not willing to expose how it works; it's free if you want it but I won't show the code for it (it wouldn't be very secure if I showed how it works on a public worldwide website).

    I thought you understood that yesterday but I guess not.

    Sorry I couldn't help.


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

    Saturday, September 16, 2017 3:57 PM
  • Frank

    I really appreciate your help. I was unaware that there was a dll involved.

    In our software we have no third party dlls. Just to give you an idea, we created a calendar out of textboxes because we did not want to rely on say Microsoft's calendar.

    Thanks again,

    John

    Saturday, September 16, 2017 4:03 PM
  • Frank

    I really appreciate your help. I was unaware that there was a dll involved.

    In our software we have no third party dlls. Just to give you an idea, we created a calendar out of textboxes because we did not want to rely on say Microsoft's calendar.

    Thanks again,

    John

    The BCL itself comes down to a bunch of .dll files. I don't understand your rationale there but to each their own.

    I'll add this though: Now that you're into security, consider a good obfuscator. It's very easy to pull apart a dotNet program.

    Embarrasingly easy! ;-)


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


    • Edited by Frank L. Smith Saturday, September 16, 2017 4:08 PM ...typo
    Saturday, September 16, 2017 4:08 PM
  • Frank

    I really appreciate your help. I was unaware that there was a dll involved.

    In our software we have no third party dlls. Just to give you an idea, we created a calendar out of textboxes because we did not want to rely on say Microsoft's calendar.

    Thanks again,

    John

    I know that you said "non-text based" but just in case this might help:

    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 originalText As String = "The rain in Spain"
            Const password As String = "NotVerySecure"
    
            Dim encText As String = AES_Encrypt(originalText, password)
    
            Stop
    
            Dim decText As String = AES_Decrypt(encText, password)
    
            Stop
    
        End Sub
    
    
    
        Private Function AES_Encrypt(ByVal input As String, ByVal pass As String) As String
            Dim AES As New System.Security.Cryptography.RijndaelManaged
            Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
            Dim encrypted As String = ""
    
            Dim hash(31) As Byte
            Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass))
            Array.Copy(temp, 0, hash, 0, 16)
            Array.Copy(temp, 0, hash, 15, 16)
            AES.Key = hash
            AES.Mode = Security.Cryptography.CipherMode.ECB
            Dim DESEncrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateEncryptor
            Dim Buffer As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(input)
            encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
            Return encrypted
            
        End Function
    
    
    
        Private Function AES_Decrypt(ByVal input As String, ByVal pass As String) As String
            Dim AES As New System.Security.Cryptography.RijndaelManaged
            Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
            Dim decrypted As String = ""
    
            Dim hash(31) As Byte
            Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass))
            Array.Copy(temp, 0, hash, 0, 16)
            Array.Copy(temp, 0, hash, 15, 16)
            AES.Key = hash
            AES.Mode = Security.Cryptography.CipherMode.ECB
            Dim DESDecrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateDecryptor
            Dim Buffer As Byte() = Convert.FromBase64String(input)
            decrypted = System.Text.ASCIIEncoding.ASCII.GetString(DESDecrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
            Return decrypted
           
        End Function
    
    End Class


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

    Saturday, September 16, 2017 4:46 PM
  • Thanks Frank,

    It reminded me that I have encrypt/decrypt code in my project, which is used when data is moved back and forth to the cloud. I will look into your solution as well.

    Maybe after it is encrypted/descrypted it can be converted to a non ascii file.

    John

    Sunday, September 17, 2017 7:53 AM
  • Maybe after it is encrypted/descrypted it can be converted to a non ascii file.

    What encryption are you using?   Encrypted data is usually written to files as plain text, using standard text read/write procedures.  If you want to write multiple 'records' to one file you need a way of separating the records, and as you are writing encrypted text the usual techniques (eg, newline) might not work.  But it depends on the encryption you are using.  Converting binary data to plain text (if necessary) and writing to text files using newline delimiters is the common procedure.

    Sunday, September 17, 2017 8:06 AM
  • For encryption I use something like the following. It uses CryptoStream to write. I can create a class with all the settings. Is there any sense in encrypting more than once, with a different encryption key?

        Public Function fungEncrypt(strUnencrypted As String) As String
            Dim strEncrypted As String
            Dim strEncryptionKey As String = "A weak key"
            Dim aryClearBytes As Byte() = Encoding.Unicode.GetBytes(strUnencrypted)
            Using encryptor As Aes = Aes.Create()
                Dim pdb As New Rfc2898DeriveBytes(strEncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, _
                 &H65, &H64, &H76, &H65, &H64, &H65, &H76})
                encryptor.Key = pdb.GetBytes(32)
                encryptor.IV = pdb.GetBytes(16)
                Using ms As New MemoryStream()
                    Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
                        cs.Write(aryClearBytes, 0, aryClearBytes.Length)
                        cs.Close()
                    End Using
                    strEncrypted = Convert.ToBase64String(ms.ToArray())
                End Using
            End Using
            Return strEncrypted
        End Function

    Sunday, September 17, 2017 8:54 AM
  • Using a dll would be a problem. Need the actual code to proceed.

    Ok, this will do what you want.

    Creating a binary file isn't difficult; a binary serializer is in the dotNET library and works pretty well. There is an issue with the out-of-the-box serializer though: It stores text as text ... no changes at all.

    In fact, when I originally set out to create what became my CAE assembly, encryption never was part of the scheme; I was doing it so that I could get compression and in doing that, the zip format itself pretty well hides it. I later added AES encryption because it was easy to do.

    Back to this though, can I store the data "encrypted" and leave the "un-encrypted" version for you to use?

    Yes - a few ways. One way would be to have both in the class and per "un-encrypted" backing field, tag it with the <NonSerialized()> attribute. I thought about doing that, but I like this idea better: Let the Setter and Getter take care of it.

    The following does just that. It's long because of what all is in it, but there's no outside assembly doing this; it'll all be baked into your program's code:

    Option Strict On Option Explicit On Option Infer Off Imports System.IO Imports System.IO.Path Imports System.Environment Imports System.Runtime.Serialization.Formatters.Binary Public Class Form1 Private _userData As clsUserValidation Private Sub _ Form1_Load(sender As System.Object, _ e As System.EventArgs) _ Handles MyBase.Load _userData = clsUserValidation.Instance _userData.LoadFromBinary() Stop ' John, ' ' On the second run through, comment the following ' line of code out so that you know that it's ' loaded the information from the binary file ' that's in the ApplicationData directory. SetDataAndSave() Stop ShowInfo() End Sub Private Sub SetDataAndSave() With _userData .String01 = "Server=.;Initial Catalog=1;Trusted_Connection=Yes;" .String02 = "DB = 2" .String03 = "http://50.160.252.87/VDWS/Service.asmx" .String04 = "http://50.160.252.87/VDFILE/FileUploader.asmx" .String05 = "http://www.VisualDentist.com.cy/SmsWebService/SmsWebService.asmx" End With _userData.SaveToBinary() End Sub Private Sub ShowInfo() Dim sb As New System.Text.StringBuilder With sb .AppendLine("String 01: " & _userData.String01) .AppendLine("String 02: " & _userData.String02) .AppendLine("String 03: " & _userData.String03) .AppendLine("String 04: " & _userData.String04) .Append("String 05: " & _userData.String05) MessageBox.Show(sb.ToString, "The Information Isn't Encrypted When You Use It") End With End Sub End Class <Serializable()> _ Public Class clsUserValidation Private _string01 As String Private _string02 As String Private _string03 As String Private _string04 As String Private _string05 As String Private Shared _instance As clsUserValidation = Nothing Private Sub New() End Sub Public Shared ReadOnly Property Instance As clsUserValidation Get If _instance Is Nothing Then _instance = New clsUserValidation End If Return _instance End Get End Property Public Sub SaveToBinary() Try Utilities.CreateProgramDataFolder() Dim fi As New FileInfo(Utilities.UserValidationBinaryPath) If fi.Exists Then fi.Delete() End If Utilities.SaveBinaryData(_instance, fi.FullName) Catch ex As Exception Throw End Try End Sub Public Sub LoadFromBinary() Try Dim fi As New FileInfo(Utilities.UserValidationBinaryPath) If fi.Exists Then Dim thisInstance As clsUserValidation = _instance Dim savedInstance As clsUserValidation = DirectCast(Utilities.LoadBinaryData(fi.FullName), clsUserValidation) If savedInstance IsNot Nothing Then thisInstance._string01 = savedInstance._string01 thisInstance._string02 = savedInstance._string02 thisInstance._string03 = savedInstance._string03 thisInstance._string04 = savedInstance._string04 thisInstance._string05 = savedInstance._string05 End If End If Catch ex As Exception Throw End Try End Sub Public Property String01 As String Get Using s3d As New Simple3Des Return s3d.DecryptData(_string01) End Using End Get Set(ByVal value As String) If value Is Nothing Then _string01 = Nothing Else Using s3d As New Simple3Des _string01 = s3d.EncryptData(value) End Using End If End Set End Property Public Property String02 As String Get Using s3d As New Simple3Des Return s3d.DecryptData(_string02) End Using End Get Set(ByVal value As String) If value Is Nothing Then _string02 = Nothing Else Using s3d As New Simple3Des _string02 = s3d.EncryptData(value) End Using End If End Set End Property Public Property String03 As String Get Using s3d As New Simple3Des Return s3d.DecryptData(_string03) End Using End Get Set(ByVal value As String) If value Is Nothing Then _string03 = Nothing Else Using s3d As New Simple3Des _string03 = s3d.EncryptData(value) End Using End If End Set End Property Public Property String04 As String Get Using s3d As New Simple3Des Return s3d.DecryptData(_string04) End Using End Get Set(ByVal value As String) If value Is Nothing Then _string04 = Nothing Else Using s3d As New Simple3Des _string04 = s3d.EncryptData(value) End Using End If End Set End Property Public Property String05 As String Get Using s3d As New Simple3Des Return s3d.DecryptData(_string05) End Using End Get Set(ByVal value As String) If value Is Nothing Then _string05 = Nothing Else Using s3d As New Simple3Des _string05 = s3d.EncryptData(value) End Using End If End Set End Property End Class Public NotInheritable Class Simple3Des Implements IDisposable Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider Public Sub New() ' Initialize the crypto provider. ' ===== CHANGE THIS BEFORE YOU USE IT!! ===== Dim key As String = "YourPasswordHere" ' =========================================== TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) 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 Public NotInheritable Class Utilities Private Sub New() End Sub Public Shared ReadOnly ProgramDataFolderPath As String = _ Combine(GetFolderPath(SpecialFolder.ApplicationData), _ My.Application.Info.AssemblyName) Public Shared ReadOnly UserValidationBinaryPath As String = _ Combine(ProgramDataFolderPath, "UV.bin") Public Shared Sub CreateProgramDataFolder() Try Dim di As New DirectoryInfo(ProgramDataFolderPath) If Not di.Exists Then di.Create() End If Catch ex As Exception Throw End Try End Sub ''' <summary> ''' A method to serialize an object and save it to a binary file. ''' </summary> ''' <param name="data">The data to serialize.</param> ''' <param name="filePath">The full filepath where this binary file is to be saved to.</param> ''' <remarks></remarks> Public Shared Sub SaveBinaryData(ByVal data As Object, _ ByVal filePath As String) Try Using fs As New FileStream(filePath, FileMode.Create) Dim formatter As New BinaryFormatter formatter.Serialize(fs, data) End Using Catch ex As Exception Throw End Try End Sub ''' <summary> ''' A method to serialize an object (binary) into a MemoryStream which is then returned. ''' </summary> ''' <param name="data">The data to serialize.</param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function SaveBinaryData(ByVal data As Object) _ As MemoryStream Dim retVal As MemoryStream Try Dim ms As New MemoryStream Dim formatter As New BinaryFormatter formatter.Serialize(ms, data) retVal = ms Catch ex As Exception retVal = Nothing Throw End Try Return retVal End Function ''' <summary> ''' A method to load a binary file which was serialized using the ''' "SaveBinaryData" method into an object which is returned. ''' </summary> ''' <param name="filePath">The full filepath where this binary file is to be loaded from.</param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function LoadBinaryData(ByVal filePath As String) _ As Object Dim retVal As Object = Nothing Try Using fs As New FileStream(filePath, FileMode.Open) Dim formatter As New BinaryFormatter() retVal = formatter.Deserialize(fs) End Using Catch ex As Exception retVal = Nothing Throw End Try Return retVal End Function ''' <summary> ''' A method to load binary data from a MemoryStream into an object which is then returned. ''' </summary> ''' <param name="ms">The MemoryStream containing the serialized data.</param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function LoadBinaryData(ByVal ms As MemoryStream) _ As Object Dim retVal As Object = Nothing Try Dim formatter As New BinaryFormatter() retVal = formatter.Deserialize(ms) Catch ex As Exception retVal = Nothing Throw End Try Return retVal End Function End Class


    Notice how the getters will decrypt the strings "on the fly" and likewise, the setters will first check that the string isn't empty null and if not, will encrypt the string data. If it's null that's not a problem with serialization; it handles that safely.

    You can see in my example that I set the strings to what you showed Friday. If you'll run it, you'll notice that it's no different than any other (other than that it's set up as a Singleton) but on the outside, what would someone see if they found that binary file and opened it with NotePad or similar?

    I copied it, changed the file extension to .txt and uploaded it. Have a look and see what they'll see:

    http://www.fls-online.net/VBNet_Forum/09-17-17/UV.txt

    So the data is safe, it's binary, and you don't have to change how you'd normally work with it.

    On your end, it's just a class like any other:

    Give that a go and hopefully this gets you what you want. :)


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


    • Edited by Frank L. Smith Sunday, September 17, 2017 12:44 PM ...reworded: An empty string can be encrypted but a null string cannot.
    Sunday, September 17, 2017 12:37 PM
  • Came up with the following

    <Serializable>
    Public Class clsSetting
        Public Property strConnection As String
        Public Property strDatabase As String
        Public Property strWebService As String
        Public Property strUploader As String
        Public Property strSMS As String
    
        ' add anything else to be encrypted
    End Class
    
    
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim SvrData As clsSetting = New clsSetting
            Dim password As String = "AnyPassword"
            Dim key As Byte() = System.Text.Encoding.UTF8.GetBytes(password)
            Dim iv(15) As Byte
    
            SvrData.strConnection = "String1"
            SvrData.strDatabase = "String2"
            SvrData.strWebService = "String3"
            SvrData.strUploader = "String4"
            SvrData.strSMS = "String5"
    
            Using rng As New RNGCryptoServiceProvider
                rng.GetNonZeroBytes(iv)
            End Using
    
            Using rijAlg = Rijndael.Create()
                rijAlg.Padding = PaddingMode.ISO10126
    
                ' USING encryptor AND filestream
                Using encryptor As ICryptoTransform = rijAlg.CreateEncryptor(key, iv),
                    fs As New FileStream(Application.StartupPath + "\init.bin",
                                         FileMode.OpenOrCreate Or FileMode.Truncate)
                    ' save iv to "naked" filestream
                    fs.Write(iv, 0, iv.Length)
                    Using cs As New CryptoStream(fs, encryptor, CryptoStreamMode.Write)
                        Dim bf As New BinaryFormatter
                        bf.Serialize(cs, SvrData)
                        ' may not be needed - doesnt hurt
                        cs.FlushFinalBlock()
                    End Using
                End Using
            End Using
    
            Using rijAlg = Rijndael.Create()
                rijAlg.Padding = PaddingMode.ISO10126
    
                Using fs As New FileStream(Application.StartupPath + "\init.bin", FileMode.Open)
                    ' read the IV first
                    fs.Read(iv, 0, iv.Length)
                    ' USING encryptor AND CryptoStream
                    Using encryptor As ICryptoTransform = rijAlg.CreateDecryptor(key, iv),
                        cs As New CryptoStream(fs, encryptor, CryptoStreamMode.Read)
                        Dim bf As New BinaryFormatter
                        SvrData = CType(bf.Deserialize(cs), clsSetting)
                    End Using
                End Using
            End Using
    
            ' test if the data made the round trip:
            Dim s1 As String = SvrData.strConnection
            Dim s2 As String = SvrData.strDatabase
            Dim s3 As String = SvrData.strWebService
            Dim s4 As String = SvrData.strUploader
            Dim s5 As String = SvrData.strSMS
    
        End Sub
    

    Sunday, September 17, 2017 1:56 PM
  • John,

    That's the same concept as what I came up with. Mine is doing it differently but if that works for you then that's great. :)

    I'll make a comment though: The location where you're storing it might be a problem. Consider using the ApplicationData directory or any of a number of other places that are available to us:

    https://www.codeproject.com/Tips/370232/Where-should-I-store-my-data


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

    Sunday, September 17, 2017 2:12 PM