Ocultar entrada de contraseña en la terminal

Quiero enmascarar mi contraseña mientras la escribo con * . Yo uso Linux GCC para este código. Sé que una solución es usar la función getch() como esta

 #include  int main() { char c,password[10]; int i; while( (c=getch())!= '\n');{ password[i] = c; printf("*"); i++; } return 1; } 

pero el problema es que GCC no incluye el archivo conio.h , así que getch() es inútil para mí. ¿Alguien tiene una solución?

En el mundo Linux, el enmascaramiento generalmente no se realiza con asteriscos, normalmente el eco se apaga y el terminal muestra espacios en blanco. Por ejemplo, si usa su o ingresa en un terminal virtual, etc.

Hay una función de biblioteca para manejar contraseñas, no enmascara la contraseña con asteriscos, pero desactivará el eco de la contraseña a la terminal. Saqué esto de un libro de Linux que tengo. Creo que es parte del estándar posix

 #include  char *getpass(const char *prompt); /*Returns pointer to statically allocated input password string on success, or NULL on error*/ 

La función getpass () primero desactiva el eco y todo el procesamiento de los caracteres especiales del terminal (como el carácter de interrupción, normalmente Control-C).

A continuación, imprime la cadena señalada por solicitud y lee una línea de entrada, devolviendo la cadena de entrada terminada en nulo con la nueva línea arrastrada como resultado de su función.

Una búsqueda en google para getpass () tiene una referencia a la implementación de GNU (debe estar en la mayoría de las distribuciones de Linux) y algún código de muestra para implementar la suya si es necesario.

http://www.gnu.org/s/hello/manual/libc/getpass.html

Su ejemplo para hacer su propio:

 #include  #include  ssize_t my_getpass (char **lineptr, size_t *n, FILE *stream) { struct termios old, new; int nread; /* Turn echoing off and fail if we can't. */ if (tcgetattr (fileno (stream), &old) != 0) return -1; new = old; new.c_lflag &= ~ECHO; if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0) return -1; /* Read the password. */ nread = getline (lineptr, n, stream); /* Restore terminal. */ (void) tcsetattr (fileno (stream), TCSAFLUSH, &old); return nread; } 

Si es necesario, puede usar esto como base para modificarlo y mostrar asteriscos.

La funcionalidad de getch (que es una función de Windows no estándar) se puede emular con este código:

 #include  #include  int getch() { struct termios oldt, newt; int ch; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return ch; } 

Tenga en cuenta que su enfoque no es perfecto: es mejor usar algo como ncurses u otra biblioteca de terminal para manejar estas cosas.

Sin getch para confiar y evitar el getpass obsoleto, el enfoque recomendado es desactivar ECHO terminal a través del uso de termios . Después de algunas búsquedas para encontrar una rutina de contraseñas flexibles enlatadas, me sorprendió que fueran muy pocas las que usaran de forma independiente con C. En lugar de simplemente recodificar las opciones getch con termios c_lflag , un enfoque un poco más general solo requiere algunas adiciones. Más allá de reemplazar getch cualquier rutina debe hacer cumplir una longitud máxima especificada para evitar el desbordamiento, truncar si el usuario intenta ingresar más allá del máximo, y advertir si el truncamiento ocurre de alguna manera.

A continuación, las adiciones permitirán leer desde cualquier flujo de entrada FILE * , limitar la duración a una longitud especificada, proporcionar una capacidad mínima de edición (retroceso) al tomar entrada, permitir que la máscara de caracteres se especifique o deshabilite por completo, y finalmente devolver la longitud de la contraseña ingresada. Se agregó una advertencia cuando la contraseña introducida se truncó al máximo o la longitud especificada.

Esperemos que resulte útil para otros con esta pregunta en busca de una solución similar:

 #include  #include  #include  #include  #include  #include  /* for errno */ #include  /* for EINTR */ #define MAXPW 32 /* read a string from fp into pw masking keypress with mask char. getpasswd will read upto sz - 1 chars into pw, null-terminating the resulting string. On success, the number of characters in pw are returned, -1 otherwise. */ ssize_t getpasswd (char **pw, size_t sz, int mask, FILE *fp) { if (!pw || !sz || !fp) return -1; /* validate input */ #ifdef MAXPW if (sz > MAXPW) sz = MAXPW; #endif if (*pw == NULL) { /* reallocate if no address */ void *tmp = realloc (*pw, sz * sizeof **pw); if (!tmp) return -1; memset (tmp, 0, sz); /* initialize memory to 0 */ *pw = tmp; } size_t idx = 0; /* index, number of chars in read */ int c = 0; struct termios old_kbd_mode; /* orig keyboard settings */ struct termios new_kbd_mode; if (tcgetattr (0, &old_kbd_mode)) { /* save orig settings */ fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__); return -1; } /* copy old to new */ memcpy (&new_kbd_mode, &old_kbd_mode, sizeof(struct termios)); new_kbd_mode.c_lflag &= ~(ICANON | ECHO); /* new kbd flags */ new_kbd_mode.c_cc[VTIME] = 0; new_kbd_mode.c_cc[VMIN] = 1; if (tcsetattr (0, TCSANOW, &new_kbd_mode)) { fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__); return -1; } /* read chars from fp, mask if valid char specified */ while (((c = fgetc (fp)) != '\n' && c != EOF && idx < sz - 1) || (idx == sz - 1 && c == 127)) { if (c != 127) { if (31 < mask && mask < 127) /* valid ascii char */ fputc (mask, stdout); (*pw)[idx++] = c; } else if (idx > 0) { /* handle backspace (del) */ if (31 < mask && mask < 127) { fputc (0x8, stdout); fputc (' ', stdout); fputc (0x8, stdout); } (*pw)[--idx] = 0; } } (*pw)[idx] = 0; /* null-terminate */ /* reset original keyboard */ if (tcsetattr (0, TCSANOW, &old_kbd_mode)) { fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__); return -1; } if (idx == sz - 1 && c != '\n') /* warn if pw truncated */ fprintf (stderr, " (%s() warning: truncated at %zu chars.)\n", __func__, sz - 1); return idx; /* number of chars in passwd */ } 

