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());
Related
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("-", "");
}
I have a program in which a user can set up a bank account. It writes (in order) name, address, balance, and account type to a base text file. I am trying to provide a function for the user to be able to update their account by providing a new name and address. The balance and account type cannot be edited, and are taken from the base file.
The program currently writes the new data to a temporary file, which will eventually overwrite the base file with its contents. However, it also writes the old data from the user to the file, which is not what I want. Currently, the file will contain both the old data (before the user went to change it) and the new data (what the user entered to update).
I would like some help on how I can overwrite or skip the old data in the temporary file, and leave only the new data and other accounts.
I have tried to implement this feature by using the String.Replace method, iterating it for each data item by using a for loop (I use a for loop to show the user's data if they select the option to view their data, which works for that), but it did not function as intended (it did not replace the text or do anything).
else if (ChoiceInput == "3")
//Choice 3 - Update account details.
{
//Check that the account exists.
using (FileStream fs2 = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite))
{
StreamReader sr2 = new StreamReader(fs2);
StreamWriter sw2 = new StreamWriter(fs2);
Console.Write("Enter the account name: ");
string NameCheck = Console.ReadLine();
string NameValidation;
try
{
NameValidation = sr2.ReadLine();
string NameReplace = NameValidation;
NameReplace.Replace(NameValidation, "");
sw2.Write(NameReplace);
while (NameValidation != null)
{
if (NameValidation.Contains(NameCheck))
//Account exists.
{
for (int i = 0; i < 3; i++)
{
if (i == 1)
{
string ReadReplace = sr2.ReadLine();
ReadReplace.Replace(ReadReplace, "" + "\r\n");
sw2.Write(NameReplace);
Console.WriteLine(ReadReplace);
}
else if (i == 2)
{
string ReadReplace = sr2.ReadLine();
ReadReplace.Replace(ReadReplace, "" + "\r\n");
sw2.Write(NameReplace);
Console.WriteLine(ReadReplace);
}
}
}
using (StreamWriter sw = new StreamWriter(FileNameTemp, true))
{
//Enter new details. It writes these details to the temporary file.
Console.WriteLine("Account found.");
Console.WriteLine("Enter new name: ");
string AccountName = Console.ReadLine();
sw.WriteLine(AccountName);
Console.WriteLine("Enter new address: ");
string AccountAddress = Console.ReadLine();
sw.WriteLine(AccountAddress);
NameValidation = null;
for (int i = 0; i < 3; i++)
//Loop that iterates twice, writing the balance and account type to the temporary file. This data cannot be changed.
{
string Write = sr2.ReadLine();
if (i == 1)
//Balance.
{
sw.WriteLine(Write);
}
else if (i == 2)
//Account type.
{
sw.WriteLine(Write);
}
}
}
using (StreamReader sre = new StreamReader(FileName, true))
{
using (StreamWriter sw = new StreamWriter(FileNameTemp, true))
{
string Lines;
int Counter = 0;
while ((Lines = sre.ReadLine()) != null)
//While the program still has lines to go through, it will continue writing to the text file.
{
Console.WriteLine(Lines);
sw.Write(Lines + "\r\n");
Counter++;
}
}
using (FileStream fs = new FileStream(FileNameTemp, FileMode.Truncate))
//Clears the temporary file, as not doing so would cause issues.
{
}
Console.WriteLine("Account details updated!");
}
}
}
finally
{
Console.ReadLine();
}
}
}
Update: I have added an example of what I am trying to do. The first for loop under NameValidation is supposed to remove the old details on the base file by replacing them with empty strings. However, it does not work as intended. It does not write anything to the base file, and then it crashes with the error "System.IO.IOException: 'The process cannot access the file 'C:\program1\Bank.txt' because it is being used by another process.'", when it carries onto StreamReader sre.
However, it does write the balance and account type of the next account into the temporary file.
Okay. Some tips on how to proceed.
This is how your text file should be
Id, Name, address, Balance
1, testName, xyz, 300
Before Insert check if the name already exists. If yes, get the id (here if testname exists, we have to get the id value i.e 1).
If we get this id, we can parse the file and update them with StreamWriter
[Or]
Read the name and address, replace with string.replace
Console.WriteLine("What name would you like to be known as?");
string usernameforscore = Console.ReadLine();
int classicscore = 0;
string path = "";
File.AppendAllText(path, (usernameforscore + " " + classicscore + Environment.NewLine));
So essentially this will write a name and a score to a file one line after another, I want to add some kind of validation that checks if someone's entered username is in the file, it will then override that entire line with the new username and score data.
"classicsscore" references the score of the user, stored as an integer previously. It is then placed into a text file along with the person's inputting string username i.e. "John 12". What I want is that if a person inputs John as their username, which the score 400, the line would then be replaced with "John 400" and not affect the rest of the text file.
I'm using Visual studio, C# console program.
Apologies if this is a duplicate, couldn't find a specific answer myself.
Im thinking something like this should work for you.
public void AddOrUpdate(string userName, int score)
{
string path = "";
var newLine = userName + " " + score;
var lines = File.ReadAllLines(path);
var wasUpdated = false;
using (var writer = new StreamWriter(path))
{
foreach (var line in lines)
{
var foundUserName = line.Substring(0, line.LastIndexOf(' '));
if (foundUserName == userName)
{
writer.WriteLine(newLine);
wasUpdated = true;
}
else
writer.WriteLine(line);
}
if(!wasUpdated)
writer.WriteLine(newLine);
}
}
But unless you need this specific format for some reason using a database would be a much better option.
I've been trying to decrypt my file using GpgAPI in C#. It works fine, but it keeps prompting me for the password. The following code is what I used which is from the author's example.
public bool DecryptReport(string dataFileLocation, string filename)
{
log.Info("Starting GPG decryption.");
GpgInterface.ExePath = #"C:\Program Files (x86)\GNU\GnuPG\gpg2.exe";
String encryptedFile = dataFileLocation + filename;
filename = filename.ToString().Substring(0, filename.ToString().IndexOf(".gpg")).ToString();
string file = dataFileLocation + filename;
try
{
log.Info("Decrypting " + file);
GpgDecrypt decrypt = new GpgDecrypt(encryptedFile, file);
decrypt.AskPassphrase = GetPassword;
{
log.Info("Password received.");
GpgInterfaceResult result = decrypt.Execute();
Callback(result);
}
}
catch(Exception e)
{
log.Error("Caught an exception" + e.InnerException);
return false;
}
return true;
}
public static string Callback(GpgInterfaceResult result)
{
if(result.Status == GpgInterfaceStatus.Success)
{
return "successfully decrypted.";
}
else
{
return "Error was found during decryption. Check the log.";
}
}
public static SecureString GetPassword(AskPassphraseInfo arg)
{
return GpgInterface.GetSecureStringFromString(“password$");
}
What am I doing wrong in this code? Why does it not pass the password and continue decrypting instead of prompting for the password?
The gpg2 does not work as it should ... download the gpg classic.
Visit https://www.gnupg.org/download/ go to GnuPG binary -> Windows -> Simple installer for GnuPG classic.
Change GpgInterface.ExePath = #"C:\Program Files (x86)\GNU\GnuPG\gpg2.exe"; to "C:\Program Files (x86)\GNU\GnuPG\gpg.exe";
I am using Koolwired.Imap to retrieve attachments. The following is the code that I have written.
using K = Koolwired.Imap;
public void GetAttachmentsTest(string thread, string selectFolder, string fileName)
{
K.ImapConnect connect = new K.ImapConnect(Global.host);
K.ImapCommand command = new K.ImapCommand(connect);
K.ImapAuthenticate auth = new K.ImapAuthenticate(connect, Global.username, Global.password);
connect.Open();
auth.Login();
K.ImapMailbox mailBox = command.Select(Global.inbox);
mailBox = command.Fetch(mailBox);
K.ImapMailboxMessage mbstructure = new K.ImapMailboxMessage();
while (true)
{
try
{
int mailCount = mailBox.Messages.Count;
if (mailCount == 0)
{
Console.WriteLine("no more emails");
break;
}
for (int i = 0; i < mailCount; ++i)
{
mbstructure = mailBox.Messages[mailCount - 1];
mbstructure = command.FetchBodyStructure(mbstructure);
for (int j = 0; j < mbstructure.BodyParts.Count; ++j)
{
if (mbstructure.BodyParts[j].Attachment)
{
//Attachment
command.FetchBodyPart(mbstructure, mbstructure.BodyParts.IndexOf(mbstructure.BodyParts[j]));
//Write Binary File
string tempPath = Path.GetTempPath();
FileStream fs = new FileStream(tempPath + mbstructure.BodyParts[j].FileName, FileMode.Create);
int length = Convert.ToInt32(mbstructure.BodyParts[j].DataBinary.Length);
fs.Write(mbstructure.BodyParts[j].DataBinary, 0,length);
fs.Flush();
fs.Close();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("T1 " + ex.Message);
Console.WriteLine("T1 " + ex.StackTrace);
if (ex.InnerException != null)
Console.WriteLine("T1 " + ex.InnerException.Message);
}
}
}
I am getting error on the statement:
int length = Convert.ToInt32(mbstructure.BodyParts[j].DataBinary.Length);
and
fs.Write(mbstructure.BodyParts[j].DataBinary, 0,length);
and the error is:
The input is not a valid Base-64 string as it contains a non-base 64 characters, more than two padding characters, or an illegal character among the padding characters.
The above code breaks down at the lines shown when there is only 1 attachment.
If there are more than one attachment:
Then the code breaks down on line
mbstructure = command.FetchBodyStructure(mbstructure);
and the error is:
Invalid format could not parse body part headers.
I am soo close to getting this assignment taken care of. Could any one please help me.
I would also like to know how to delete the emails once I retrieve them.
Thanks.
I experienced the same problem
If anyone cares about, I solved it downloading the latest source code for the library from codeplex.
Once compiled, it works with no change. Looks like they have fixed it.
Also for deleting an email, just mark it for deletion:
command.SetDeleted(n, true); //-> Where n is the message number.
If is an IMAP connection, actually you have to expunge the deleted mails to complete the deletion.
command.Expunge();
Hope it helps someone.