Your challenge is to read a "password" from the keyboard / standard input.


  • Read a string s invisibly.
  • For each of the characters in s, print a character c.
  • In realtime.


  • You must print c in realtime. As soon as the user enters a character you must display c.
  • c must be constant, i.e. it must be the same character.
  • c can be any visible character (i.e. it cannot be a newline, space, tab, or unprintable).
  • c can't be based on s, i.e. c must be defined/constant before s is read.
  • c must be the same every time the program is run.
  • c can be one of the characters in s if by accident, as long as all other rules are followed.
  • None of the characters of s may appear on the screen, c excepted (see previous rule).
  • You may use any reasonable methods of input and output as long as all other rules are followed.
  • You may assume that the length of s is never longer than the terminal/graphical window width.
  • If using a terminal, your program should terminate after a newline or EOF is entered.


If s was password01 and c was *, the output would look something like:



The shortest submission in each language wins.

  • \$\begingroup\$ Is python with tkinter allowed for our custom input field (like the one in HTML), such that the program does not terminate when enter is pressed, but when you close the Entry's Window (X on Windows and cmd+W on mac)? \$\endgroup\$ – Mr. Xcoder Jun 9 '17 at 16:35
  • \$\begingroup\$ @Mr.Xcoder Yes, that's valid. \$\endgroup\$ – MD XF Jun 9 '17 at 16:36
  • \$\begingroup\$ Can we use Ctrl+J to represent a literal newline in the terminal? Alternatively, can we use Ctrl+Z instead of enter? \$\endgroup\$ – Conor O'Brien Jun 9 '17 at 16:43
  • \$\begingroup\$ @ConorO'Brien Clarifying how input should end in the terminal. \$\endgroup\$ – MD XF Jun 9 '17 at 16:44
  • 2
    \$\begingroup\$ What should happen if the user presses backspace? \$\endgroup\$ – zdimension Jun 10 '17 at 20:51

34 Answers 34


str, 5 bytes


Due to a bug, this is 5 bytes. It should be only 1 byte:


Execution of <code>n=?,1</code>

  • \$\begingroup\$ Definitely saw the cmder answer coming due to your Ctrl+Z comment :P \$\endgroup\$ – MD XF Jun 9 '17 at 16:53
  • \$\begingroup\$ 10/10 right tool for the job \$\endgroup\$ – Erik the Outgolfer Jun 9 '17 at 17:16

HTML, 20 bytes

<input type=password

Alternative: HTML + JavaScript, 51 bytes

Although the OP has confirmed that to be valid, here's a solution using JS for the purists!

<input id=i oninput=i.value=i.value.replace(/./g,8)

  • 4
    \$\begingroup\$ FGITW, anyone? :P (took him literally ten seconds) \$\endgroup\$ – MD XF Jun 9 '17 at 16:21
  • \$\begingroup\$ oninput=_=>i.value=i.value.replace(/./g,"*") saves a byte. \$\endgroup\$ – Arjun Jun 9 '17 at 16:54
  • \$\begingroup\$ Since c can be anything, you can save two more bytes with oninput=_=>i.value=i.value.replace(/./g,1) \$\endgroup\$ – Arjun Jun 9 '17 at 17:01
  • \$\begingroup\$ I'll worry about that if (when) someone declares my HTML-only solution invalid, @Arjun ;) I only threw the JS one together quickly to placate a few people! \$\endgroup\$ – Shaggy Jun 9 '17 at 17:07
  • 6
    \$\begingroup\$ Where's the explanation, I don't understand. \$\endgroup\$ – Magic Octopus Urn Jun 9 '17 at 17:27

Vim, 36 bytes:

:im <C-v><CR> <C-v><esc>ZQ<CR>:au I<tab><tab> * let v:char=0<CR>i

This uses vim-key notation, so <C-v> is control-v, <CR> is enter, <esc> is the escape key, and <tab> is the tab key.

c is '0'.

Here is a hexdump to prove the byte count is accurate:

00000000: 3a69 6d20 160a 2016 1b5a 510a 3a61 7520  :im .. ..ZQ.:au 
00000010: 4909 0920 2a20 6c65 7420 763a 6368 6172  I.. * let v:char
00000020: 3d30 0a69                                =0.i

This works by running the following two ex commands:

:imap <CR> <esc>ZQ
:autocmd InsertCharPre * let v:char=0

The first one means

:imap               " Anytime the following is pressed in insert mode:
      <CR>          "   (the 'enter' key)
           <esc>ZQ  " Then act as if the user instead pressed '<esc>ZQ' (close the buffer)

