Hide password input on terminal

后端 未结 15 1328
清酒与你
清酒与你 2020-11-22 09:55

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

相关标签:
15条回答
  • 2020-11-22 10:36
    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';
    
    0 讨论(0)
  • 2020-11-22 10:38

    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'.

    0 讨论(0)
  • 2020-11-22 10:39

    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.

    0 讨论(0)
  • 2020-11-22 10:44

    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.

    0 讨论(0)
  • 2020-11-22 10:44
    #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

    0 讨论(0)
  • 2020-11-22 10:44

    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?

    0 讨论(0)
提交回复
热议问题