隐藏terminal上的密码input

我想在使用*写入密码时掩盖我的密码。 我使用Linux GCC代码。 我知道一个解决scheme是像这样使用getch()函数

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

但问题是GCC不包含conio.h文件,所以, getch()对我来说是没用的。 有没有人有解决scheme?

在Linux世界中,掩码通常不会用星号来完成,通常回显function是closures的,terminal显示空白。例如,如果使用su或login到虚拟terminal等。

有一个库函数来处理获取密码,它不会用星号屏蔽密码,但会禁用terminal回显密码。 我把这个从我的Linux书中拿出来。 我相信它是posix标准的一部分

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

getpass()函数首先禁止回显和terminal特殊字符(如中断字符,通常是Control-C)的所有处理。

然后打印出提示所指向的string,并读取一行input,并返回以空行结尾的inputstring和尾随的换行符作为其函数结果。

一个谷歌searchgetpass()有一个GNU实现(应该在大多数Linux发行版)和一些示例代码实现自己的,如果需要的引用

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

他们自己的榜样:

 #include <termios.h> #include <stdio.h> 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; } 

如果需要的话,你可以用这个作为修改它的基础来显示星号。

getch (这是一个非标准的Windows函数)的function可以用下面的代码来模拟:

 #include <termios.h> #include <unistd.h> 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; } 

请注意,你的方法并不完美 – 最好使用像ncurses或其他terminal库来处理这些事情。

如果没有getch依靠和避免过时的getpass ,推荐的方法是通过termios使用终止ECHOterminal。 经过几次searchfind一个灵活的密码例行程序,我很惊讶,很less单独使用C.而不是简单地使用termios c_lflag选项重新编码getch ,略微更普遍的方法只需要几个补充。 除了replacegetch之外,任何例程都应该强制执行指定的最大长度以防止溢出,如果用户尝试超出最大值,则截断,并且以某种方式发出截断警告。

在下面,添加将允许从任何FILE *inputstream中读取,将长度限制为指定的长度,在input时提供最小的编辑(退格)能力,允许完全指定或禁用字符掩码,最后返回input的密码。 当input的密码被截断为最大或指定的长度时,会添加警告。

希望这个问题对于其他人来说也是有用的,寻找类似的解决scheme:

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <termios.h> #include <errno.h> /* for errno */ #include <unistd.h> /* 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 */ } 

显示使用的简单程序如下。 如果使用字符的静态数组来保存密码,只要确保指针传递给函数。

 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; } 

示例输出

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

你可以用这种方式在Linux上创build自己的getch()函数。

 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; } 

演示代码:

 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; } 

你的方法是正确的,但是你需要在input密码时closuresterminal回显:

 #include <sgtty.h> 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); } 

而不是getch() ,为什么不使用getc()呢?

感谢大家的帮助和支持,以解决我的问题。 我发现一个最好的方式来隐藏我的密码在Linux最适合我。 使用getpass()函数。 它只需要包含“unistd.h”文件。

getpass函数的syntex:

char * getpass(const char *提示符)

参数:prompt:要求input密码的string指针

返回值:密码的string指针

例:

 #include <stdio.h> #include <unistd.h> 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; } 

输出:

input密码:

HEET

你可以使用ncurses.h,如果没有必要将它移植到Windows上,但是这里有一些更“便携”的版本:

如果不是便携式的,那么你需要一个ncurses解决scheme

portablegetch.h

 /*portablegetch.h*/ #ifndef PGETCH #define PGETCH #ifdef __unix__ #include <termios.h> #include <unistd.h> 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 <conio.h> #endif #endif 

和c文件

whatever.c

 #include <stdio.h> #include <stdlib.h> #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; } 

这应该适合你的问题。

希望有所帮助。

 #include <termios.h> #include <stdio.h> 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; } 

只需复制这些片段并使用它。 希望它有帮助

不幸的是在C标准库中没有这样的function。 也许在第三方库。

一种select是使用ANSI转义序列将背景颜色设置为控制台中的前景色以隐藏密码。 试试这个链接 。

通过扫描字符,您可以将其放入缓冲区。 如果退格被按下,你也需要编写代码,并正确地修改插入的密码。

这是一个我曾经用curses写的代码。 用gcc file.c -o pass_prog -lcurses编译gcc file.c -o pass_prog -lcurses

 #include <stdio.h> #include <stdlib.h> #include <curses.h> #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; } 

在C中,可以使用getpasswd()函数,它几乎和shell中的stty类似,比如:

 #include <stdio.h> #include <string.h> #include <pwd.h> #include <unistd.h> 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; } 

这是使用stty (它改变你的tty的设置)的等效shell脚本:

 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 

来源: 我怎样才能读取密码,而不用在C中回显它?

请注意,ICANON termios lflag会closures处理回车/换行符,负ECHO termios设置会closuresSTDIN的回显。

当使用这个(有或者没有回显)读取一个密码并为input的字符打印'*' ,它不仅仅是一个阅读字符的事情,直到遇到一个换行符/回车符,你还必须在你的回退'stringbuild立例程'(否则后退最终在实际的string,并不会导致字符被删除,如各种基于string的inputfunction的情况)。

在DOS下的C中也会发生同样的错误。 也会很高兴地返回0x08退格(或127或任何您特定的操作系统使用退格)

跟踪“不删除string的起始位置”,用“0”replace“string的新结尾”,并将当前位置计数器移回1(除非位于位置0)由程序员决定这些function中的任何一个(即使是C上的getch)。

getpass()没有做用户最初要求的btw,他想要*(它仍然向站在他身后的人们展示密码的长度,看他的屏幕,以及在terminal的滚动缓冲区使用后他没有closures它)。 但在没有*的情况下,在“非封闭环境”中可能是一个更好的主意。