And the second one means

:autocmd                                " Automatically as vim runs:
         InsertCharPre                  "   Any time the user is about to insert a char
                       *                "   In any type of file
                         let v:char=0   "     Then instead insert a '0' character
  • \$\begingroup\$ I think there's not a way for me to get down to this using my current method without ignoring spaces at the very least.. Nice answer! \$\endgroup\$ – nmjcman101 Jun 9 '17 at 17:48
  • \$\begingroup\$ o_O That's neat... \$\endgroup\$ – Mr. Xcoder Jun 9 '17 at 18:13

Ruby with Shoes, 29 characters

Shoes.app{edit_line secret:1}

Sample output:

password input in Ruby with Shoes

  • 25
    \$\begingroup\$ Ruby with Shoes? Rails weren't enough? \$\endgroup\$ – Magic Octopus Urn Jun 9 '17 at 17:52

Aceto, 8 7 6 bytes



Read a character (,), negate it (!) and conditionally exit. Print the zero on top of the stack (p) and go back to the beginning.

Run with -F to see the effect immediately (because flushing)

My first solution was based on the sandbox post, with spaces allowed as replacement characters and no need to exit on enter (4 bytes):


C on POSIX, 128 117 113 96 bytes

-11 thanks to Quentin searching through termios.h
-4 thanks to Quentin pointing out my stupid mistakes
-17 because Quentin is a freaking wizard.


This puts STDIN into raw/invisible mode so that it can get keypresses in realtime. This takes 77 bytes and I'm sure I can golf it in a bit. Note that this does not reset STDIN upon exiting so it will mess up your terminal if you don't do so manually.

Here's how you can reset STDIN:

void stdin_reset(void)
    struct termios t;
    t.c_lflag |= ECHO;
    t.c_lflag |= ICANON;

Output as shown in the GIF :-)

  • 1
    \$\begingroup\$ Digging into my termios.h, ECHO is 0000010 and ICANON is 0000002. This means that ~(ECHO|ICANON) is just ~10 :) \$\endgroup\$ – Quentin Jun 9 '17 at 23:39
  • \$\begingroup\$ @Quentin Edited! Cheers :D \$\endgroup\$ – MD XF Jun 9 '17 at 23:41
  • 1
    \$\begingroup\$ Also, each != can be replaced with ^, and '\n' with 10 (assuming UTF-8) ;) \$\endgroup\$ – Quentin Jun 9 '17 at 23:47
  • 2
    \$\begingroup\$ If we go full UB, we can replace t's storage with an array of integers. Then c_lcflags ends up at t[3], and we need neither the name or the type nor the #include, totaling 94 bytes: c,t[15];f(){for(tcgetattr(1,t),t[3]&=~10,tcsetattr(1,0,t);(c=getchar())^10&&c^4;)printf(".");} -- But maybe you'd better have me post it as an answer rather than having fun with yours :) \$\endgroup\$ – Quentin Jun 10 '17 at 0:01
  • 1
    \$\begingroup\$ @Quentin Oh... my. You're a wizard. And I thought I was good at C... if you'd like to post it as your own answer feel free and I'll rollback my edits, otherwise I'll leave it edited into mine. \$\endgroup\$ – MD XF Jun 10 '17 at 0:47

x86 machine code on MS-DOS - 14 bytes

As usual, this is a full COM file, that can be run on DosBox, plus most DOS variants.

00000000  b4 08 b2 2a cd 21 80 f4  0a 3c 0d 75 f7 c3        |...*.!...<.u..|

Commented assembly:

    org 100h

section .text

    mov ah,8h       ; ah starts at 08h (read console, no echo)
    mov dl,'*'      ; write asterisks (we could have left whatever
                    ; startup value we have here, but given that dx=cs,
                    ; we have no guarantee to get a non-zero non-space
                    ; value)
    ; this loop runs twice per character read: the first time with
    ; ah = 08h (read console, no echo syscall), the second time with
    ; ah = 02h (write console); a xor is used to switch from one
    ; mode to the other
    int 21h         ; perform syscall
    xor ah,0ah      ; switch syscall 08h <=> 02h
    cmp al,0dh      ; check if we read a newline (if we wrote stuff
                    ; we are just checking the last value read, so
                    ; no harm done; at the first iteration al starts
                    ; at 0, so no risk here)
    jne lop         ; loop if it wasn't a newline
    ret             ; quit
  • 2
    \$\begingroup\$ ...no way. That's amazing. \$\endgroup\$ – MD XF Jun 11 '17 at 14:32
  • \$\begingroup\$ Thanks, but I feel that there's still something else to trim; that xor is a woppin' 3 bytes, and would be exactly as big if I made it work on the whole ax; I tried xor ax,0a0dh / test al,al, but it's just as big because stupid test is two bytes, grrr... \$\endgroup\$ – Matteo Italia Jun 11 '17 at 14:43

