C 在终端上隐藏密码输入

C 在终端上隐藏密码输入,c,linux,C,Linux,我想在使用*写入密码时屏蔽密码。 我使用LinuxGCC来编写这段代码。 我知道一个解决方案是像这样使用getch()函数 #include <conio.h> int main() { char c,password[10]; int i; while( (c=getch())!= '\n');{ password[i] = c; printf("*"); i++; } return 1;

我想在使用
*
写入密码时屏蔽密码。 我使用LinuxGCC来编写这段代码。 我知道一个解决方案是像这样使用
getch()
函数

#include <conio.h>   
int main()
{
    char c,password[10];
    int i;
    while( (c=getch())!= '\n');{
        password[i] = c;
        printf("*");
        i++;
    }
    return 1;
}
#包括
int main()
{
字符c,密码[10];
int i;
而((c=getch())!='\n'){
密码[i]=c;
printf(“*”);
i++;
}
返回1;
}
但问题是,
GCC
不包括
conio.h
文件,因此,
getch()
对我来说是无用的。
有人有解决方案吗?

您可以用这种方式在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;
}

可以使用以下代码模拟
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;
}
#包括
#包括
int getch(){
结构termios oldt,NETT;
int-ch;
tcgetattr(标准文件号和旧文件号);
newt=oldt;
newt.c|lflag&=~(ICANON | ECHO);
tcsetattr(标准文件号、TCSANOW和NETT);
ch=getchar();
tcsetattr(标准文件号、TCSANOW和oldt);
返回ch;
}

请注意,您的方法并不完美-最好使用ncurses或其他终端库来处理这些事情。

不幸的是,在C标准库中,没有现成的函数。也许在第三方图书馆


一个选项是使用ANSI转义序列在控制台中将背景色设置为前景色以隐藏密码。请尝试。

您的方法是正确的,但是在输入密码时,您需要关闭terminal echo:

#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);
}
#包括
void echo_off()
{
结构sgttyb状态;
(无效)ioctl(0,(int)TIOCGETP,(char*)和state);
state.sg_标志&=~ECHO;
(无效)ioctl(0,(int)TIOCSETP,(char*)和state);
}
void echo_on()
{
结构sgttyb状态;
(无效)ioctl(0,(int)TIOCGETP,(char*)和state);
state.sg_flags |=ECHO;
(无效)ioctl(0,(int)TIOCSETP,(char*)和state);
}

与其使用
getch()
,为什么不直接使用
getc()

如果不需要将ncurses.h移植到Windows上,您可以使用它,但这里有一种更“可移植”的版本:

如果不需要便携,我会为您提供一个ncurses解决方案

便携式Getch.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
/*portablegetch.h*/
#ifndef PGETCH
#定义PGETCH
#ifdef\uuuuunix__
#包括
#包括
静态结构术语n_术语;
静态结构术语;
静态整数
cbreak(内部fd)
{
if((tcgetattr(fd,&o_项))=-1)
返回-1;
n_项=o_项;
n_term.c_lflag=n_term.c_lflag&~(ECHO | ICANON);
n_项c_cc[VMIN]=1;
n_term.c_cc[VTIME]=0;
if((tcsetattr(fd、TCSAFLUSH和n_项))=-1)
返回-1;
返回1;
}
int
getch()
{
int-cinput;
如果(cbreak(标准文件号)=-1){
fprintf(标准,“cbreak故障,正在退出”);
退出(退出失败);
}
cinput=getchar();
tcsetattr(标准文件号、TCSANOW和o条款);
回输;
}
#elif | MSC | VER | | | | | | | WIN32 | | | | | MS | u DOS__
#包括
#恩迪夫
#恩迪夫
还有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;
}
#包括
#包括
#包括“portablegetch.h”
int
主(内部argc,字符**argv)
{
int输入;
printf(“请输入密码:\t”);
而((input=getch())!='\n')
printf(“*”);
printf(“\n”);
返回退出成功;
}
这应该适合你的问题


希望有帮助。

通过扫描字符,您可以将其放入缓冲区。如果按backspace,还需要编写代码,并适当地更正插入的密码

这是我曾经用诅咒写过的一段代码。使用gcc file.c-o pass\u 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;
}
#包括
#包括
#包括
#定义足够大的\u大小256
#在1上定义ECHO_
#定义ECHO_OFF 0
#定义后空间127
char*my_getpass(int echo_状态);
内部主(空)
{
字符*通行证;
initscr();
printw(“输入密码:”);
通过=我的获取通过(回显打开);
printw(“\n输入的密码:%s”,通过);
刷新();
getch();
endwin();
返回0;
}
char*my_getpass(int echo_状态)
{
char*pass,c;
int i=0;
pass=malloc(sizeof(char)*足够的大小);
if(pass==NULL)
{
佩罗(“退出”);
出口(1);
}
cbreak();
noecho();
而((c=getch())!='\n')
{
if(c==返回空间)
{
/*不要让缓冲区下溢*/
如果(i>0)
{ 
我--;
if(回显状态==回显开启)
printw(“\b\b”);
}
}
else如果(c=='\t')
;/*忽略选项卡*/
其他的
{
通过[i]=c;
i=(i>=足够大小)?足够大小-1:i+1;
if(回显状态==回显开启)
printw(“*”);
}
}
echo();
nocbreak();
/*用NUL终止密码字符串*/
通过[i]='\0';
endwin();
回程通行证;
}

在Linux世界中,屏蔽通常不使用星号,通常只关闭回声,终端显示空白,例如,如果您使用
su
或登录到虚拟终端等

有一个处理获取密码的库函数,它不会用星号屏蔽密码,但会禁用向终端回显密码。我从我的一本linux书中找到了这个。我相信这是posix标准的一部分

#包括
char*getpass(const char*prompt);
/*返回指向静态分配的输入密码字符串的指针
成功时为空,错误时为空*/
函数的作用是:首先禁用回显和对 终端特殊字符(如中断字符,通常为 对照组(C)

然后它打印提示符指向的字符串,并读取一行 输入,返回以null结尾的输入字符串,并带有尾随字符 换行符剥离,作为其功能结果

google对getpass()的搜索引用了GNU实现(应该在大多数linux发行版中),如果需要,还提供了一些示例代码来实现您自己的实现

他们的榜样
#include <unistd.h>
char *getpass(const char *prompt);

/*Returns pointer to statically allocated input password string
on success, or NULL on error*/
#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;
}
#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;
}
#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;
}
#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;
}
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

#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 =  (char*) 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)
# 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 */
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';