53

How to mask a password from console input? I'm using Java 6.

I've tried using console.readPassword(), but it wouldn't work. A full example might help me actually.

Here's my code:

import java.io.BufferedReader;
import java.io.Console;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test 
{   
    public static void main(String[] args) 
    {   
        Console console = System.console();

        console.printf("Please enter your username: ");
        String username = console.readLine();
        console.printf(username + "\n");

        console.printf("Please enter your password: ");
        char[] passwordChars = console.readPassword();
        String passwordString = new String(passwordChars);

        console.printf(passwordString + "\n");
    }
}

I'm getting a NullPointerException...

7
  • 2
    How exactly doesn't console.readPassword() work? Commented Nov 15, 2011 at 15:07
  • 3
    run in the console and not from within an IDE Commented Nov 15, 2011 at 15:25
  • 1
    This code does not work in an ide, please see my updated answer. Commented Nov 15, 2011 at 15:29
  • so i have to export the project as a jar file and run from the command line? if so, i did that, and got this error.. "Failed to load Main-Class manifest attribute from C:\......" Commented Nov 15, 2011 at 15:31
  • Take a look at stackoverflow.com/questions/2591516/… Commented Nov 15, 2011 at 15:36

5 Answers 5

71

A full example ?. Run this code : (NB: This example is best run in the console and not from within an IDE, since the System.console() method might return null in that case.)

import java.io.Console;
public class Main {

    public void passwordExample() {        
        Console console = System.console();
        if (console == null) {
            System.out.println("Couldn't get Console instance");
            System.exit(0);
        }

        console.printf("Testing password%n");
        char[] passwordArray = console.readPassword("Enter your secret password: ");
        console.printf("Password entered was: %s%n", new String(passwordArray));

    }

    public static void main(String[] args) {
        new Main().passwordExample();
    }
}
Sign up to request clarification or add additional context in comments.

13 Comments

I just got another NullPointerException... I don't understand!
Are you running this from within an IDE? Is not the code running ? Why downvote ?
For the guys getting the null pointer, run it from console, from eclipse this will not work
@Woot4Moo Can you clarify why this is "highly insecure"? Without any context of why, the statement alone isn't very useful for promoting understanding (nor is it easy to verify or refute).
There's not much sense in fretting over the internal memory security risk of a line that is literally printing the password out to the console.
|
8

You would use the Console class

char[] password = console.readPassword("Enter password");  
Arrays.fill(password, ' ');

By executing readPassword echoing is disabled. Also after the password is validated it is best to overwrite any values in the array.

If you run this from an ide it will fail, please see this explanation for a thorough answer: Explained

5 Comments

@Woot4Moo: Could you please elaborate how "the accepted answer is insecure!". I see you're writing over the password after you read it in, but this just seems silly. The password is going to be in memory for some amount of time no matter what you do. Even if you didn't manually write over the memory holding the password, it would get garbage collected and the memory would be refilled with something else. Honestly, if someone has the ability to read arbitrary addresses in memory, I think you should have bigger concerns.
@ArtOfWarfare in the event the "answer" ever changes: stackoverflow.com/a/8138549/205426 the reason why it is insecure as I have stated is this: new String(passwordArray) a new String is allocated to the String Pool which "never" goes away during the lifetime of a JVM. To counter your statement about garbage collection, you may not be aware that the String class is "special" and doesn't get GCd. And yes I agree the password will be in memory for some amount of time, I just happen to reduce that amount of time as much as possible.
@ArtOfWarfare additionally, any system as complex as the JVM is going to have issues with it. There have been a myriad of vulnerabilities discovered in the almost 4 years since I made this post, against the JVM. So if you were running the JVM since 2011 in Java 6 I bet there was a "arbitrary memory" exploit
Overwriting the character values in the array is, at best, a band-aid. There is no guarantee that the contents of the "password" character array have not been copied around the heap a few times between the time that the password is read from the Console object and the time the Arrays.fill() method completes. The reality is that safe-handling of in-memory passwords in Java is simply not possible.
1. Strings created with the ordinary constructor are not added to the pool. 2. Even strings added to the pool get garbage collected when no (other) reference exists. 3. In any real life application, something useful has to happen between the readPassword and the fill operation which will determine whether this effort has any point. Take JDBC drivers, for example. There is no way to pass the password to the driver without creating a string. While using an array and overwriting it after use, is an established best-effort practice, it should not be explained with wrong myths about string pool
3
Console console = System.console();
String username = console.readLine("Username: ");
char[] password = console.readPassword("Password: ");

1 Comment

need to fill the password array.
0

If you're dealing with a Java character array (such as password characters that you read from the console), you can convert it to a JRuby string with the following Ruby code:

# GIST: "pw_from_console.rb" under "https://gist.github.com/drhuffman12"

jconsole = Java::java.lang.System.console()
password = jconsole.readPassword()
ruby_string = ''
password.to_a.each {|c| ruby_string << c.chr}

# .. do something with 'password' variable ..    
puts "password_chars: #{password_chars.inspect}"
puts "password_string: #{password_string}"

See also "https://stackoverflow.com/a/27628738/4390019" and "https://stackoverflow.com/a/27628756/4390019"

Comments

-1

The given code given will work absolutely fine if we run from console. and there is no package name in the class

You have to make sure where you have your ".class" file. because, if package name is given for the class, you have to make sure to keep the ".class" file inside the specified folder. For example, my package name is "src.main.code" , I have to create a code folder,inside main folder, inside src folder and put Test.class in code folder. then it will work perfectly.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.