Como esconder a entrada de dados via CLI com C++

Tanto exibindo vazio quanto exibindo asteriscos durante a digitação do usuário.


Como esconder a entrada de dados via CLI com C++


Muitas vezes estamos desenvolvendo uma aplicação que interage com usuário solicitando a senha e se ele estiver fazendo isso com a presença de alguém ou gravando um vídeo, a senha irá aparecer.

Na maioria dos sistemas tipo UNIX isso já é escondido por padrão. Então vamos ver como fazer isso com C++ .


Escondendo a senha

Para isso vamos precisar incluir os seguintes cabeçalhos:

#include <iostream> // Para usar 'std::cout' e 'std::cin'
#include <termios.h> // Para usar 'termios' e 'tcsetattr'
#include <unistd.h> // Para usar 'STDIN_FILENO'

A iostream já é conhecida e comumente utilizada por nós.

Já a termios.h é uma biblioteca que contém as definições usadas pelas interfaces de E/S do terminal , será com ela que iremos esconder o digitado.

E o unistd.h é uma biblioteca que fornece acesso à API do sistema operacional POSIX e torna compatível com qualquer sistema operacional e compilador.

Após adicionar os cabeçalhos, basta:

  • Instanciar o termios
  • Obter os dados do terminal e guardar em uma variável com a função tcgetattr()
  • Criar uma nova instância do termios, mas dessa vez para replicarmos os dados da instância anterior para podermos alterar
  • Esconder os dados digitados e passando para a nova instância com a função tcsetattr() após estabelecer a regra: newt.c_lflag &= ~ECHO;
  • Interagir e obter os dados digitados pelo usuário com std::cout, getline() e std::cin, armazenando em uma variável pré declarada
  • E por final retornar a exibição dos dados após finalizar o programa também com tcsetattr, mas para devolvermos à instância inicial.

    Além disso no código adicionamos a exibição dos dados(na mesma linha com \r) digitados só por questões didáticas.


O código em resumo fica assim

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); // esconde

    std::string s;
    std::cout << "Informe sua senha: ";
    getline(std::cin, s);

    std::cout << "\rSua senha é: " << s << '\n';
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // retorna à exibir
    return EXIT_SUCCESS;
}

Compile e rode: g++ hidden.cpp && ./a.out

Exemplo:

Esconde input, mostra senha.

Esconde input, mostra senha


Se durante o std::cout opcional você ainda quiser trocar a std::string por asteriscos(*), adicione esse trecho ao seu código:

std::string n{};
for (int i{}; i < s.length(); ++i){
  n += "*";
}
std::cout << "\rSua senha é: " << n << '\n'; // exiba agora 'n' em vez de 's'

Aparecerá: Sua senha é: ************ .

Exemplo:

Esconde input, mostra asteriscos.

Esconde input, mostra asteriscos


Podemos notar que o comando no terminal stty -echo(para esconder os dados digitados no terminal) e stty echo para retornar a exibição faz a mesma coisa. Nota-se que o programa/comando stty faz uso da biblioteca termios.h.


Exibindo asteriscos em vez de vazio ou letras

Eu vejo muita gente fazendo essa pergunta no StackOverflow e sinceramente nunca vi uma solução eficaz que realmente resolva do jeito que a pessoa deseja, nem usando a biblioteca curses.h(Observação, curses.h, compila também com: -lcurses -ltinfo, não é NCURSES) .

Então, eu criei uma forma que resolve isso de maneira simples, utilizando do while, excluindo o getline() e utilizando getchar() no lugar:

Só que a mágica está na linha: newt.c_lflag &= 'a';, eu troquei o ~ECHO por qualquer letra/caractere, nesse o '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'; // removi o ~ECHO
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); // esconde

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

    std::cout << "\rSua senha é: " << s << 
    "                                     " << '\n';
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // retorna à exibir
    return EXIT_SUCCESS;
}

Aparecerá: Informe sua senha: ************, ou seja, asteriscos em vez de vazio.

Exemplo:

Input asteriscos, mostra senha.

Input, mostra senha


Aprenda C++:

https://terminalroot.com.br/cpp


Links úteis


cpp cppdaily


Compartilhe


Nosso canal no Youtube

Inscreva-se


Marcos Oliveira

Marcos Oliveira

Desenvolvedor de software
https://github.com/terroo


Crie Aplicativos Gráficos para Linux e Windows com C++

Aprenda C++ Moderno e crie Games, Programas CLI, GUI e TUI de forma fácil.

Saiba Mais

Receba as novidades no seu e-mail!

Após cadastro e confirmação do e-mail, enviaremos semanalmente resumos e também sempre que houver novidades por aqui para que você mantenha-se atualizado!