Secure Password Input in C++
How do I handle password input where characters should not be displayed?
Handling password input securely, where characters are not displayed as they're typed, is an important feature for many applications.
In C++, this isn't as straightforward as in some other languages, but we can achieve it using platform-specific functions. Let's explore how to do this on both Windows and Unix-like systems (Linux, macOS).
Windows Implementation
For Windows, we'll use the _getch()
function from <conio.h>
:
#include <iostream>
#include <string>
#include <conio.h> // Windows-specific header
std::string getPassword(){
std::string password;
char ch;
// Read until Enter is pressed
while ((ch = _getch()) != '\r') {
// Handle backspace
if (ch == '\b') {
if (!password.empty()) {
std::cout << "\b \b";
password.pop_back();
}
} else {
password += ch;
std::cout << '*';
}
}
std::cout << '\n';
return password;
}
int main(){
std::cout << "Enter password: ";
std::string password = getPassword();
std::cout << "Password entered: " << password;
}
This Windows implementation uses _getch()
to read characters without echoing them to the console. We print an asterisk for each character entered to provide visual feedback.
Enter password: ******
Password entered: secret
Unix-like Systems Implementation
For Unix-like systems, we'll use the termios.h
header to modify terminal attributes:
#include <iostream>
#include <string>
#include <termios.h>
#include <unistd.h>
std::string getPassword(){
std::string password;
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
char ch;
while ((ch = getchar()) != '\n') {
if (ch == 127) {
// Handle backspace
if (!password.empty()) {
std::cout << "\b \b";
password.pop_back();
}
} else {
password += ch;
std::cout << '*';
}
}
std::cout << '\n';
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return password;
}
int main(){
std::cout << "Enter password: ";
std::string password = getPassword();
std::cout << "Password entered: " << password;
}
Enter password: ******
Password entered: secret
In this Unix-like system implementation, we temporarily disable echo in the terminal, read characters one by one, and restore the original terminal settings afterwards.
Cross-platform Solution
To create a cross-platform solution, you can use conditional compilation:
#include <iostream>
#include <string>
#ifdef _WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#endif
std::string getPassword(){
std::string password;
#ifdef _WIN32
// Windows implementation
char ch;
while ((ch = _getch()) != '\r') {
if (ch == '\b') {
if (!password.empty()) {
std::cout << "\b \b";
password.pop_back();
}
} else {
password += ch;
std::cout << '*';
}
}
#else
// Unix-like implementation
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
char ch;
while ((ch = getchar()) != '\n') {
if (ch == 127) {
if (!password.empty()) {
std::cout << "\b \b";
password.pop_back();
}
} else {
password += ch;
std::cout << '*';
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif
std::cout << '\n';
return password;
}
int main(){
std::cout << "Enter password: ";
std::string password = getPassword();
std::cout << "Password entered: " << password;
}
Enter password: ******
Password entered: secret
This cross-platform solution uses conditional compilation to choose the appropriate implementation based on the target platform.
Remember, while these methods hide password input from the screen, they don't provide complete security. For production systems, consider using secure password hashing algorithms and avoid storing plaintext passwords.
User Input in the Terminal
This lesson introduces the fundamentals of capturing user input, using std::cin
and std::getline()