Reading in Encrypted Username/Password - c++

I am in the process of developing a console application that acts as a Diary. At this stage I am developing the login authentication and have hit a bit of a wall! As I will be dealing with text files for both my login and diary storage, I would like to encrypt these text files from prying eyes.
Now, the problem is I do not know how to go about the decrypt >> check user&&pass >> encrypt again.
Would it be along these lines?:
Program Loads
Decrypt passwords.txt
If at any point the program closes, encryptFile() is ran.
Validate user entry
Encrypt passwords.txt
If I am along the right lines how do I go about implementing this? I searched for encryption tutorials for text files using c++ and they were not very helpful.
Here is my butchered beginner password.txt code, where shall I go from here? If there is an encryption tutorial/article you recommend that I missed please post it!
void checkPasswordFile() {
string username;
string password;
string passwordAgain;
string userIn;
string passIn;
string line;
ifstream passwordFile("passwords.txt");
istringstream instream;
if (passwordFile.good()) {
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tYou are a returning user, please fill in your details" << endl;
while(!passwordFile.eof()) {
getline(passwordFile, line);
instream.clear();
instream.str(line);
username = line;
getline(passwordFile, line);
instream.clear();
instream.str(line);
password = line;
}
do {
cout << "Username: " << endl;
cin >> userIn;
cout << "Password: " << endl;
cin >> passIn;
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "Username and Password Do Not Match, Try Again" << endl;
}
} while(userIn != username && passIn != password);
} else {
cout << "file no exist";
ofstream passwordFile;
passwordFile.open ("passwords.txt", ios:: in | ios::app);
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tThis is your first run, please enter a username and password" << endl;
cout << "\tUsername: " << endl;
cin >> username;
cout << "\tPassword: " << endl;
cin >> password;
/*
Do Loop:
Prompts Re-Entry if PasswordAgain is not equal to Password
*/
do {
cout << "Re-Type Password: ";
cin >> passwordAgain;
if(password != passwordAgain) {
cout << "Passwords Do Not Match! Try Again" << endl;
}
} while(password != passwordAgain);
passwordFile << username << "\n";
passwordFile << password;
}
}
Thank you very much for your time.
p.s for the life of me I cannot find out how to do:
Username:[cin>>username] on the same console line, sorry for doubling up but didn't deem it a big enough question for its own post! Thanks.
EDIT:
I have succesfully been able to decrypt the username and pass when created and stored in the text file. Then when the user comes back, what they entered is encrypted and compared with the file.
Problem being this only works for short words, user pass works, but username and password does not... any ideas why? Here is my encryption code:
char encryptKey = 'h';
cout << "\tUsername: ";
cin >> userIn;
cout << "\tPassword: ";
cin >> passIn;
for (int i = 0; i < userIn.size(); i++) {
userIn[i] ^= encryptKey;
}
for (int x = 0; x < passIn.size(); x++) {
passIn[x] ^= encryptKey;
}
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "\tUsername and Password Do Not Match, Try Again" << endl;
}

The right thing to is not to encrypt the passwords file - the issue is that the encryption key for the file would need to be stored somewhere that the program can access it, which would make it relatively easy to find and abuse.
Instead, you should be using password hashing (using a strong hash algorithm like SHA1). A hash algorithm is a algorithm that deterministically maps a piece of text onto a large number (called its hash), and is designed to be irreversible without great effort. The basic concept is that you take the password, use it to compute its hash, and then store that hash. Later, when the user enters the password to log in, you compute its hash again and compare the resulting hash to the stored hash. Even if someone gains access to the hashes, they do not obtain the password, which is important, because people often share passwords between applications. Don't implement your own SHA1 hash - see "What is the best encryption library in C/C++?" for a list of libraries.
You must also use salting and key stretching to defend against common brute force attacks.

Related

I'm comparing two variables with the same value but it says they're different

