Can you securely read a password on the command line?

Securely reading a password from the command line in Java is difficult, but there are some (imperfect) solutions

Q: I need to read passwords from the command line. Is there a way to easily read characters from the command line securely in Java? Specifically, how do you echo * to the command line?

A: To read items in from the command line, we use the input stream System.in. If we dig into the code a bit, we see that the default System.in input stream is really just an InputStream. Digging into my implementation of Java (IBM 1.1.7), the true implementation type of that System.in is a FileInputStream. That input stream is set to read in from the source file descriptor FileDescriptor.in. However, FileDescriptor.in is initialized by natively defined code. It is left to the system to point the FileDescriptor.in at the standard input handle.

If we look at the API definition for FileInputStream, we see that the read method is natively defined. Typed data is not taken from the command line and made available from the standard in file descriptor until the return button is pressed. Since we cannot grab a character as it is typed, there is no way to intercept the character and echo a * to the command line. Instead, we can only grab complete lines.

That leaves us with few alternatives. Unfortunately, most of the solutions require us to dive into native code or employ a GUI frontend. Briefly, here are a few solutions:

  1. Forgo a command-line-based username/password interface. Instead, use a graphical frontend. Swing provides for protected text fields. Of course, that approach is useless if you plan to deploy on a terminal or another nongraphical environment.
  2. Forget writing that piece of your application in Java. Instead, write a process based on C or C++ that reads from the command line. Your Java application can talk to that process over the wire through sockets or some other protocol such as CORBA. There are some disadvantages to that approach: first, you must recompile the code for each deployment environment. Second, you'll need to encrypt the password since it may pass over the network.
  3. Write your own JNI command line reader and call it from your code, thus bypassing the input stream. Again, you'll need to recompile your library for each platform.
  4. If you feel really adventurous, you can always extend FileInputStream and provide your own read() implementation.
Tony Sintes is a senior consultant at ObjectWave Corporation who specializes in telecommunications. Tony has worked with Java since 1997 and is a Sun-certified Java 1.1 programmer and Java 2 developer.
Recommended
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more