隐藏终端上的密码输入

发布于 2024-11-27 03:27:18 字数 419 浏览 2 评论 0原文

我想在使用 * 写入密码时隐藏密码。 我使用 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 文件,因此,< code>getch() 对我来说没用。 有人有解决办法吗?

I want to mask my password while writing it with *.
I use Linux GCC for this code.
I know one solution is to use getch() function like this

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

but the problem is that GCC does not include conio.h file so, getch() is useless for me.
Does anyone have a solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

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

有一个库函数为了处理获取密码,它不会用星号掩盖密码,但会禁用密码到终端的回显。这是我从一本 Linux 书中摘下来的。我相信它是 posix 标准的一部分

#include ;
char *getpass(const char *提示);

/*返回指向静态分配的输入密码字符串的指针
成功时为 NULL,错误时为 NULL*/

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

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

In the Linux world, masking isn't usually done with asterisks, normally echoing is just turned off and the terminal displays blanks E.g. if you use su or log into a virtual terminal etc.

There is a library function to handle getting passwords, it won't mask the password with asterisks but will disable echoing of the password to terminal. I pulled this out of a linux book I have. I believe its part of the posix standard

#include <unistd.h>
char *getpass(const char *prompt);

/*Returns pointer to statically allocated input password string
on success, or NULL on error*/

The getpass() function first disables echoing and all processing of
terminal special characters (such as the interrupt character, normally
Control-C).

It then prints the string pointed to by prompt, and reads a line of
input, returning the null-terminated input string with the trailing
newline stripped, as its function result.

A google search for getpass() has a reference to the GNU implementation (should be in most linux distros) and some sample code for implementing your own if need be

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

Their example for rolling your own:

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

If need be you could use this as the basis as modify it to display asterisks.

居里长安 2024-12-04 03:27:19

如果不依赖 getch 并避免过时的 getpass,建议的方法是通过使用 termios 禁用终端 ECHO。经过几次搜索,找到了一个固定的灵活密码例程,令我惊讶的是,很少有人可以单独使用 C。而不是简单地使用 termios c_lflag 选项重新编码 getch,稍微更通用的方法只需添加一些内容。除了替换 getch 之外,任何例程都应该强制执行指定的最大长度以防止溢出,如果用户尝试输入超出最大值则进行截断,并在以某种方式发生截断时发出警告。

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

希望它对其他寻求类似解决方案的问题有用:

#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)

Without getch to rely on and avoiding the obsolete getpass, the recommended approach is to disable terminal ECHO through termios use. After a few searches to find a canned flexible password routine, I was surprised that very few for stand-alone use with C. Rather than simply recoding getch with termios c_lflag options, slightly more generalized approach takes just a few additions. Beyond replacing getch any routine should enforce a specified maximum length to prevent overflow, truncate if the user attempt to enter beyond the maximum, and warn if truncation occurs in some manner.

Below, the additions will allow reading from any FILE * input stream, limiting the length to a specified length, provide minimal editing (backspace) ability when taking input, allow the character mask to be specified or disabled completely, and finally return the length of the password entered. A warning was added when the password entered was truncated to the maximum or specified length.

Hopefully it will prove useful to others with this question looking for a similar solution:

#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    */
}

A simple program showing the use would be as follows. If using a static array of character for holding the password, just insure a pointer is passed to the function.

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

Example Output

$ ./bin/getpasswd2

 Enter password: ******
 you entered   : 123456  (6 chars)

 Enter password:
 you entered   : abcdef  (6 chars)
猫卆 2024-12-04 03:27:19

可以使用以下代码模拟 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 这样的东西> 或另一个终端库来处理这些事情。

The functionality of getch (which is a non-standard, Windows function) can be emulated with this code:

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

Note that your approach is not perfect - it's better to use something like ncurses or another terminal library to handle these things.