Well, I was asked to do a little job with SHA-256. I have to receive a user name and a password from the user (in console), change the password to a SHA-256 hash value and close the file (binary file). Then I have to read it again, getting its data and comparing it with new user inputs, checking if they are the same or not. A simple log-in system using SHA-256 hashing. The thing is, I write a random user name and password, but when I try to compare them later in the second step, it fails. The SHA-256 part comes straight out of the original code, it wasn't the point of this assignation.
I tried changing all my char arrays to strings, used, strcpy, strcpy_s and strncpy (just in case) and more, but it doesn't seem to work. Most of the codecomes directly from SHA-256 (my teacher sent it), but I'll put it here nonetheless
I'm putting the entire code in pastebin (it's kind of long): https://pastebin.com/W9jxsbK6
I don't know how to edit correctly in this text box, so please use the paste bin link.
struct Credentials {
char user[10];
char password[256];};
int main() {
Credentials c;
char user2[10];
char password2[256];
string test;
fstream file;
int opc;
do{
cout << "Menu:" << endl;
cout << "1.Create new user and password" << endl;
cout << "2.Validate user and password" << endl;
cin >> opc;
switch(opc){
case 1:
cout << "Type the user name" << endl;
cin >> user2;
strcpy_s(c.user, sizeof user2, user2);
cout << "Type the password" << endl;
cin >> password2;
test = SHA256::digestString(password2).toHex();
strcpy_s(c.password, sizeof test, test.c_str());
file.open("credentials.dat",ios::out|ios::binary);
if(!archivo){
cout<<"Error...\n";
return -1;
}
file.write((char*)&c,sizeof(c));
file.close();
break;
case 2:
cout << "Type user name" << endl;
cin >> user2;
cout << "Type password" << endl;
cin >> password2;
file.open("credentials.dat",ios::in|ios::binary);
if(!file){
cout<<"Error...\n";
return -1;
}
if(file.read((char*)&c,sizeof(Credentials))){
if(c.user == user2 && SHA256::digestString(password2).toHex() == c.password){
cout << endl << endl << "User validated" << endl;
}else{
cout << endl << endl << "Error" << endl;
}
}
}
} while (opc > 0 && opc < 3);
cin.ignore();
return 0;
}
if (c.user == user2)
Since user2 is a character array, and Credentials::user is also a character array, that line is not how you compare two character arrays. What that line does is compare two pointers, not contents of arrays.
The function to use is strcmp, or if you want to compare specifically N characters, the function is strncmp.
#include <cstring>
//...
if ( strcmp(c.user, user2) == 0)
{
// strings are equal
}
Now, if c.user and/or user2 were std::string, then using == to compare would have worked. That's why using std::string is much more intuitive than using char arrays in this respect -- operations such as == actually work as expected.

Login from txt file with attempt limits

i'm totally new to C++ and this forum. I tried searching the codes and found a piece of code but it doesn't work as what I wanted. I want a login that check every line of the txt file and grant access to the system if the username and password is correct.
string line = " ";
ifstream readfile("Login.txt");
string username, password, adminname, adminpass;
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
cout << "\nLOGIN SUCCESSFUL!";
}
}
//Login Fail Function
{
int fail = 5;
while (fail > 0)
{
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
fail--;
}
cout << "\nACCESS DENIED!";
}
The txt file consists of 1st line (admin123 password123), 2nd line (admin admin).
The login worked fine if I entered correctly however, if I enter wrong username or password I just stuck in the while loop until it shows access denied even if I enter correct username and password for the second try.
Can anyone help me to fix this? If possible please include the comments(the //) so that I am able to learn from it. Thanks in advance.
Since you mention in the comments that this is an assignment, I'm going to keep this pretty general.
In your program, you prompt once for username and password, then read through the file to see if there is a match.
If there is no match, you then prompt for username and password again in a loop, but do not check to see if they are valid. This is what the problem is. Each time you get a new username and password, check to see if they are valid.
There are (at least) two possible approaches:
Include the "fail" and re-prompt logic around the code that reads the file. So you get a username and password, then read the file checking for a match. If no match, do it again. In this case, you would be reading the file each time. For a large data-set, this could get slow. For this problem, it should be fine.
Read the file once and save the values (Have you studied arrays, vectors, or other data structures? You need at least some of those things to do this). I would use a std::map here because it is direct access and would be the smallest amount of code, but there are many other ways to do this as well.
Here is a possible way to do it with re-reading the file. Note that this mostly just re-organizing the code you already have:
bool success = false; //use this as part of our loop condition
int fail = 5;
while (!success && fail > 0) //loop until we succeed or failed too much
{
//get the username and password
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
//open the file and see if we have a match
ifstream readfile("Login.txt");
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
//we have a match, so set success to true so we exit the loop
success = true;
}
}
if (!success) //we did not find a match in the file
{
//so we output the message
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
fail--;
}
}
//now we know if we had success or not, so report it
if (success)
{
cout << "\nLOGIN SUCCESSFUL!";
}
else
{
cout << "\nACCESS DENIED!";
}

