2

Around a few hours ago, I enquired on Stack Overflow about methods on how to convert a char[] to an MD5 hash. A solution was provided, but was thought to be insecure - as outlined by a couple of people: Generating an MD5 Hash with a char[]

Neil Smithline recommended that I make use of BCrypt, but I am unable to use that with char[]'s.

The reason that I am using a char[] for storing the retrieved password from a login form is because .getPassword() supports only char[].

        char[] passwordChars = passwordInputField.getPassword();
        String hashed = BCrypt.hashpw(passwordChars, BCrypt.gensalt(12));

Currently, I am trying to use the above code to generate a hash but as the variable passwordCars is of type a char[], it is not supported by BCrypt.haspw()

Now the only reason why I am not using a regular String is because it cannot be cleared from memory.

My question now is - is it possible to somehow use char[]'s with BCrypt?

Thanks in advance!

Community
  • 1
  • 1

3 Answers3

4

So, based on the implementation presented at https://github.com/jeremyh/jBCrypt, you need to change the hashpw and checkpw methods to accept char[] instead of String

Probably, the hardest part is in hashpw...

    try {
        passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
    } catch (UnsupportedEncodingException uee) {
        throw new AssertionError("UTF-8 is not supported");
    }

The easiest solution would be to wrap the char[] back into a String, but we're trying to avoid that. Instead, based on the highest scoring answer from Converting char[] to byte[], we can do something more like...

    char[] expanded = password;
    if (minor >= 'a') {
        expanded = Arrays.copyOf(expanded, expanded.length + 1);
        expanded[expanded.length - 1] = '\000';
    }

    CharBuffer charBuffer = CharBuffer.wrap(expanded);
    ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
    passwordb = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());

The checkpw method actually doesn't need any modifications (apart from the parameters), as it uses the hashpw method to check the results.

So, testing...

// We want the same salt for comparison
String salt = BCrypt.gensalt(12);
String original = BCrypt.hashpw("Testing", salt);
System.out.println(original);
String hash = BCrypt.hashpw("Testing".toCharArray(), salt);
System.out.println(hash);
System.out.println(BCrypt.checkpw("Testing", hash));
System.out.println(BCrypt.checkpw("Testing".toCharArray(), hash));

Outputs...

$2a$12$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
$2a$12$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
true
true

Now, if you have a GitHub account, you could actually clone the original repo, make the suggested changes and generate a pull requests. I'd, personally, be temptered to get rid of the checkpw and hashpw methods which require String

I also found this implementation of the PDKDF2, which uses String, but then promptly converted it to a char[] ... so, that was VERY simply to change...

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

Both Java impls of bcrypt that I found take a String as input. As you seem to know, putting the password into a string opens you up to memory attack.

You can use PBKDF2 as well as bcrypt. Both are considered top-notch. There are PBKDF2 Java code samples here and here. Both allow passing a char[] to the functions.

To answer an implicit question from the comments, the reason that you don't use MD5 or any hash is that they are just too fast. Brute forcing passwords with special hardware becomes possible with them. Bcrypt and PBKDF2 are designed to be slow.

Even if you're going to use a hash (which I recommend against), you must salt it. Reversing unsalted password hashes is trivial (see this tool).

The CrackStation's reference on password storage is a good general reference.

Neil Smithline
  • 1,526
  • 9
  • 21
0

The short answer to your question: yes, it is possible to use char[]s with BCrypt in Java.

The Bouncy Castle crypto packages for Java added the BCrypt password hashing algorithm (using the String format and the Base64 encoding of the reference implementation on OpenBSD) in version 1.52 (Mar 2015), and it only supports char[] passwords.

The relevant method to generate a BCrypt string can be found in the org.bouncycastle.crypto.generators.OpenBSDBCrypt class and has the following signature:

String generate(char[] password,
                byte[] salt,
                int cost)

If you'd like to verify in the source code that the char[] is preserved without being converted into a String, the relevant classes are OpenBSDBcrypt, Strings and BCrypt.

fspinnenhirn
  • 1,784
  • 1
  • 13
  • 27