C# txt contains X instead of txt's line contains X [duplicate] - c#

First I made textbox1(for username) , textbox2(for password) and button1(check).
After:
private void button1_Click(object sender, EventArgs e)
{
FileStream fs = new FileStream(#"D:\C#\test.txt", FileMode.Open, FileAccess.Read, FileShare.None);
StreamReader sr = new StreamReader(fs);
}
I want to check username from the first line of test.txt (equals like added from me text in textbox1) and password from the second line.
Sorry for my bad english.

You could try something like this:
private void button1_Click(object sender, EventArgs e){
string[] lines = System.IO.File.ReadAllLines(#"D:\C#\test.txt");
String username = lines[0];
String password = lines[1];
}
However, it's not a very good way to store your usernames and passwords. I'm assuming you're just testing something out.

The simplest answer to your question is to read the text-file line by line. I would however strongly suggest at least seeding and hashing the password.
This is a short example utilizing seeded SHA256 hashed passwords. It's just to show the concept and should not be used as is.
void Test()
{
string pwd = "Testing1234";
string user = "username";
StorePassword(user, pwd);
bool result = ValidatePassword(user, pwd);
if (result == true) Console.WriteLine("Match!!");
}
private void StorePassword(string username, string password)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var salt = new string(
Enumerable.Repeat(chars, 8)
.Select(s => s[random.Next(s.Length)])
.ToArray());
string hash = GetHash(salt + password);
string saltedHash = salt + ":" + hash;
string[] credentials = new string[] { username, saltedHash };
System.IO.File.WriteAllLines(#"D:\C#\test.txt",credentials);
}
bool ValidatePassword(string username, string password)
{
string[] content = System.IO.File.ReadAllLines(#"D:\C#\test.txt");
if (username != content[0]) return false; //Wrong username
string[] saltAndHash = content[1].Split(':'); //The salt will be stored att index 0 and the hash we are testing against will be stored at index 1.
string hash = GetHash(saltAndHash[0] + password);
if (hash == saltAndHash[1]) return true;
else return false;
}
string GetHash(string input)
{
System.Security.Cryptography.SHA256Managed hasher = new System.Security.Cryptography.SHA256Managed();
byte[] bytes = hasher.ComputeHash(Encoding.UTF8.GetBytes(input));
return BitConverter.ToString(bytes).Replace("-", "");
}

Related

C# Login error with text checking/validation

So baiscally my first registered username and password in my text file when i login is able to pass through the validation however my next pair gets past the .contains but fails at checking password, not giving me the message and closing the console.
Example of text file-
Elliot|Benten67Fred|Payne
It will be able to check Elliot and Benten67. However can locate Fred but not able to check if the password is right? Any help would be great
public void Register()
{
string filePath = #"/Users/elliot/Documents/Film Libary Software/Film-Libary/Film-Libary/bin/Debug/netcoreapp3.1/UserInfo.txt";
Console.WriteLine("Create A Username which contains A Upper Case character");
Username = Console.ReadLine();
bool usernameIsUpper = Username.Any(char.IsUpper);
if (usernameIsUpper)
{
Console.WriteLine("Please enter a password: ");
Password = Console.ReadLine();
string toWrite = Username + "|" + Password;
File.AppendAllText(filePath, toWrite);
Login();
}
else
{
Console.WriteLine("Invalid Username: Please try again!");
Register();
}
}
public void Login()
{
string fileName = #"/Users/elliot/Documents/Film Libary Software/Film-Libary/Film-Libary/bin/Debug/netcoreapp3.1/UserInfo.txt";
using (StreamReader reader = new StreamReader(fileName))
{
string line;
Console.WriteLine("Enter your username");
string loginUsername = Console.ReadLine();
while ((line = reader.ReadLine()) != null)
{
if (line.Contains(loginUsername))
{
int indexOfDelimiter = line.IndexOf('|');
string usernameFromFile = loginUsername;
string passwordFromFile = line.Substring(indexOfDelimiter + 1, line.Length - (indexOfDelimiter + 1));
Console.WriteLine("Please enter your password");
string enteredPassword = Console.ReadLine();
if (enteredPassword == passwordFromFile)
{
Console.WriteLine("Elliot well done");
}
}
}
}
}
Your reading code requires the each user be on a separate line, but you are not writing new lines, you can see that here
Elliot|Benten67Fred|Payne
you need
Elliot|Benten67
Fred|Payne
The error is here
string toWrite = Username + "|" + Password;
File.AppendAllText(filePath, toWrite);
you need
string toWrite = Username + "|" + Password + "\n";
File.AppendAllText(filePath, toWrite);

StreamReader failing to read second line

I am using a StreamReader to read out the Username and Password from a .csv file (I'm just trying this out because I'm new to C#). For some reason, if I press sign in it works for the account in the first line of the file but not the second one. Anyone can help?
Register Code (Writer):
try
{
using (StreamWriter sw = new StreamWriter("C:\\GameLauncherKarakurt\\users.csv", true))
{
sw.WriteLine(tbxUsername.Text + ';' + tbxPassword.Text);
sw.Close();
}
}
catch
{
// Do nothing
}
Sign-in Code (Reader):
string username;
string password;
bool usernameCorrect = false;
bool passwordCorrect = false;
// Username
try
{
using (StreamReader sr = new StreamReader("C:\\GameLauncherKarakurt\\users.csv"))
{
username = sr.ReadLine();
string[] usernameSplit = username.Split(';');
string user = usernameSplit[0];
while (username != null)
{
if (tbxUsername.Text == user)
{
usernameCorrect = true;
break;
}
else
{
username = sr.ReadLine();
}
}
sr.Close();
}
}
catch
{
}
// Password
try
{
using (StreamReader sr = new StreamReader("C:\\GameLauncherKarakurt\\users.csv"))
{
password = sr.ReadLine();
string[] passwordSplit = password.Split(';');
string pass = passwordSplit[1];
while (password != null)
{
if (tbxPassword.Text == pass)
{
passwordCorrect = true;
break;
}
else
{
password = sr.ReadLine();
}
}
sr.Close();
}
}
catch
{
}
if (usernameCorrect == true && passwordCorrect == true)
{
pnlMenu.Visible = true;
tbxUsername.Clear();
tbxPassword.Clear();
}
You are not keeping the structure of CSV file. all couples of user and password must be separated by comma (",") and not by a new line,
Add a comma after each user and password couple.
Use Write() and not WriteLine().
private void Write()
{
try
{
using (StreamWriter sw = new StreamWriter("C:\\GameLauncherKarakurt\\users.csv", true))
{
// next time you add user and pass word you need to concatenate with ","
sw.Write(tbxUsername.Text + ';' + tbxPassword.Text + ",");
sw.Close();
}
}
catch()
{
// Do nothing
}
}
Here is one way to read the file. Use ReadToEnd() and split all the user and password couples to an array, each couple will be at a different index:
using (StreamReader sr = new StreamReader("C:\\GameLauncherKarakurt\\users.csv"))
{
var rows = sr.ReadToEnd();
string[] splitted = rows.Split(',');
}
Now you can split again each index of the array by the ";" separator,
keep in mind that there are some improvements you can do to your "matching"/authentication logic.
Once your file has been created, you can read the user and password from each line using the statement below:
using (StreamReader sr = new StreamReader(""C:\\GameLauncherKarakurt\\users.csv""))
{
while (!sr.EndOfStream)
{
strLine = sr.ReadLine();
string[] usernameSplit = strLine.Split(';');
string user = usernameSplit[0];
string password = usernameSplit[1];
}
}

Using a hash to protect password in file

I've had a look around around SO and found some useful info on using a hash, but not actually any information on how to use it with the StreamWriter function in C#.
The code I used from SO was the code I found here: How to hash a password - Christian Gollhardt
CODE
private void Accept_Click(object sender, EventArgs e)
{
usrpass = usrpassTextbox.Text.ToString();
usrid = usridTextbox.Text.ToString();
if (FileExists() == true)
{
if (DialogResult.OK == MessageBox.Show("This user already exists, overwrite?", "Warning", MessageBoxButtons.OKCancel))
{
using (StreamWriter streamWriter = new StreamWriter(usrid + ".txt"))
{
streamWriter.WriteLine(usrpass);
MessageBox.Show(id + "'s password has been saved");
}
}
}
else
{
using (StreamWriter streamWriter = new StreamWriter(usrid + ".txt"))
streamWriter.WriteLine(usrpass);
MessageBox.Show(id + " " + "'s password has been saved");
}
}
}
Also I am considering putting the saving into a method to reduce code, I know there's no point in writing it out twice.
Desired Outcome
I would like the password that is being written to the .txt file to be hashed, if this is hashed, will the user still be able to login when I write a bit of code that checks if the user's txt file exists, then reads it for the password?
Will I have to unhash it?
As of yet, I have the code I borrowed from Christian but not sure how to use it to hash the usrpassbefore it is written to file
public static string CreateMD5(string input)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
...
usrpass = CreateMD5(usrpassTextbox.Text.ToString());

Login using Multiple tables C#

Im trying to work out how to use data from 3 tables to authenticate then redirect to a different page dependant on table used. I have the first bit working (ie using 1 table) the problem is when i try to use 2/3 tables.
(I know about SQL injection etc ive just made the page super simple to try and get this working first :))
any help would be really appricated as its driving me nuts
heres were im up to
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void _login_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Testconnection"].ConnectionString);
conn.Open();
string Checkuser = "Select count(*) from dbo.loginuser where username='" + Textusername.Text + "'";
SqlCommand com = new SqlCommand(Checkuser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPasswordQuery = "select password from dbo.loginuser where username='" + Textusername.Text + "'";
SqlCommand passComm = new SqlCommand(checkPasswordQuery, conn);
string password = passComm.ExecuteScalar().ToString().Replace(" ", "");
if (password == textpassword.Text)
{
Session["New"] = Textusername.Text;
Response.Redirect("Reporthome.aspx");
}
}
else
{
conn.Open();
string Checkuser1 = "Select count(*) from dbo.employee where idno='" + Textusername.Text + "'";
SqlCommand com1 = new SqlCommand(Checkuser1, conn);
int temp1 = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp1 == 1)
{
conn.Open();
string checkPasswordQuery1 = "select epass from dbo.employee where idno='" + Textusername.Text + "'";
SqlCommand passComm1 = new SqlCommand(checkPasswordQuery1, conn);
string epass = passComm1.ExecuteScalar().ToString().Replace(" ", "");
if (epass == textpassword.Text)
{
Session["New"] = Textusername.Text;
Response.Redirect("Engineerhome.aspx");
}
else
{
Response.Write("password is incorrect");
}
}
}
}
}
Why not try and use a stored procedure and let the database handle it. If the three tables have the same columns or fields then UNION ALL for all three tables and pass your credentials to the stored procedure.
Handle the entire three tables in the select. Also make sure once you get there to salt your passwords and encrypt accordingly and save the product.
Try something like.....
public class PasswordHash{
public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
// The following constants may be changed without breaking existing hashes.
public static final int SALT_BYTE_SIZE = 24;
public static final int HASH_BYTE_SIZE = 24;
public static final int PBKDF2_ITERATIONS = 1000;
public static final int ITERATION_INDEX = 0;
public static final int SALT_INDEX = 1;
public static final int PBKDF2_INDEX = 2;
/**
* Returns a salted PBKDF2 hash of the password.
*
* #param password the password to hash
* #return a salted PBKDF2 hash of the password
*/
public static String createHash(String password)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
return createHash(password.toCharArray());
}
/**
* Returns a salted PBKDF2 hash of the password.
*
* #param password the password to hash
* #return a salted PBKDF2 hash of the password
*/
public static String createHash(char[] password)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Generate a random salt
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
// Hash the password
byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
// format iterations:salt:hash
return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);
}
/**
* Validates a password using a hash.
*
* #param password the password to check
* #param correctHash the hash of the valid password
* #return true if the password is correct, false if not
*/
public static boolean validatePassword(String password, String correctHash)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
return validatePassword(password.toCharArray(), correctHash);
}
/**
* Validates a password using a hash.
*
* #param password the password to check
* #param correctHash the hash of the valid password
* #return true if the password is correct, false if not
*/
public static boolean validatePassword(char[] password, String correctHash)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Decode the hash into its parameters
String[] params = correctHash.split(":");
int iterations = Integer.parseInt(params[ITERATION_INDEX]);
byte[] salt = fromHex(params[SALT_INDEX]);
byte[] hash = fromHex(params[PBKDF2_INDEX]);
// Compute the hash of the provided password, using the same salt,
// iteration count, and hash length
byte[] testHash = pbkdf2(password, salt, iterations, hash.length);
// Compare the hashes in constant time. The password is correct if
// both hashes match.
return slowEquals(hash, testHash);
}
/**
* Compares two byte arrays in length-constant time. This comparison method
* is used so that password hashes cannot be extracted from an on-line
* system using a timing attack and then attacked off-line.
*
* #param a the first byte array
* #param b the second byte array
* #return true if both byte arrays are the same, false if not
*/
private static boolean slowEquals(byte[] a, byte[] b)
{
int diff = a.length ^ b.length;
for(int i = 0; i < a.length && i < b.length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
/**
* Computes the PBKDF2 hash of a password.
*
* #param password the password to hash.
* #param salt the salt
* #param iterations the iteration count (slowness factor)
* #param bytes the length of the hash to compute in bytes
* #return the PBDKF2 hash of the password
*/
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
return skf.generateSecret(spec).getEncoded();
}
/**
* Converts a string of hexadecimal characters into a byte array.
*
* #param hex the hex string
* #return the hex string decoded into a byte array
*/
private static byte[] fromHex(String hex)
{
byte[] binary = new byte[hex.length() / 2];
for(int i = 0; i < binary.length; i++)
{
binary[i] = (byte)Integer.parseInt(hex.substring(2*i, 2*i+2), 16);
}
return binary;
}
/**
* Converts a byte array into a hexadecimal string.
*
* #param array the byte array to convert
* #return a length*2 character string encoding the byte array
*/
private static String toHex(byte[] array)
{
BigInteger bi = new BigInteger(1, array);
String hex = bi.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if(paddingLength > 0)
return String.format("%0" + paddingLength + "d", 0) + hex;
else
return hex;
}
/**
* Tests the basic functionality of the PasswordHash class
*
* #param args ignored
*/
public static void main(String[] args)
{
try
{
// Print out 10 hashes
for(int i = 0; i < 10; i++)
System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));
// Test password validation
boolean failure = false;
System.out.println("Running tests...");
for(int i = 0; i < 100; i++)
{
String password = ""+i;
String hash = createHash(password);
String secondHash = createHash(password);
if(hash.equals(secondHash)) {
System.out.println("FAILURE: TWO HASHES ARE EQUAL!");
failure = true;
}
String wrongPassword = ""+(i+1);
if(validatePassword(wrongPassword, hash)) {
System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");
failure = true;
}
if(!validatePassword(password, hash)) {
System.out.println("FAILURE: GOOD PASSWORD NOT ACCEPTED!");
failure = true;
}
}
if(failure)
System.out.println("TESTS FAILED!");
else
System.out.println("TESTS PASSED!");
}
catch(Exception ex)
{
System.out.println("ERROR: " + ex);
}
}
}
Since your two coding elements are so similar, you could also create a separate routine that is common to both elements, like this version of EmpPassword:
private string EmpPassword(string sqlText, System.Data.SqlClient.SqlConnection openConnection)
{
object obj = null;
using (var cmd = new System.Data.SqlClient.SqlCommand(sqlText, openConnection))
{
using (var r = cmd.ExecuteReader())
{
if (r.Read())
{
obj = r.GetValue(0);
}
}
}
if ((obj != null) && (obj != DBNull.Value))
{
return obj.ToString().Replace(" ", "");
}
return null;
}
Your _login_Click event could call each of your databases, depending on the outcome, using the same database connection object:
protected void _login_Click(object sender, EventArgs e)
{
using (var con = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings["Testconnection"].ConnectionString))
{
Session["New"] = null;
try
{
con.Open();
var sqlText = String.Format("SELECT password FROM dbo.loginuser WHERE username='{0}';", Textusername.Text);
var sqlResult = EmpPassword(sqlText, con);
if (sqlResult == textpassword.Text)
{
Session["New"] = Textusername.Text;
Response.Redirect("Reporthome.aspx");
}
else
{
sqlText = String.Format("Select epass from dbo.employee where idno='{0}';", Textusername.Text);
sqlResult = EmpPassword(sqlText, con);
if (sqlResult == textpassword.Text)
{
Session["New"] = Textusername.Text;
Response.Redirect("Engineerhome.aspx");
}
else
{
Response.Write("password is incorrect");
}
}
}
finally
{
con.Close();
}
}
}
Notice I skipped the SELECT Count(*) options on both. If the user exists on the table, it will be returned.
Of course, if your schema allows multiple instances of the same user ID, that would not work.