else if looping quandry

I am in the second phase of a project where I need to extend my program into a menu driven application to query the database I have on a .txt file. So, my trouble is that I cannot get my loop to be perpetual. It always terminates when it initializes from one option to the next. Here is the snippet of my code that is my int main:
int main ()
{
char Q,q;
char S,s;
char task;
string pathname;
string z;
int count=0;
cout << "Welcome to Jason Rodriguez's Library Database." << endl;
cout << "Please enter the name of the backup file: ";
cin >> pathname;
ifstream inFile(pathname.c_str());
while(!inFile.eof())
{
getline(inFile,z);
count++;
}
while (task != 'Q' || task != 'q') {
cout << count << " records loaded successfully." << endl;
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: ";
cin >> task;
if ((task == 'Q')||(task =='q'))
{
cout << "Program will now terminate";
break;
}
else if ((task == 'S')||(task =='s'))
{
showAll (loadData (pathname));
cout << endl;
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: ";
cin >> task;
}
}
}
I need to add two more options into the loop on top of these two but I figured I should get the first two working correctly first. The other two should be plug & chug after that. Basically what I was trying to do is say if the user enters Q or q, terminate the program. Else, if user hits S or s, activate showall function and after ward, go back to the original query. It isn't working though. Assistance is welcome and appreciated.
Menus almost always require loops - especially ones that require the user to enter the correct choice input. The most applicable one in a case like this is the while loop - but essentially, any other loop variant can be used.
UPDATE:
int main ()
{
char task;//this is the only char needed. Your other chars were redundant
string pathname;
string temp;//I changed z to temp to better reflect its purpose
int count=0;
cout << "Welcome to Jason Rodriguez's Library Database." << endl;
cout << "Please enter the name of the backup file: ";
cin >> pathname;
ifstream inFile(pathname.c_str());//this is potentially a problem in that you aren't verifying that the pathname is a valid one
//you did not check to see that your file was open, otherwise there is no way to tell that you successfully opened the file
if (inFile.is_open()) {
//while(!inFile.eof()) is a character by character read and comparison
//made your life easier by shortening it down to this - which ensures
//that a line is read. (Much faster and more readable)
while(getline(inFile,temp))
{
count++;
}
inFile.close();//always close a file after you've used it
//At this point the entire file has been read. So, this is where this message SHOULD be
cout << count << " records loaded successfully." << endl;
}
else {
//if there was an error opening the file (i.e. wrong path, or it simply does not exist), this will be displayed
cout << "There was a problem opening your file" << endl;
exit(0);//and the program will terminate
}
while (task != 'Q' || task != 'q') {
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: ";
cin >> task;
if ((task == 'Q')||(task =='q'))
{
cout << "Program will now terminate";
break;
}
else if ((task == 'S')||(task =='s'))
{
string author;
//showAll (loadData (pathname));
cout << endl;
cout << "Search an Author" << endl;
cin >> author;//get the author name to search from the user
//write code to search an author here
}
}
}
There are a number of issues with the code that you posted which I will forgo for the sake of brevity. Hence, note the following:
Your code was printing the same message per option (except for quit). Of course it would appear that it didn't work. Each option is a different task. Print what each task does (similar to what I did).
You wish to search the file for an author, but you have not stored it. Look into a way of storing it that appeases your instructor.
It would be ideal for you to use switch in this case, considering the increasing complexity of your code.
Try breaking down each task into functions, and call them to make your main function readable. In fact, it is a good programming practice for your main function to be as small as possible.
And, as juanchopanza quite rightly pointed out: you have some fundamental issues with C++. Try doing some more exercises and do more examples from a good C++ book.

C++ function runs more than intended