倾`听者〃 2024-12-04 03:27:19

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

You can create your own getch() function on Linux in this manner.

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

Demo code:

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;
}
栀梦 2024-12-04 03:27:19

感谢大家的帮助和帮助!支持解决我的问题。
我找到了最适合我的在 Linux 中隐藏密码的最佳方法。
使用 getpass() 函数。它只需要包含“unistd.h”文件。

getpass 函数的语法:

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

输出:

Enter 密码:

heet

Thanks all of you whose help & support to solve my problem.
I find a best way to hide my password in linux that fits me best.
To use getpass() function. It just need to include "unistd.h" file.

syntex of getpass function:

char * getpass (const char *prompt)

Parameters:
prompt: string pointer to print while asking for Password

Return Value:
string pointer of password

Example:

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

output:

Enter Password:

heet

肥爪爪 2024-12-04 03:27:19

您的方法是正确的,但是您需要在输入密码时关闭终端回显:

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

为什么不直接使用 getc() 而不是 getch()

Your method is correct, however you'll need to turn off terminal echo while the password is being entered:

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

Instead of getch(), why not just use getc() instead?

来世叙缘 2024-12-04 03:27:19

如果不需要移植到 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;
}

应该适合你的问题。

希望有帮助。

You might use ncurses.h if it is not necessary to be portable onto Windows for that, but here is some kind of a more "portable" version:

If it is not necessery to be portable ill point you to a ncurses solution

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

And the c-file

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

That should fit to your problem.

Hope that helps.

_畞蕅 2024-12-04 03:27:19
#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 <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;
}

Just copy these snippet and use it. Hope it helped

花开雨落又逢春i 2024-12-04 03:27:19

只需传递您想要设置密码的 char* 及其大小,该函数就会完成其工作

void set_Password(char *get_in, int sz){
    for (int i = 0; i < sz;) {
        char ch = getch();
        if (ch == 13) {
            get_in[i] = '\0';
            break;
        }
        else if(ch != 8){
            get_in[i++] = ch;
            putch('*');
        }
        else if(i > 0)
            cout << "\b \b",get_in[i--] = '\0';
    }
    cout << "\n";
}

这是一个示例,在你的编译器上运行它

Just pass for it the char* that you want to set password in and its size and the function will do its job

void set_Password(char *get_in, int sz){
    for (int i = 0; i < sz;) {
        char ch = getch();
        if (ch == 13) {
            get_in[i] = '\0';
            break;
        }
        else if(ch != 8){
            get_in[i++] = ch;
            putch('*');
        }
        else if(i > 0)
            cout << "\b \b",get_in[i--] = '\0';
    }
    cout << "\n";
}

This is an example, run it on your compiler

紫轩蝶泪 2024-12-04 03:27:19

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

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

Unfortunately in the C standard library there is no such function out of the box. Maybe in third party library.

One option is use ANSI escape sequences to set the background color to foreground color in the console to conceal the password. Try this link.

凤舞天涯 2024-12-04 03:27:19

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

这是我曾经用诅咒编写的代码。使用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;
}

With scanning the characters you can take it into a buffer. Also you need to write code if backspace is pressed, and appropriately correct the inserted password.

Here is a code which once i wrote with the curses. Compile with 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;
}
回眸一笑 2024-12-04 03:27:19

在 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 的等效 shell 脚本>(更改 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

来源:如何读取密码而不在 C 中回显密码?

In C you can use getpasswd() function which pretty much doing similar thing as stty in shell, example:

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

Here is equivalent shell script which use stty (which changes the settings of your 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

Source: How can I read a password without echoing it in C?

花间憩 2024-12-04 03:27:19

man getpass

此功能已过时。不要使用它。如果你想读取输入
没有启用终端回显,请参阅 ECHO 标志的描述
术语(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 发行版都不会使用星号屏蔽密码。这样做会泄露密码的长度,这没有任何好处。当输入密码时,简单地让光标不移动会更容易、更好。如果出于某种原因,您需要为输入的每个字符打印 * ,那么您将必须抓住每个按键在按下 Enter 之前,这总是有问题的。

man getpass

This function is obsolete. Do not use it. If you want to read input
without terminal echoing enabled, see the description of the ECHO flag
in 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 */

If you notice, most current linux distro's do not mask a password with asterisks. Doing so divulges the length of the password which is no way beneficial. It is easier and better to simply make the cursor not move when a password is typed in. If for whatever reason you require a * to be printed for every character that's typed then you would have to grab every keypress before Enter is hit and that's always been problematic.

橘亓 2024-12-04 03:27:19
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';
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';
一袭水袖舞倾城 2024-12-04 03:27:19

这是我的想法,改编自C++ 官方网站

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

它将一次读取一个字符并将其添加到字符串中,并支持显示另一个字符。

Here is my idea, adapted from that of 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;
}

It will read one character at once and add it to the string and supports showing another character.

谁许谁一生繁华 2024-12-04 03:27:19

请注意,ICANON termios lflag 会关闭处理回车/换行,负 ECHO termios 设置会关闭 STDIN 的回显。

当使用它(无论是否打开回显)读取密码并打印输入字符的 '*' 时,这不仅仅是读取字符直到遇到换行符/回车符的问题,您还必须在“字符串构建例程”中处理退格键(否则退格键最终会出现在实际字符串中,并且不会导致字符从其中删除,就像各种基于字符串的输入函数的情况一样)。

在 DOS 中的 C 语言中使用 getch 也会发生同样的情况。这也会很高兴地返回 0x08 表示退格键(或 127 或您的特定操作系统用作退格键的任何内容),

跟踪“不删除字符串开头之前”,替换“字符串的新结尾” string' 为 0 并将当前位置计数器向后移动 1(除非您位于位置 0)取决于程序员使用这些函数中的任何一个(甚至是 dos C 上的 getch)。

getpass() 并没有执行用户最初要求的操作,他想要 * 的(这仍然向站在他身后看着他的屏幕的人透露密码的长度,以及在终端的滚动缓冲区中(如果他在使用后没有关闭它)。但在“非封闭环境”中,没有 * 可能是一个更好的主意。

note that the ICANON termios lflag turns off the processing carriagereturn/linefeed, and the negative ECHO termios setting turns off echo for STDIN.

when using this (with or without the echo being on) to read a password and print '*' for entered characters, it's not just a matter of reading characters until a newline/carriage return is encountered, you also have to process backspace in your 'string building routine' (else the backspaces end up in the actual string, and do not cause characters to be removed from it such as would be the case with the various string based input functions).

the same would happen in C in DOS with getch tho. that would also happily return 0x08 for backspace (or 127 or whatever your specific os uses as backspace)

keeping track of 'not deleting -before- the start of the string', replacing the 'new end of the string' with 0 and moving the current position counter back by one (unless you are at position 0) is up to the programmer with any of these functions (even the getch on dos C).

getpass() doesn't do what the user originally asked for btw, he wants *'s (which still disclose the length of the password to people standing behind him and looking at his screen, as well as in the scrollbuffer of the terminal if he doesn't close it after use). but without *'s is probably a better idea in 'non closed environments'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文