Un progtwig simple que muestra el uso sería el siguiente. Si usa una matriz estática de caracteres para mantener la contraseña, solo asegúrese de que se pase un puntero a la función.

 int main (void ) { char pw[MAXPW] = {0}; char *p = pw; FILE *fp = stdin; ssize_t nchr = 0; printf ( "\n Enter password: "); nchr = getpasswd (&p, MAXPW, '*', fp); printf ("\n you entered : %s (%zu chars)\n", p, nchr); printf ( "\n Enter password: "); nchr = getpasswd (&p, MAXPW, 0, fp); printf ("\n you entered : %s (%zu chars)\n\n", p, nchr); return 0; } 

Ejemplo de salida

 $ ./bin/getpasswd2 Enter password: ****** you entered : 123456 (6 chars) Enter password: you entered : abcdef (6 chars) 

Puede crear su propia función getch() en Linux de esta manera.

 int getch() { struct termios oldtc, newtc; int ch; tcgetattr(STDIN_FILENO, &oldtc); newtc = oldtc; newtc.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newtc); ch=getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldtc); return ch; } 

Código de demostración:

 int main(int argc, char **argv) { int ch; printf("Press x to exit.\n\n"); for (;;) { ch = getch(); printf("ch = %c (%d)\n", ch, ch); if(ch == 'x') break; } return 0; } 

Su método es correcto, sin embargo, deberá desactivar el eco del terminal mientras se ingresa la contraseña:

 #include  void echo_off() { struct sgttyb state; (void)ioctl(0, (int)TIOCGETP, (char *)&state); state.sg_flags &= ~ECHO; (void)ioctl(0, (int)TIOCSETP, (char *)&state); } void echo_on() { struct sgttyb state; (void)ioctl(0, (int)TIOCGETP, (char *)&state); state.sg_flags |= ECHO; (void)ioctl(0, (int)TIOCSETP, (char *)&state); } 

En lugar de getch() , ¿por qué no usar getc() lugar?

Gracias a todos ustedes por su ayuda y apoyo para resolver mi problema. Encuentro la mejor manera de ocultar mi contraseña en Linux que mejor se adapta a mí. Para usar la función getpass (). Solo necesita incluir el archivo “unistd.h”.

syntex de la función getpass:

char * getpass (prompt de const char *)

Parámetros: prompt: puntero de cadena para imprimir mientras se solicita la contraseña

Valor devuelto: puntero de cadena de contraseña

Ejemplo:

 #include  #include  int main() { char *password; // password string pointer password = getpass("Enter Password: "); // get a password printf("%s\n",password); // this is just for conformation // that password stored successfully return 1; } 

salida:

Introducir la contraseña:

Heet

Puede usar ncurses.h si no es necesario ser portátil en Windows para eso, pero aquí hay una especie de versión más “portátil”:

Si no es necesario que sea portátil, apunte a una solución ncurses

portablegetch.h

 /*portablegetch.h*/ #ifndef PGETCH #define PGETCH #ifdef __unix__ #include  #include  static struct termios n_term; static struct termios o_term; static int cbreak(int fd) { if((tcgetattr(fd, &o_term)) == -1) return -1; n_term = o_term; n_term.c_lflag = n_term.c_lflag & ~(ECHO|ICANON); n_term.c_cc[VMIN] = 1; n_term.c_cc[VTIME]= 0; if((tcsetattr(fd, TCSAFLUSH, &n_term)) == -1) return -1; return 1; } int getch() { int cinput; if(cbreak(STDIN_FILENO) == -1) { fprintf(stderr, "cbreak failure, exiting \n"); exit(EXIT_FAILURE); } cinput = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &o_term); return cinput; } #elif _MSC_VER || __WIN32__ || __MS_DOS__ #include  #endif #endif 

Y el archivo c