When I run my program the user can log in, but if the enter in a wrong user name, it runs a check username loop again, saying that they did not enter in a valid user name. This work perfectly fine except for one thing. Say they attempt to log in in three times and the third attempt is correct and the get prompted for a password. Once they input it it ask for a second password and then a third. It seems like it is completing the function for the other attempts. I can not think of a way to check for this. Any ideas.
If you look at it you can see that I am calling UserCheck inside of getNameIndex. I am almost positive this is where the error is occurring.
The Function that checks the users:
void User_Psw::UserCheck()
{
// read from the database
ifstream fin("dataBase.txt", ios::in);
if( !fin.good() )
{
cout << "Failed to open database file." << endl;
return;
}
while (fin >> username >> password)
{
Usernames.push_back(username);
Password.push_back(password);
++sizeOfDatabase; // This may or may not be needed elsewhere.
}
// rest of the program
cout << "Username: ";
cin >> username;
getNameIndex();
cout << "Password: ";
cin >> password;
if(!PasswordMatches())
{
cout << "Access denied";
}
else
{
cout << "Success! You have logged in.";
}
}
This is the username check function
void User_Psw::getNameIndex()
{
userThere = false;
for(int i=0; i < sizeOfDatabase; i++)
{
if (Usernames[i] == username)
{
index = i;
userThere = true;
}
}
if (userThere == false)
{
cout << "\nThat user name does not exsist. \n";
cout << "Please try again. \n\n";
UserCheck();
}
}
The structure of your program is wrong.
Instead of getNameIndex calling UserCheck() again, you should have getNameIndex return a bool - true on success, false on failure. Run it inside of a loop, something like this:
bool success = false;
while (!success)
{
cout << "Username: ";
cin >> username;
success = getNameIndex();
}
Also, instead of having global variables, you should pass them to the function. Something like:
success = getNameIndex(username);
and getNameIndex() shouldn't do any I/O - the function that calls getNameIndex() should also be responsible for printing the error message. Imagine if you used getNameIndex() in a different context, such as when when the program is being run by another program or in an automated way - then printing to the console would be meaningless.

Skipping lines and not leaving them blank w/ ofstream

I have a pretty basic ofstream() question. I have an app that matches data that was inputted by a user in a text document. Can i skip lines with ofstream and not modify text already there? If possible, how? Please forgive me my English isn't too great.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0;
int num;
int numcopy;
string clientNames[3000];
string caseNumbers[3000];
int userInp = 1;
string confirm = "2";
cout << "Do you have a file already started (y/n)?"<<endl;
cin >> confirm;
if(confirm == "y")
{
goto input;
}
if(confirm == "n")
{
goto postinput;
}
input:
cout << "What is the number of the query last entered?";
cin >> userInp;
num = userInp;
numcopy = userInp;
postinput:
for(int i = 1; i <3000; i++)
{
userInp ++;
repeat:
cout <<"Enter Client's Name:";
cin >> clientNames[userInp];
cout << " " <<endl;
cout <<"Enter Case Number:";
cin>> caseNumbers[userInp];
cout <<"Client Name "<< i << " "<<clientNames[userInp]<<endl;
cout << "Case Number" << i << " "<<caseNumbers[userInp]<<endl;
cout <<"Is This Correct?"<<endl;
confirm == " ";
cin >> confirm;
if(confirm == "y")
{
cout <<"Confirmed"<<endl;
}
if(confirm == "n")
{
goto repeat;
}
if(confirm == "/end")
{
break;
}
}
ofstream file;
file.open("caseData.txt");
for(int w = 0; w <3000;w++)
{
num++;
file <<
}
}
"skip lines with ofstream and not modify text already there" is not possible.
But you can store all lines of the file in your program first. And while you are processing the file, output the stored line when you want to leave that line unchanged.
This effectively does what you want.
Also, you really should get rid of the gotos in your code. They should be used only in rare cases. And for beginners, I always feel they should not use it until they are very familiar with programming.
I am going to take a guess that you want to do something about the circumstance when the user has inputted the same clientName or same caseNumber multiple times. It is actually not entirely clear from your question that this is what you want to do, but you asked:
I have an app that matches data that was inputted by a user in a text document. Can i skip lines with ofstream and not modify text already there? If possible, how?
However, I did not see any matching logic in your program. You are simply recording up to 2999 entries (since you don't use the 0 entry of your arrays), or wait until the user enters /end as a confirmation message.
If you had actual matching logic, you could detect on input whether the user has typed in the same clientName or same caseNumber, and you can prompt the user for what to do about it (for example, keep the old existing entry, keep newly entered entry). If you had such logic, you would know that you would only be outputting unique lines of data, and so your output loop would be fairly simple.
There were some comments made on your use of goto. Instead of the repeat: label, you could start another loop:
//repeat:
do {
// ...read in input, echo it back, wait for confirmation...
cin >> confirm;
if (confirm == "y") {
cout << "Confirmed" << endl;
break;
}
} while (confirm != "/end");
if (confirm == "/end") {
break;
}
In this code, anything other than a y or /end is treated the same as n.