Password Hasher

08 Jan 2020

Table of Contents


Introduction

I have previously written about my wish to avoid being responsible for password management.  Here is the other side of the coin: Some code which performs two main functions:

  1. Creates a hash for a new password.  It takes a password (for example, as provided in a user sign-up web form) and generates a hash, using a new salt value, plus a defined number of hash iterations. Most importantly, it uses a cryptographically secure hashing algorithm.

  2. Checks if a password is valid. It takes a password submitted for authentication, re-hashes it, and checks if its hash matches a previously stored hash (using the previously stored salt and iteration count).

The Implementation

For the first function, I assume that there is some form of unique identifier for the account, such as a user ID, or an e-mail address. A new salt is generated to be used with this - and only this - password hash. I also assume that the hash iterations count is defined elsewhere (e.g. in a properties file) - and may be adjusted over time.

So, for the first “create a new hash” function, the application needs to store the following data items:

  • account unique ID
  • salt value
  • iterations count
  • hash value

This could be stored in a user table in a database, for example.

The password, of course, should never be stored anywhere.

Furthermore, efforts must be taken to overwrite and nullify any variables which contain the raw password.

If you are handling form data submitted from a web page, then inevitably you are going to be handling at least one String object containing the password. Move the password into a char[] array as soon as possible, and set the string to null.  You still have to wait for garbage collection before the string is destroyed - but at least with a char[] you can remove the data as soon as you have finished using it.

Of course, if someone has access to your application server and can dump your VM, then you probably have bigger problems - but that’s no excuse for not taking these small security steps.

I am also assuming that network traffic is encrypted, using SSL/TLS.

The interface for my password handler looks like this:

The related data could be stored in a user table in a database, for example.

It’s pretty straightforward.

The core hashing implementation looks like this:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private byte[] hashPassword(final char[] password, final byte[] salt,  
        final int keyLength, final int iterations) {  
    try {  
        final SecretKeyFactory skf = SecretKeyFactory.getInstance(ALGORITHM);  
        final PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);  
        return skf.generateSecret(spec).getEncoded();  
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {  
        throw new RuntimeException(e);  
    }  
}

This, in turn looks like the Java example provided here, and the guidance provided here.

My example code is here.

Tip of the Iceberg

As soon as you commit to storing password-related data, you should realize you’re committing to a whole lot of infrastructure in addition to one simple hashing utility, and the points already mentioned above.

This is not a comprehensive list:

a) Password length and complexity policy.

b) Storage security.  Is your database secure?

c) Additional authentication defenses - such as two-factor authentication

Strings are Immutable

One final thought: You may see statements about Java strings which appear to contradict some of the above statements regarding strings versus character arrays.

The discussion goes like this:

Question: Why did the designers of Java choose to make strings immutable?

Answer: Well, for several reasons - one of which was security. There are various situations in which parameters are passed around as string values - for example, network and database connections, file names, and so on.  If a string were not immutable, it would be possible to change it at runtime - with potentially harmful or malicious consequences.

It’s hard to find much concrete data on this subject (security through immutability).  Discussions such as this tend to emphasize string pooling (and its related performance benefits) as one of the primary motivators which may have been in the minds of  the Java designers when they decided to make strings immutable. And certainly, immutability enables pooling.

But security? Things get vague there.  An argument can be made that immutability makes it much harder for accidental re-assignment of a String reference within a code base - and that means less chance that a vital network parameter is also accidentally changed.  But I don’t know how immutability defends against malicious runtime attacks. I’ve never seen that explained.

And here’s the big puzzle (to me, at least): Within the context of password management, you may well see the exact opposite argument being made about passwords stored in Strings: They are less secure than, for example, passwords stored in character arrays - precisely because strings are immutable.

So which is it? Does string immutability help security or hinder it?

I think the answer is: It depends on the context and the intent.  If you want to avoid inadvertent changes to a string reference (from one probably known value to another different known value), then yes, String immutability helps.

But if you want to keep the value of a string reference secret, then no, String immutability is a hindrance.  Passwords stored in Strings tend to hang around in the JVM’s heap longer than you may want them to - and there’s not much you can do about it.  It can be argued that if someone has unauthorized access to your JVM then you have bigger problems than a password stored in the heap. But that’s no excuse for doing nothing.

Unfortunately the chances are, no matter how diligent you are, there may well be some other password related problem.  Even if you overwrite a user’s password after logging them in, there may be (for example) a database password over which you have no control - one which persists in the JVM for the lifetime of the JVM itself.  Web servers such as Tomcat and Jetty both keep hold of JDBC connection credentials, even after the initial connection has been established.

It feels like you are just adding one more lock onto the front door, while the back door is hanging off its hinges.

Bottom line is probably this: First ensure your servers are secure; and worry about the finer-grained issues after that. How to keep your servers secure?  There are people far smarter than me who know about this large and complex topic.