Python 2, 50 bytes

from msvcrt import*

Only works on windows

  • 1
    \$\begingroup\$ Sadly it only works on Windows :(( \$\endgroup\$ – Mr. Xcoder Jun 9 '17 at 16:50

AHK, 17 bytes


Built-ins are not interesting.


Java 5-8, 125 122 131 124 bytes

class X{public static void main(String[]a){new java.awt.Frame(){{add(new javax.swing.JPasswordField());setVisible(1>0);}};}}


class X{
    public static void main(String[]a){
        new java.awt.Frame(){
                add(new javax.swing.JPasswordField());


enter image description here


-3 @MD XF (Pointed out my stupid mistake with String[]args)

-7 @KritixiLithos (Pointed out public class can just be class)

  • 1
    \$\begingroup\$ Is the String[]args necessary? \$\endgroup\$ – MD XF Jun 9 '17 at 17:32
  • \$\begingroup\$ @MDXF if I wish to make the answer for Java 8 there is PLENTY of stuff I could do. However, I'm making this a generic Java answer. However, however, yes I can make that String[]a. \$\endgroup\$ – Magic Octopus Urn Jun 9 '17 at 17:34
  • \$\begingroup\$ You forgot to update the golfed answer. Also, doesn't 1>0 evaluate to 1? \$\endgroup\$ – MD XF Jun 9 '17 at 17:35
  • \$\begingroup\$ @MDXF in Java (< 8) - 1>0 evaluates to true, which is different. I'll post this same answer in Groovy. \$\endgroup\$ – Magic Octopus Urn Jun 9 '17 at 17:37
  • \$\begingroup\$ @StephenS this is a generic Java answer, not a Java 8 answer. \$\endgroup\$ – Magic Octopus Urn Jun 9 '17 at 17:42

Mathematica 34 bytes


An single asterisk appears, after each character is keyed in. The empty quotation marks are for the title that appears in the pop-up input window.

The ; prevents the password from being printed.

enter image description here

  • \$\begingroup\$ Intentional leading space? \$\endgroup\$ – MD XF Feb 9 '18 at 19:49

Vim, 58 50 52 50 bytes

Added to make sure it handled spaces properly.

Thanks to @DJMcMayhem for a bunch of help and ideas

i:im 32 *Y94pVGg

In typical Vim key syntax below. The characters marked like with a ^ are Ctrl+<char>, so ^Q=Ctrl+q

i:im ^V^V32 *^[Y94pVGg^A
:im ^V

There's no TIO link, because you'd need to directly input to Vim (as opposed to pre-inputting like normal). To run the code you need to type it into Vim, and then you can type your password and hit enter. It won't do anything with the password. It won't even know what it was. As soon as you hit enter the Vim window will :q!

This works by mapping all printable ASCII to * in insert mode, and mapping <CR> to <ESC>:q!<CR>

  • \$\begingroup\$ Maybe clarify what the symbols are? I think they're supposed to be <C-v>, <esc> and <C-a> but it's hard to tell. \$\endgroup\$ – James Jun 9 '17 at 17:04
  • \$\begingroup\$ @DJMcMayhem Will do. Incidentally I think that you can paste them into Vim and they'll show up appropriately. \$\endgroup\$ – nmjcman101 Jun 9 '17 at 17:07
  • \$\begingroup\$ Some friendly competition :D \$\endgroup\$ – James Jun 9 '17 at 17:46

FLTK, 47 characters

Function{}{}{Fl_Window{}{}{Fl_Input{}{type 5}}}

Sample run:

bash-4.4$ fluid -c password.fl

bash-4.4$ fltk-config --compile password.cxx 
g++ -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/freetype2 -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -fvisibility-inlines-hidden -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_THREAD_SAFE -D_REENTRANT -o 'password' 'password.cxx' -Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -lfltk -lX11

bash-4.4$ ./password 

Sample output:

password input in FLTK


Processing, 53 bytes

String a="";void draw(){text(keyPressed?a+=0:a,9,9);}

This takes input via keypresses from a graphical window. The character it chooses to represent passwords with is 0. Note that due to the high framerate, each keypress will appear as multiple 0s (and also due to the fact that this is keyPressed and not keyTyped (not a boolean) or keyrelease).



Bash, 54 bytes

while read -eN1 c 2>&-;[[ ${c/$'\r'/} ]];do printf X;done

For scoring purposes, $'\r' can be replaced with a literal carriage return.

Try it online! (not much to look at)


ZX81 BASIC, 54 bytes

70 PRINT "*";

In the ZX81 character set the printable characters are in the range space to Z, although you can't actually input a space this way as it's the break character.

ZX Spectrum BASIC, 24 bytes


Note that >= counts as a single-byte keyword in Sinclair BASIC (codepoint 140 in this case).

  • \$\begingroup\$ Are the spaces between the line numbers and functions necessary? \$\endgroup\$ – MD XF Jun 11 '17 at 20:04
  • \$\begingroup\$ Could you shorten PRINT to ?, I know that works in a lot of old BASIC dialects \$\endgroup\$ – MD XF Jun 11 '17 at 20:04
  • \$\begingroup\$ @MDXF PRINT is a 1-byte token, it's just represented on screen as the 7 characters (except after THEN, when the leading space is suppressed). \$\endgroup\$ – Neil Jun 11 '17 at 21:13

R, 29 bytes


Built-in that handles password entries. Opens a new window and replaces the input with dots. invisible is used to suppress printing the password to STDOUT.


Tcl/Tk, 18

gri [ent .e -sh *]

Must be run on the in the interactive shell (or have abbreviations enabled):

enter image description here

  • \$\begingroup\$ 21 bytes without the tricky command abbreviations: grid [entry .e -sh *] and -sh is an option abbreviation for -show. 23 bytes is what I'd consider a minimum for a maintainable ungolfed program doing this. \$\endgroup\$ – Donal Fellows Jun 13 '17 at 21:48

Vim, 15 keystrokes

:cal inp<S-tab>'')|q<cr>

<S-tab> means shift + tab.

Apparently, there is a builtin for this that I wasn't aware of. Since I really like my manual answer, and this approach is radically different, I figured I should post a new answer instead of editing.

This works by calling the inputsecret function, then immediately quitting after it exits.


6502 machine code (C64), 22 21 bytes

0e 08 20 9f ff 20 e4 ff f0 f8 c9 0d f0 01 a9 60 20 d2 ff 50 ed

Usage: SYS 2062

Commented disassembly listing (ACME), you can uncomment the first three commented lines to launch with RUN once loaded:

!cpu 6502
!to "password2.prg",cbm
;* = $0801                               ; BASIC starts at #2049
;!byte $0d,$08,$dc,$07,$9e,$20,$32,$30   ; BASIC to load $c000
;!byte $36,$32,$00,$00,$00               ; inserts BASIC line: 2012 SYS 2062

    GETIN  =  $FFE4
    SCNKEY =  $FF9F
    CHROUT =  $FFD2

* = $080e
    jsr SCNKEY  ; get key
    jsr GETIN   ; put key in A

    beq keyScan ; if no key pressed loop    

    cmp #13     ; check if RETURN was pressed
    beq $081b   ; if true go to operand of next instruction (#$60 = rts)

    lda #$60    ; load char $60 into accumulator
    jsr CHROUT  ; print it

    bvc keyScan ; loop


  • I haven't found anything in the docs, but it seems that, after the GETIN call, beq branches only where no new key presses have been recorded;
  • Using #$60 as output char, that byte can be reused as "rts" instruction when RETURN is pressed.

Forth (gforth), 54 bytes

: f begin key dup 4 - swap 13 - * while ." *" repeat ;


begin      \ enters the loop
    key    \ waits for a single character as input, places ascii code of character on stack
    dup    \ duplicates the key value on the stack
    4 -    \ subtracts 4 from the key value (shorter way of checking for not equals)
    swap   \ swaps the top two stack values
    13 -   \ subtract 13 from the key value
    *      \ multiply top two stack values (shorter version of "and")
while      \ if top of stack is true, enter loop body, else exit loop
    ." *"  \ output *
repeat     \ go back to beginning of loop

Python 3 + tkinter - 63 61 bytes

from tkinter import*

Displays a 1 for every character, ends when closing window (OP said it's allowed).


  • \$\begingroup\$ Would from tkinter import* (newline) Entry(show=1).pack();Tk().mainloop() work? \$\endgroup\$ – Conor O'Brien Jun 9 '17 at 17:01
  • \$\begingroup\$ @ConorO'Brien testing \$\endgroup\$ – Mr. Xcoder Jun 9 '17 at 17:01
  • \$\begingroup\$ @ConorO'Brien no. It produces two different tkinter windows. One with the text field, one empty. It doesn't seem right to me. \$\endgroup\$ – Mr. Xcoder Jun 9 '17 at 17:03
  • \$\begingroup\$ Do you need the show=? \$\endgroup\$ – Esolanging Fruit Jun 11 '17 at 23:14
  • \$\begingroup\$ @Challenger5 Yes, we do need the show= \$\endgroup\$ – Mr. Xcoder Jun 12 '17 at 12:19

Groovy, 77 73 bytes

{new java.awt.Frame(){{add(new javax.swing.JPasswordField());visible=1}}}

This is an anonymous closure, with 0 required inputs.


    new java.awt.Frame() {
            add(new javax.swing.JPasswordField())

Edit 1 (-4 bytes): Component#visible can be directly accessed, read more here.


Micro, 35 bytes



"":i                      create new blank string 'i'
    {                          begin input loop
     L                         input a character
      46c:\                    display ascii char #46 (.) (it is popped, leaving the input char from 'L'
           i~+:i               push i, flip i and the char around, concatinate them, and store that to i
                i10c=if(,a)}a  OK, a lot happens here, if a NL is in i, the loop terminates, and the final i:\ will display the input
  • 1
    \$\begingroup\$ That's a pretty good first attempt at a language! +1 \$\endgroup\$ – MD XF Jun 9 '17 at 17:54

BF, 24 bytes


Works with bf.doleczek.pl. You can send a zero char to the program with Ctrl+Z.

Alternative solution:

BF, 1 byte


This is a very tongue-in-cheek solution. My terminal is 0 characters wide, so please don't enter any passwords longer than that.

  • \$\begingroup\$ Whoa... not bad! \$\endgroup\$ – MD XF Jun 11 '17 at 23:01
  • \$\begingroup\$ @MDXF Are you referring to the 24 byte one or the 1 byte one? \$\endgroup\$ – Esolanging Fruit Jun 11 '17 at 23:09
  • \$\begingroup\$ Clearly the 24-byte one. I completely forgot that printing \b is a thing. :P \$\endgroup\$ – MD XF Jun 11 '17 at 23:10
  • \$\begingroup\$ @MDXF What do you mean by that? \b is unprintable anyways. \$\endgroup\$ – Esolanging Fruit Jun 11 '17 at 23:11
  • \$\begingroup\$ No I mean your solution uses \b to override the input, correct? \$\endgroup\$ – MD XF Jun 11 '17 at 23:12

PowerShell, 12 bytes

Read-Host -a

This reads input from host and, with the -a flag treats it as a securestring/password. In the ISE it pops up a message box which has a similar behavior since the ISE doesn't allow keypress capture.

PS C:\Windows\system32> Read-Host -a

QBasic, 48 bytes


INPUT$(1) reads the next character from keyboard input. (This can include things like tab, backspace, and escape, but since the OP didn't say anything about those I'll assume we don't have to worry about them.) If the character is \r (ASCII 13), terminate the program; otherwise, print * without a newline. Repeat ad infinitum.


Perl + Bash, 30 bytes

print"*"while$|=1+`read -sn 1`

c is *, uses read from bash, so isn't a pure Perl solution.


brainfuck, 21 bytes


Last one, I promise. No input = -1, end of input = 0

How it Works

-[  Enters the loop
  +>, Get input
     [<->+ If not end of input it create the ÿ character and check if the input is not -1
          [<.>[-]]] If there was input, print the ÿ character. 
                    <] Exit the loop if end of input
  • \$\begingroup\$ Your code is missing a closing bracket. And why do you make it that complicated? A simple "print a 'ÿ' for every input character" could be accomplished with a simple ,[>-.,] \$\endgroup\$ – Dorian Jun 12 '19 at 7:55
  • \$\begingroup\$ @Dorian The bracket was a mistake, but the complexity arises from having to handle both no input and end of input \$\endgroup\$ – Jo King Jun 12 '19 at 9:59

QBIC, 44 bytes



{            DO
X=inkey$     Read a char, set it to X$
             Note that INKEY$ doesn't wait for keypress, but simply sends out "" if no key was pressed.
~X<>@`|      IF X$ has a value THEN
~X=chr$(13)| IF that value is ENTER
_X           THEN END
\            ELSE
Y=Y+@*`      append a literal * to Y$
_C           Clear the screen
?Y           Display Y$ (having 1 * for each char entered)
             The IF's and the DO-loop are auto-closed at EOF{            DO

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.