Searching for specific data in file using StreamReader C# then writing it to console window

I come to you with as I have exhausted myself searching Google and trying my own methods.
I have a struct made up of all strings which are stored in a text file. I want the user to be able to search for customer accounts in the text file by the customer's number and then the program should then return the customer information.
Below is the non-working search method I have created for the program. I get to the stage of this method as it allows me to enter the customer's number I want to search but after I press enter, I get nothing in return:
If you could tell me what is wrong in this code I'll be extremely grateful and relieved!
//SEARCHING BY CUSTOMER NUMBER
static void FindCustNo(CustomerStruct[] CustomerDeats)
{
String NumberSearch;
bool CustomerNumberMatch = false;
Console.Clear();
begin:
try
{
Console.WriteLine("\t\tPlease enter a customer number: ");
NumberSearch = Console.ReadLine();
}
catch
{
Console.WriteLine("Failed. Please try again.");
goto begin;
}
while (!CustomerNumberMatch)
{
var pathToCust = #"..\..\..\Files\Customer.txt";
using (StreamReader sr = new StreamReader(pathToCust))
{
RecCount = 0;
CustomerDeats[RecCount].CustomerNo = sr.ReadLine();
if (CustomerDeats[RecCount].CustomerNo == NumberSearch)
{
CustomerNumberMatch = true;
CustomerDeats[RecCount].CustomerNo = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].CustomerNo);
CustomerDeats[RecCount].Surname = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].Surname);
CustomerDeats[RecCount].Forename = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].Forename);
CustomerDeats[RecCount].Street = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].Town);
CustomerDeats[RecCount].Town = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].Town);
CustomerDeats[RecCount].DOB = sr.ReadLine();
Console.WriteLine(CustomerDeats[RecCount].DOB);
}
RecCount++;
if (RecCount > 15)
{
Console.WriteLine("No One Found");
}
}
}
Console.ReadKey();
}
Please try to find in Array instead of file. Following lines of code will return Array of string from file
string[] records = System.IO.File.ReadAllLines("filePath");
foreach (var record in records)
{
string[] fields = record.Split(' ');//space
if (customerIdToFind == fields[0])
{
Console.WriteLine("Customer ID:" + fields[0]);
Console.WriteLine("Customer Name:" + fields[1]);
}
}
Do not do this for large file, it will load entire content to memory. so StreamReader is always good.
while (!CustomerNumberMatch)
{
var pathToCust = #"..\..\..\Files\Customer.txt";
using (StreamReader sr = new StreamReader(pathToCust))
...
Seems to be the same problem someone else had just yesterday:
Why do you create a new StreamReader in every iteration?
Try this:
var pathToCust = #"..\..\..\Files\Customer.txt";
using (StreamReader sr = new StreamReader(pathToCust) {
while (!CustomerNumberMatch)
{
...
try this
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section,
string key, string def, StringBuilder retVal,
int size, string filePath);
/// <summary>
/// read value from given section and key
/// </summary>
/// <param name="Section">string</param>
/// <param name="Key">string</param>
/// <returns>string</returns>
public string IniReadValue(string Section, string Key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section, Key, "", temp,
255, this.path);
return temp.ToString();
}
To call this function See Below Code
string sBENCHNO = ini.IniReadValue("Sextion", "Key");

Categories

Resources