lo que sea.c

 #include  #include  #include "portablegetch.h" int main(int argc, char **argv) { int input; printf("Please Enter your Password:\t"); while(( input=getch() ) != '\n') printf("*"); printf("\n"); return EXIT_SUCCESS; } 

Eso debería encajar con tu problema.

Espero que ayude.

 #include  #include  static struct termios old, new; void initTermios(int echo) { tcgetattr(0, &old); new = old; new.c_lflag &= ~ICANON; new.c_lflag &= echo ? ECHO : ~ECHO; tcsetattr(0, TCSANOW, &new); } void resetTermios(void) { tcsetattr(0, TCSANOW, &old); } char getch_(int echo) { char ch; initTermios(echo); ch = getchar(); resetTermios(); return ch; } char getch(void) { return getch_(0); } int main(void) { char c; printf("(getch example) please type a letter..."); c = getch(); printf("\nYou typed: %c\n", c); return 0; } 

Solo copie estos fragmentos y úselos. Espero que haya ayudado

Desafortunadamente en la biblioteca estándar C no hay tal función lista para usar. Tal vez en una biblioteca de terceros.

Una opción es usar secuencias de escape ANSI para establecer el color de fondo en color de primer plano en la consola para ocultar la contraseña. Prueba este enlace

Al escanear los caracteres, puede llevarlo a un búfer. También debe escribir el código si se presiona la tecla de retroceso y corregir correctamente la contraseña insertada.

Aquí hay un código que una vez escribí con las maldiciones. Comstackr con gcc file.c -o pass_prog -lcurses

 #include  #include  #include  #define ENOUGH_SIZE 256 #define ECHO_ON 1 #define ECHO_OFF 0 #define BACK_SPACE 127 char *my_getpass (int echo_state); int main (void) { char *pass; initscr (); printw ("Enter Password: "); pass = my_getpass (ECHO_ON); printw ("\nEntered Password: %s", pass); refresh (); getch (); endwin (); return 0; } char *my_getpass (int echo_state) { char *pass, c; int i=0; pass = malloc (sizeof (char) * ENOUGH_SIZE); if (pass == NULL) { perror ("Exit"); exit (1); } cbreak (); noecho (); while ((c=getch()) != '\n') { if (c == BACK_SPACE) { /* Do not let the buffer underflow */ if (i > 0) { i--; if (echo_state == ECHO_ON) printw ("\b \b"); } } else if (c == '\t') ; /* Ignore tabs */ else { pass[i] = c; i = (i >= ENOUGH_SIZE) ? ENOUGH_SIZE - 1 : i+1; if (echo_state == ECHO_ON) printw ("*"); } } echo (); nocbreak (); /* Terminate the password string with NUL */ pass[i] = '\0'; endwin (); return pass; } 

En C puede usar la función getpasswd() que hace algo similar a stty in shell, por ejemplo:

 #include  #include  #include  #include  int main() { char acct[80], password[80]; printf(“Account: “); fgets(acct, 80, stdin); acct[strlen(acct)-1] = 0; /* remove carriage return */ strncpy(password, getpass(“Password: “), 80); printf(“You entered acct %s and pass %s\n”, acct, password); return 0; } 

Aquí hay un script de shell equivalente que usa stty (que cambia la configuración de su tty ):

 save_state=$(stty -g) /bin/echo -n “Account: “ read acct /bin/echo -n “Password: “ stty -echo read password # this won't echo stty “$save_state” echo “” echo account = $acct and password = $password 

Fuente: ¿Cómo puedo leer una contraseña sin hacer eco en C?

tenga en cuenta que el ICANON termios lflag desactiva el procesamiento carriagereturn / linefeed, y el ajuste ECHO termios negativo desactiva el eco para STDIN.

cuando utiliza esto (con o sin el eco activado) para leer una contraseña e imprimir '*' para los caracteres ingresados, no se trata solo de leer caracteres hasta que se encuentre una nueva línea / retorno de carro, también debe procesar el retroceso en su ‘rutina de creación de cadenas’ (de lo contrario, los espacios posteriores terminan en la cadena real, y no hacen que los caracteres sean eliminados, como sería el caso con las diversas funciones de entrada basadas en cadenas).

lo mismo sucedería en C en DOS con getch tho. que también devolvería felizmente 0x08 para el retroceso (o 127 o lo que sea que tu os específico use como retroceso)

El seguimiento de “no borrar -antes del comienzo de la cadena”, reemplazar el “nuevo final de la cadena” por 0 y mover el contador de posición actual hacia atrás por uno (a menos que esté en la posición 0) depende del progtwigdor con cualquiera de estas funciones (incluso el getch en dos C).

getpass() no hace lo que el usuario originalmente pidió por cierto, quiere * (que todavía revela la longitud de la contraseña a las personas que están detrás de él y mirando su pantalla, así como en el buffer de desplazamiento de la terminal si no lo cierra después de su uso). pero sin * es probablemente una mejor idea en “entornos no cerrados”.