Search

How to hide input via CLI with C++

Both displaying empty and displaying asterisks during user typing.


How to hide input via CLI with C++


Often we are developing an application that interacts with the user asking for the password and if he is doing it in the presence of someone or recording a video, the password will appear.

On most systems like UNIX this is already hidden by default. So let’s see how to do it with C++ .


Hiding the password

For this we will need to include the following headers:

#include <iostream> // To use 'std::cout' and 'std::cin'
#include <termios.h> // To use 'termios' and 'tcsetattr'
#include <unistd.h> // To use 'STDIN_FILENO'

iostream is already known and commonly used by us.

termios.h is a library that contains the definitions used by the I/O interfaces of terminal , it will be with it that we will hide the typed.

And unistd.h is a library that provides access to the POSIX operating system API and makes it compatible with any operating system and compiler.

After adding the headers, just:

  • Instantiate termios
  • Get the data from the terminal and store it in a variable with the tcgetattr() function
  • Create a new instance of termios, but this time to replicate the data from the previous instance so we can change
  • Hide the typed data and passing to the new instance with the tcsetattr() function after establishing the rule: newt.c_lflag &= ~ECHO;
  • Interact and get user-entered data with std::cout, getline() and std::cin, storing in a pre-declared variable
  • And finally, return the data display after finishing the program also with tcsetattr, but to return to the initial instance.

    Also in the code we added the data display (on the same line with \r) typed just for didactic reasons.


The code in short looks like this

vim hidden.cpp

#include <iostream>
#include <termios.h>
#include <unistd.h>

int main(int argc, char ** argv){
    termios oldt;
    tcgetattr(STDIN_FILENO, &oldt);
    termios newt = oldt;
    newt.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); // Hides

    std::string s;
    std::cout << "Enter your password: ";
    getline(std::cin, s);

    std::cout << "\rYour password is: " << s << '\n';
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return to display
    return EXIT_SUCCESS;
}

Compile and run: g++ hidden.cpp && ./a.out

Example:

Hide input, show password.

Hide input, show password


If during the optional std::cout you still want to replace the std::string with asterisks(*), add this snippet to your code:

std::string n{};
for (int i{}; i < s.length(); ++i){
  n += "*";
}
std::cout << "\rYour password is: " << n << '\n'; // now display 'n' instead of 's'

It will appear: Your password is: ************ .

Example:

Hide input, show asterisks.

Hides input, shows asterisks


We can see that the command in the terminal stty -echo (to hide the data typed in the terminal) and stty echo to return the display do the same thing. Note that the stty program/command makes use of the termios.h library.


Displaying asterisks instead of empty or letters

I see a lot of people asking this question on StackOverflow and honestly I’ve never seen an effective solution that actually solves it the way one wants, not even using the curses.h library(Note, curses.h, also compiles with: -lcurses -ltinfo, not NCURSES) .

So, I created a way that solves this in a simple way, using do while, excluding getline() and using getchar() instead:

Only the magic is on the line: newt.c_lflag &= 'a';, I replaced the ~ECHO with any letter/character, in this 'a'.

#include <iostream>
#include <termios.h>
#include <unistd.h>

int main(int argc, char ** argv){
    termios oldt;
    tcgetattr(STDIN_FILENO, &oldt);
    termios newt = oldt;
    newt.c_lflag &= 'a'; // remove ~ECHO
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); // Hides

    std::string s{}, current{};
    char c{};
    std::cout << "Enter your password: ";
    do {
      std::cout << current;
      s += c;
      current = "*";
    }while((c = getchar()) != '\n' && c != EOF);

    std::cout << "\rYour password is: " << s <<
    "                                 " << '\n';
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return to display
    return EXIT_SUCCESS;
}

It will appear: Enter your password: ************, that is, asterisks instead of empty.

Example:

Input asterisks, show password.

Input, show password


Useful links


cpp cppdaily


Share



Comments