encrypting/decrypting a password stored on a compact database - vb.net

My project contains 2 forms, one to register users and one to login. I am using a compact local database to store the passwords. I wrote a function to encrypt the password when the user registers. I then wrote another to decrypt the same password when the user logs in.
The first part, encryption, works just fine. The user registers, and I can see the password encrypted on the database. However, when I try to log in, the password is not being decrypted. Here are my Functions.
Module EncryptionModule
Public Function base64Encode(ByVal sData As String) As String
Try
Dim encData_Byte As Byte() = New Byte(sData.Length - 1) {}
encData_Byte = System.Text.Encoding.UTF8.GetBytes(sData)
Dim encodedData As String = Convert.ToBase64String(encData_Byte)
Return (encodedData)
Catch ex As Exception
Throw (New Exception("Error is base64Encode" & ex.Message))
End Try
End Function
Public Function base64Decode(ByVal sData As String) As String
Dim encoder As New System.Text.UTF8Encoding()
Dim utf8Decode As System.Text.Decoder = encoder.GetDecoder()
Dim todecode_byte As Byte() = Convert.FromBase64String(sData)
Dim charCount As Integer = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length)
Dim decoded_char As Char() = New Char(charCount - 1) {}
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0)
Dim result As String = New [String](decoded_char)
Return result
End Function
End Module
This is the routine to register a user and encrypting the password:
Private Sub btnRegister_Click(sender As Object, e As EventArgs) Handles btnRegister.Click
'If the username is taken or used on the
'database, then create account
If MasterTableAdapter.CheckUserName(txtUserName.Text) = Nothing Then
Dim pwd As String = base64Encode(Trim(txtConfirmPassword.Text))
MasterTableAdapter.CreateAccount(txtFName.Text, txtLName.Text, txtUserName.Text, pwd, int1)
MsgBox("An account has been created for: " & vbNewLine & _
"Employee: " & txtFName.Text & " " & txtLName.Text & vbNewLine & _
"User Name: " & txtUserName.Text & vbNewLine & _
"Access Level: " & strAccessLevel)
Me.Close()
Else
MessageBox.Show("The username is in use. Please select another username.", "Authentication Error", MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End If
End Sub
Here is the routine to log in and decrypt the password from the Login Form:
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
Dim pwd As String = base64Decode(Trim(txtPassword.Text))
If Not MasterTableAdapter.Login(txtUserName.Text, pwd) = Nothing Then
'frmWelcomePage.Show()
MsgBox("SUCCESS")
Else
'If no match, display error, clear text boxes and send focus back to the username text box.
MessageBox.Show("Username or password do not match", "Authentication Failure", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtPassword.Text = Nothing
txtUserName.Text = Nothing
txtUserName.Focus()
End If
End if
End Sub
I am new to the whole encryption arena so I don't know what I am doing wrong here.

You shouldn't decrypyt the password.
When the user creates a password, you should generate a hash (ie: a value from which the password can not be reconstructed)
When the user attempts to login, you should compare the hash value of the given password with the stored hash.

First, Base64 encoding is not encryption. Many people can look at a B64 string and know what to do to unscramble it. You should look into hash techniques as podiluska suggested.
That said, since your Decode method cant unscramble what you encode, it means you have an error in one or the other. Simple encoding for what you are doing can be done:
Dim s As String = "MySecretPassword"
' convert to byte array
Dim bArry() As Byte = System.Text.Encoding.UTF8.GetBytes(s)
' convert bytes to Base64:
Dim sb64 As String = System.Convert.ToBase64String(barry)
To decode is just the reverse:
' Base64 -> Byte Array
Dim bOut() As Byte = System.Convert.FromBase64String(sb64)
' Byte Arry -> clear text
Dim sOut As String = System.Text.Encoding.UTF8.GetString(bOut)

Related

Checks The Informations In Text File. VB.NET

I work on a project "SignInLogeIn" using Visual Basic.NET.
I save the user informations in text file.
the name of the file is "data.txt".
to create a new account in my program. you must enter the name,email,password and the program write the informations in textfile.
i use "Streamwritter" to write the informations.
when user create a new account The program checks if the email entered by the user is already in the text file that contains the users' information.
and the program checks from informations by "StreamReader". it reads the information in text file and checks.
I have the problem.
when I CREATE A new account. problem appears.
and the problem is
"
An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll
Additional information: The process cannot access the file 'D:\1- Anas Files\Projects\VisualBasic.NET\SignInLogIn\SignInLogIn\SignInLogIn\bin\Debug\Data.txt' because it is being used by another process.
"
I think the problem is that I used the file twice
Once to write and once to read.
The error occurs in this line "Dim sw As New StreamWriter("Data.txt")".
how can i solve this problem ?
this is the code of "SignIn" button
Private Sub btnSignIn_Click(sender As Object, e As EventArgs) Handles btnSignIn.Click
Dim strEmail As String = txtEmail.Text
Dim Reg As New Regex("^\w+([-_.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*$")
If txtUserName.Text.Trim() = "" Or txtEmail.Text.Trim() = "" Or txtPassword.Text.Trim() = "" Then
MsgBox("Please Enter All Input")
If Not Reg.IsMatch(strEmail) Then
MsgBox("Please Enter Email")
End If
Else
Dim sr As New StreamReader("Data.txt")
Dim sw As New StreamWriter("Data.txt")
Dim strPerson As String = txtUserName.Text & ";" & txtEmail.Text & ";" & txtPassword.Text
Dim line As String = ""
Do
line = sr.ReadLine()
Dim arrData As String() = line.Split(";")
If arrData(1) = strEmail Then
MsgBox("Please Change Email")
Else
sw.WriteLine(strPerson)
sw.Close()
End If
Loop While line <> Nothing
sr.Close()
End If
End Sub
You open twice the same file. First, to read and second to write, this is why you cannot write.
Dim sr As New StreamReader("Data.txt")
Dim lines As String = sr.ReadToEnd().Split(Environment.NewLine)
sr.Close()
Dim strPerson As String = txtUserName.Text & ";" & txtEmail.Text & ";" & txtPassword.Text
Dim sw As New StreamWriter("Data.txt")
For Each line As String In lines
Dim arrData As String() = line.Split(";")
If arrData(1) = strEmail Then
MsgBox("Please Change Email")
Exit For
Else
sw.WriteLine(strPerson)
Exit For
End If
Next
sw.Close()
Streams need to be closed and disposed. They are usually put in Using blocks.
I wasn't quite sure of the program flow you wanted. It seemed, since you created a writer and a reader you intended to add to user to the file if they were not listed.
I broke out some of the code into separate methods. I used System.IO since we have a simple text file.
Private Sub btnSignIn_Click(sender As Object, e As EventArgs) Handles btnSignIn.Click
If ValidInput() Then
Dim strPerson As String = $"{txtUserName.Text};{txtEmail.Text};{txtPassword.Text}"
If Not IsUserInFile(strPerson) Then
File.AppendAllText("Data.txt", strPerson & Environment.NewLine)
End If
End If
End Sub
Private Function ValidInput() As Boolean
Dim strEmail As String = txtEmail.Text
Dim Reg As New Regex("^\w+([-_.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*$")
If txtUserName.Text.Trim() = "" OrElse txtEmail.Text.Trim() = "" OrElse txtPassword.Text.Trim() = "" Then
MsgBox("Please Enter All Input")
Return False
If Not Reg.IsMatch(strEmail) Then
MsgBox("Please Enter Email")
Return False
End If
End If
Return True
End Function
Private Function IsUserInFile(Person As String) As Boolean
Dim p = Person.Split(";"c)
Dim lines = File.ReadAllLines("Data.txt")
For Each line In lines
If Person = line Then
Return True
End If
Dim fields = line.Split(";"c)
If fields(0) = p(0) AndAlso fields(2) = p(2) AndAlso fields(1) <> p(1) Then
MessageBox.Show("Please Change Email")
Return False
End If
Next
Return False
End Function
This is going to get messy and slow if there are too many users. This info should really be in a database. The worst thing is the passwords should always be salted and hashed; never stored as plain text even is a database.

How to avoid following "If" conditions if the first "If" is true

I want to make my first If to stop at "Incorrect user and password", but it goes to the second and third If saying "incorrect user" and "incorrect password" after "incorrect user and password".
Public Class Form1
Dim numAttempts As Double = 0
Private Sub btnok_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnok.Click
Dim User As String = "ShaoHecc"
Dim Password As String = "daedric123"
Dim loginuser As String
Dim loginpassword As String
Dim wrong As String = False
loginpassword = Val(txtpass.Text)
loginuser = Val(txtuser.Text)
txtpass.Text = loginpassword
txtuser.Text = loginuser
If txtuser.Text = User And
txtpass.Text = Password Then
MessageBox.Show("Access Granted!")
ElseIf txtuser.Text = loginuser And
txtpass.Text = loginpassword Then
MessageBox.Show("Username and Password incorrect, " & numAttempts & " / 3 attempts left")
End If
If txtuser.Text = User = False Then
MessageBox.Show("Username incorrect, you have " & numAttempts & " / 3 attempts left.")
txtuser.Text = Nothing
End If
If txtpass.Text = Password = False Then
MessageBox.Show("Password incorrect, you have " & numAttempts & " / 3 attempts left.")
txtpass.Text = Nothing
End If
If numAttempts = 3 Then
MessageBox.Show("Maxiumum number attempts reached, you have been denied access.")
Application.Exit()
Else
numAttempts = numAttempts + 1
End If
End Sub
End Class
You have far too much code there than what is needed.
You are also using legacy VB6 code where it is not needed.
You appear to have no idea of variables and variable types.
Let me explain a little... Let's work backwards...
Variable types, of which there are many, each are required and/or recommended for a particular task. In your example you have a numAttempts which is used to count the failed attempts, however, you have it as a Double >>> Dim numAttempts As Double, it's wrong and wasteful, just use a standard Integer for a whole number in this situation. This is also of interest: Dim wrong As String = False. There are two things fundamentally wrong here. A string is Text, which means it should always have quotes surrounding the text >>> Dim wrong As String = "False". However, using something to test for True or False should be a Boolean so actually, the correct usage and syntax should be Dim wrong As Boolean = False.
Legacy VB6 code. Never a good thing to mix and match pre-.NET code with .NET code. You're using Val, don't do it. Also, it's worth noting that your usage is not needed and simply incorrect. You are using: loginpassword = Val(txtpass.Text). Why are you doing this? What do you think is happening here? It's going to try to convert whatever is in your txtpass.Text (string) to a Double (not a string) then put it into loginpassword (string).
I hope you don't take offence, I'm just trying to get you to see some flaws so you can try to improve and get to love programming like many people here already do so.
SO let's get back to your original code and question. Below is a simplified version of what you want to do.
Try it, understand it, and then change it as you see fit. For example, if you want a separate Username/Password check.
Good Luck!
Dim numAttempts As Integer = 3
Dim User As String = "ShaoHecc"
Dim Password As String = "daedric123"
Private Sub btnok_Click(sender As Object, e As EventArgs) Handles btnok.Click
'Check if Username or Password are incorrect
If Not txtuser.Text = User Or Not txtpass.Text = Password Then
numAttempts -= 1
If numAttempts = 0 Then
MessageBox.Show("Maxiumum number attempts reached, you have been denied access.")
Application.Exit()
End If
MessageBox.Show("Invalid Username or Password, you have " & numAttempts & " attempts left.")
Exit Sub
End If
'Username and Password are correct
MessageBox.Show("Access Granted!")
numAttempts = 3 'Reset if needed
End Sub

Visual Basic: i have a file containg usernames and passwords but i want to read them back in so the user can log back in

Do
Do
Console.WriteLine("Create a password. It must be 8 characters in length")
password1 = Console.ReadLine()
Loop Until password1.Length = 8
Console.WriteLine("Please re-enter the password.")
password2 = Console.ReadLine()
Loop Until password2 = password1
password = password1
Console.WriteLine("your password has been created.")
Console.ReadLine()
The below code generates the file
Dim fileName = "C:\Users\emily\Documents\Details.csv"
Dim fileAppend As New System.IO.StreamWriter(fileName, True)
fileAppend.WriteLine(name & ", " & age & ", " & username & ", " & password & ", " & yeargroup)
fileAppend.Close()
So basically I have details about the users stored in a csv file. The columns are arranged as follows: name, age, username, password, yeargroup. I need to be able to input a username and for it to be found in the array/list and then input the password and if the password doesn't match for it to start again.
Nice homework. You should think about storing password. Clear text is obviously risky. With the user file load in a table like this will let you manage all of the user. Add,Remove, Change then just save over the userfile.
Public Class Form1
Dim UserTable As New DataTable("UserTable")
Dim SomeUserName As String = "slims"
Dim SomePassword As String = "abc1234!"
Sub ReadUserFile()
Dim fileName = "C:\dump\test.csv"
Dim fileReader As New System.IO.StreamReader(fileName)
UserTable.Columns.Add("Name")
UserTable.Columns.Add("Age")
UserTable.Columns.Add("Username")
UserTable.Columns.Add("Password")
UserTable.Columns.Add("YearGroup")
Do Until fileReader.EndOfStream = True
Dim OneLine As String = fileReader.ReadLine()
UserTable.Rows.Add(OneLine.Split(","))
Loop
fileReader.Close()
End Sub
Sub WriteUserFile()
Dim fileName = "C:\dump\test.csv"
Dim fileWriter As New System.IO.StreamWriter(fileName)
For Each xRow As DataRow In UserTable.Rows
fileWriter.WriteLine(String.Format("{0},{1},{2},{3},{4}", xRow("Name"), xRow("Age"), xRow("Username"), xRow("Password"), xRow("YearGroup")))
Next
fileWriter.Close()
End Sub
Function CheckUserPassword(UserName As String, Password As String) As Boolean
Dim Found As Boolean = False
For Each xRow As DataRow In UserTable.Rows
If (xRow("Username") = SomeUserName) And (xRow("Password") = SomePassword) Then
Found = True
Exit For
Else
Found = False
End If
Next
Return Found
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ReadUserFile()
If CheckUserPassword(SomeUserName, SomePassword) = True Then
'Good to go
Else
'bad user/pass
End If
WriteUserFile()
End Sub
End Class
You can use IO.File.ReadAllLines(fileName) to read the lines into an array of strings. Then you can use String.Split() on each line to split the fields and pick out the username and password.
dim allLines as String() = IO.File.ReadAllLines(fileName)
for each line as String in allLines
dim lineArray() as string
lineArray = line.Split(New Char() {","c})
username = lineArray(2)
password = lineArray(3)
if username = theUsernameYouWant then
'Found the user. Now check their password
endif
next
I havn't tested this code. Might have syntax errors.

VB.net COMExeption was unhandled

I am creating a user login system using vb.net and MS access. I am unsure what is going wrong with my system and I receive the error message "Item cannot be found in the collection corresponding to the requested name or ordinal" The error is coming up in the section "User.Find(Username)" on the first line of the DO loop. Here is my code:
Public Class Login
Dim LoginError As String ' This will tell the user what is wrong with his login
Public Function Login()
Dim DBConn As New ADODB.Connection ' This is how we tell visual studio
'how to connect to our database
Dim User As New ADODB.Recordset 'We pass our argument through our recordset
Dim Username As String 'This will be our "Query"
Dim strUserDB As String 'This get sets to the email field in our database.
Dim strPassDB As String 'Same as above just for the password
Dim blnUserFound As Boolean 'I will be using a "DO" loop so I will use
'this as my condition
DBConn.Open("Provider = Microsoft.Jet.OLEDB.4.0;" & _
"Data Source = '" & Application.StartupPath & "\UserDetails2000.mdb'")
'The inverted comas in the dataOuce statement as itt keeps the location of your
'file as one string.
User.Open("tblUserDetails", DBConn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic)
'This is my table 'This is my connection 'These are some settings
blnUserFound = False
Login = False
Username = "User = '" & txtEmail.Text & "'" 'This tells the database to find the email field
'Equivilent to what was entered in the textbox
Do
User.Find(Username) 'This is the full statement that sends my 'Query' to the record set
If User.BOF = False And User.EOF = False Then
'BOF = Begining of file, EOF = End of file, it tests whether the database has
'reached its sentinal value, if it hasent then the username has been found, If it has,
'the username has been found.
strUserDB = User.Fields("Email").Value.ToString
'"Email" is my table field. I am setting strUserDB to the username field of my table
strPassDB = User.Fields("Password").Value.ToString
If strUserDB <> txtEmail.Text Then
User.MoveNext()
'This IF statement handles different CASE usernames, Example, admin and AdMiN
'We use this if statement to differentiate between different CASE letters
Else
blnUserFound = True
If strPassDB = txtPassword.Text Then
User.Close()
DBConn.Close()
Return True
Else
LoginError = "Invalid Password"
User.Close()
DBConn.Close()
Return False
End If
End If
Else
LoginError = "Invalid Username"
User.Close()
DBConn.Close()
Return False
End If
Loop Until blnUserFound = True
LoginError = "Invalid Username"
User.Close()
DBConn.Close()
Return False
End Function
Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click
If Login() = True Then
MessageBox.Show("Login Succesful", "Login Status")
Else
MessageBox.Show(LoginError, "Login Status")
End If
End Sub
End Class
Verify that tblUserDetails contains a column named User.
Maybe User is also a reserved keyword in Access so try setting Username as:
Username = "[User] = '" & txtEmail.Text & "'"

Microsoft Excel Data Connections - Alter Connection String through VBA

I have a fairly straightforward question. I am trying to find a way to alter and change a connection string for an existing data connection in an excel workbook through VBA (macro code). The main reason I am trying to do this is to find a way to prompt the user that opens up the workbook to enter their credentials (Username/Password) or have a checkbox for Trusted Connection that would be used in the Connection String of those existing data connections.
Right now the Data connections are running off a sample user that I created and that needs to go away in the production version of the workbook. Hope that makes sense?
Is this possible? If yes, could you please give me a sample/example code block? I would really appreciate any suggestions at this point.
I also had this exact same requirement and although the duplicate question Excel macro to change external data query connections - e.g. point from one database to another was useful, I still had to modify it to meet the exact requirements above. I was working with a specific connection, while that answer targeted multiple connections. So, I've included my workings here. Thank you #Rory for his code.
Also thanks to Luke Maxwell for his function to search a string for matching keywords.
Assign this sub to a button or call it when the spreadsheet is opened.
Sub GetConnectionUserPassword()
Dim Username As String, Password As String
Dim ConnectionString As String
Dim MsgTitle As String
MsgTitle = "My Credentials"
If vbOK = MsgBox("You will be asked for your username and password.", vbOKCancel, MsgTitle) Then
Username = InputBox("Username", MsgTitle)
If Username = "" Then GoTo Cancelled
Password = InputBox("Password", MsgTitle)
If Password = "" Then GoTo Cancelled
Else
GoTo Cancelled
End If
ConnectionString = GetConnectionString(Username, Password)
' MsgBox ConnectionString, vbOKOnly
UpdateQueryConnectionString ConnectionString
MsgBox "Credentials Updated", vbOKOnly, MsgTitle
Exit Sub
Cancelled:
MsgBox "Credentials have not been changed.", vbOKOnly, MsgTitle
End Sub
The GetConnectionString function stores the connection string that you insert your username and password into. This one is for an OLEDB connection and is obviously different depending on the requirements of the Provider.
Function GetConnectionString(Username As String, Password As String)
Dim result As Variant
result = "OLEDB;Provider=Your Provider;Data Source=SERVER;Initial Catalog=DATABASE" _
& ";User ID=" & Username & ";Password=" & Password & _
";Persist Security Info=True;Extended Properties=" _
& Chr(34) & "PORT=1706;LOG=ON;CASEINSENSITIVEFIND=ON;INCLUDECALCFIELDS=ON;" & Chr(34)
' MsgBox result, vbOKOnly
GetConnectionString = result
End Function
This code does the job of actually updating a named connection with your new connection string (for an OLEDB connection).
Sub UpdateQueryConnectionString(ConnectionString As String)
Dim cn As WorkbookConnection
Dim oledbCn As OLEDBConnection
Set cn = ThisWorkbook.Connections("Your Connection Name")
Set oledbCn = cn.OLEDBConnection
oledbCn.Connection = ConnectionString
End Sub
Conversely, you can use this function to get whatever the current connection string is.
Function ConnectionString()
Dim Temp As String
Dim cn As WorkbookConnection
Dim oledbCn As OLEDBConnection
Set cn = ThisWorkbook.Connections("Your Connection Name")
Set oledbCn = cn.OLEDBConnection
Temp = oledbCn.Connection
ConnectionString = Temp
End Function
I use this sub to refresh the data when the workbook is opened but it checks that there is a username and password in the connection string before doing the refresh. I just call this sub from the Private Sub Workbook_Open().
Sub RefreshData()
Dim CurrentCredentials As String
Sheets("Sheetname").Unprotect Password:="mypassword"
CurrentCredentials = ConnectionString()
If ListSearch(CurrentCredentials, "None", "") > 0 Then
GetConnectionUserPassword
End If
Application.ScreenUpdating = False
ActiveWorkbook.Connections("My Connection Name").Refresh
Sheets("Sheetname").Protect _
Password:="mypassword", _
UserInterfaceOnly:=True, _
AllowFiltering:=True, _
AllowSorting:=True, _
AllowUsingPivotTables:=True
End Sub
Here is the ListSearch function from Luke. It returns the number of matches it has found.
Function ListSearch(text As String, wordlist As String, seperator As String, Optional caseSensitive As Boolean = False)
Dim intMatches As Integer
Dim res As Variant
Dim arrWords() As String
intMatches = 0
arrWords = Split(wordlist, seperator)
On Error Resume Next
Err.Clear
For Each word In arrWords
If caseSensitive = False Then
res = InStr(LCase(text), LCase(word))
Else
res = InStr(text, word)
End If
If res > 0 Then
intMatches = intMatches + 1
End If
Next word
ListSearch = intMatches
End Function
Finally, if you want to be able to remove the credentials, just assign this sub to a button.
Sub RemoveCredentials()
Dim ConnectionString As String
ConnectionString = GetConnectionString("None", "None")
UpdateQueryConnectionString ConnectionString
MsgBox "Credentials have been removed.", vbOKOnly, "Your Credentials"
End Sub
Hope this helps another person like me that was looking to solve this problem quickly.