我希望在使用*
编写密码时屏蔽我的密码。
我使用Linux GCC代码。
我知道一个解决方案是使用像这样的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()
对我来说毫无用处。
有没有人有解决方案?
答案 0 :(得分:46)
在Linux世界中,屏蔽通常不用星号来完成,通常只是关闭回声并且终端显示空白例如。如果您使用su
或登录虚拟终端等
有一个库函数来处理获取密码,它不会用星号掩盖密码,但会禁止将密码回显到终端。我把它从我的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()函数首先禁用回显和所有处理 终端特殊字符(例如中断字符,通常 控制-C)。
然后打印提示符指向的字符串,并读取一行 输入,返回带尾部的以null结尾的输入字符串 新行剥离,作为其功能结果。
谷歌搜索getpass()有一个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;
}
如果需要,您可以使用此作为基础,修改它以显示星号。
答案 1 :(得分:9)
可以使用以下代码模拟getch
(非标准Windows功能)的功能:
#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 或其他终端库来处理这些事情。
答案 2 :(得分:9)
如果没有getch
依赖并避免过时的getpass
,建议的方法是通过termios
使用来禁用终端ECHO。在进行了几次搜索以找到一个灵活的密码例程之后,我很惊讶很少有人使用C语言进行单独使用。而不是简单地使用termios getch
选项重新编码c_lflag
,稍微更通用的方法只需要一些补充。除了替换getch
之外,任何例程都应该强制执行指定的最大长度以防止溢出,如果用户尝试输入超出最大值,则截断,并警告是否以某种方式发生截断。
下面,添加内容将允许从任何FILE *
输入流中读取,将长度限制为指定长度,在获取输入时提供最小编辑(退格)功能,允许完全指定或禁用字符掩码,最后返回输入密码的长度。输入的密码被截断为最大或指定长度时,会添加警告。
希望通过这个问题寻找类似的解决方案对其他人有用:
#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)
答案 3 :(得分:6)
您可以通过这种方式在Linux上创建自己的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;
}
答案 4 :(得分:3)
您的方法是正确的,但是在输入密码时您需要关闭终端回声:
#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()
呢?
答案 5 :(得分:2)
如果没有必要在Windows上移植,你可以使用ncurses.h,但这里有一些更“便携”的版本:
如果没有必要携带,请将您指向一个ncurses解决方案
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;
}
这应该适合你的问题。
希望有所帮助。
答案 6 :(得分:2)
感谢各位的帮助和帮助。支持解决我的问题。 我找到了一个最好的方法来隐藏我最适合我的密码。 要使用getpass()函数。它只需要包含“unistd.h”文件。
getpass函数的syntex:
char * getpass(const char * prompt)
参数: 提示:要求密码
时打印的字符串指针返回值: 密码的字符串指针
示例:
#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;
}
输出:
输入密码:
HEET
答案 7 :(得分:2)
#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;
}
只需复制这些代码段并使用它即可。希望它有所帮助
答案 8 :(得分:0)
不幸的是,在C标准库中没有开箱即用的功能。也许在第三方图书馆。
一个选项是使用ANSI转义序列在控制台中将背景颜色设置为前景色以隐藏密码。试试this link。
答案 9 :(得分:0)
扫描字符后,您可以将其带入缓冲区。如果按下退格键,您还需要编写代码,并适当地更正插入的密码。
这是我用curses编写的代码。使用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;
}
答案 10 :(得分:0)
在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
答案 11 :(得分:0)
人获取密码
此功能已过时。不要使用它。如果您想阅读输入 在未启用终端回显的情况下,请参见ECHO标志的描述 在termios(3)
# include <termios.h>
# include <unistd.h> /* needed for STDIN_FILENO which is an int file descriptor */
struct termios tp, save;
tcgetattr( STDIN_FILENO, &tp); /* get existing terminal properties */
save = tp; /* save existing terminal properties */
tp.c_lflag &= ~ECHO; /* only cause terminal echo off */
tcsetattr( STDIN_FILENO, TCSAFLUSH, &tp ); /* set terminal settings */
/*
now input by user in terminal will not be displayed
and cursor will not move
*/
tcsetattr( STDIN_FILENO, TCSANOW, &save); /* restore original terminal settings */
如果您注意到,大多数当前的Linux发行版都不会屏蔽带星号的密码。这样做会泄露密码的长度,这无济于事。键入密码时,简单地使光标不移动是更容易和更好的方法。如果出于任何原因,您要求为每个键入的字符打印一个*
,那么您必须在{{ 1}}被击中,这始终是有问题的。
答案 12 :(得分:0)
printf("\nENTER PASSWORD: ");
while (1)
{
ch=getch();
if(ch==13) //ON ENTER PRESS
break;
else if(ch==8) //ON BACKSPACE PRESS REMOVES CHARACTER
{
if(i>0)
{
i--;
password[i]='\0';
printf("\b \b");
}
}
else if (ch==32 || ch==9) //ON PRESSING TAB OR SPACE KEY
continue;
else
{
password[i]=ch;
i++;
printf("*");
}
}
password[i]='\0';
答案 13 :(得分:0)
这是我的想法,改编自the C++ official site。
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
string getpass(const char *prompt, bool showchar = false, char echochar = '*')
{
struct termios oi, ni;
tcgetattr(STDIN_FILENO, &oi);
ni = oi;
ni.c_lflag &= ~(ICANON | ECHO);
const char DELETE = 127;
const char RETURN = 10;
string password;
unsigned char ch = 0;
cout << prompt;
tcsetattr(STDIN_FILENO, TCSANOW, &ni);
while (getchar() != RETURN) {
if (ch == DELETE) {
if(password.length != 0){
if (showchar) cout << "\b \b";
password.resize(password.length() - 1);
}
}else {
password += getchar();
if (showchar) cout << echochar;
}
}
tcsetattr(STDIN_FILENO,TCSANOW,&oi)
cout << endl;
return password;
}
它将立即读取一个字符并将其添加到字符串中,并支持显示另一个字符。
答案 14 :(得分:-1)
请注意,ICANON termios lflag会关闭处理回车/换行,负ECHO termios设置会关闭STDIN的回声。
当使用它(有或没有回声)来读取密码并打印'*'
输入的字符时,不仅仅是在遇到换行/回车之前读取字符,你还有在“字符串构建例程”中处理退格(否则退格会以实际字符串结尾,并且不会导致从中删除字符,例如各种基于字符串的输入函数的情况)。
0x08
退格(或127或你的特定操作系统用作退格的任何东西)
跟踪'不删除-before-字符串的开头',将'字符串的新结尾'替换为0并将当前位置计数器移回1(除非您处于位置0)取决于具有任何这些功能的程序员(甚至是dos C上的getch)。
getpass()
没有做用户最初要求的顺便说一句,他想要*(它仍然向站在他身后的人看着他的屏幕,以及在终端的滚动缓冲区,如果他在使用后没有关闭它)。但是,在“非封闭环境”中,没有*可能是一个更好的主意。