Christopher Meyer

About Christopher Meyer

Chris works as a researcher and is eagerly looking for bugs in SSL/TLS, the Java platform and various applications. In addition, he is primarily interested in secure coding and exploiting coding mistakes.

Safely Create and Store Passwords

Nearly every time when it comes to user profiles it is necessary to manage user credentials and thus be able to create and store user passwords. It should be common practice to use hashed and salted passwords to be prepared for database disclosure and hash reversing by the use of rainbow tables.
However, it is (sadly) not uncommon to find passwords stored in plaintext (we’ll skip a list of big players who had to learn how to do it right the hard way). The consequences when a database with unencrypted, unhashed and unsalted passwords is leaked should be obvious….. The second worst way to do it is to use hashed, but unsalted passwords. In this case rainbow tables or hash reversing services on the web like this or this are of tremendous help. And finally, the third worst way is to rely on encrypted records alone – once the key or the decrypted database gets leaked the game is over!

So how to do it right? The easy answer is: use PBKDF2WithHmacSHA1 together with a salt value. An example how to use it can e.g. be found here. This implementation looks mature, but complicated. If you simply want to get a feeling for the concept of salting passwords, you may want to look at the following demo code:

public static final String HASH_ALGORITHM = "SHA-256"; 
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private static final char[] PASSWORD_CHARS = new char[]{
        '!', '@', '#', '$', '%', '&', '*', '(', ')', 
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; 

    public String getRandomString(final int length) {
        /*
         * Don't try to seed SecureRandom yourself unless you know 
         * what you are doing! 
         * @see Randomly failed! Weaknesses in Java Pseudo Random Number Generators (PRNGs).
         */ 
        SecureRandom secureRandom = new SecureRandom(); 
        StringBuilder sb = new StringBuilder(length);
        int position = 0;
        // create a random string of the requested length from a set of allowed chars
        for (int i = 0; i < length; i++ ) {
            position = secureRandom.nextInt(PASSWORD_CHARS.length);
            sb.append(PASSWORD_CHARS[position]);
        }
        return sb.toString();
    }

    public static byte[] createPasswordHash(final String password,
            final String salt) {
        byte[] result = null;
        try {
            MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
            digest.update(salt.getBytes(DEFAULT_CHARSET));
            digest.update(password.getBytes(DEFAULT_CHARSET));
            result = digest.digest();
        } catch (NoSuchAlgorithmException e) {
            // TODO Logging
        }

        return result;
    }

    public static boolean checkPassword(final User user, final String password) {
        boolean result = false;
        String storedPasswordHash = user.getPwHash();
        String salt = user.getSalt();
        byte[] checkPasswordHashBytes = createPasswordHash(password, salt);
        String checkPasswordHash = encodeBase64(checkPasswordHashBytes); // for simplicity let's say we use Base64

        if (checkPasswordHash != null && storedPasswordHash != null
                && checkPasswordHash.equals(storedPasswordHash)) {
            result = true;
        }

        return result;
    } 

The code expects some kind of User object with pwHash and salt fields (both fields are not sensitive!) to store the necessary information. This User object could (in case there is no other sensitive data linked to the object) be safely persisted. Even if the database gets leaked an attacker must either brute force the password-salt combination or compute a rainbow table for the salted password. Please note that this rainbow table could not be reused for the same password with a different salt! This means that with a randomly chosen salt an attacker will need rainbow tables to reverse the hash function for every salt – even if the password stays the same!

The code above is kept as simple as possible. For example getRandomString can be reused for creating the salt value and maybe the generation of a temporary password during the registration process. But remember, this code is far from being useable in production environments!

Some final notes: Be sure to use a salt that is long enough, prevent reuse of salts and use strong algorithms for hashing!
 

Reference: Safely Create and Store Passwords from our JCG partner Christopher Meyer at the Java security and related topics blog.
Related Whitepaper:

Web Application Security; How to Minimize Prevalent Risk of Attacks

Vulnerabilities in web applications are now the largest vector of enterprise security attacks.

Stories about exploits that compromise sensitive data frequently mention culprits such as cross-site scripting, SQL injection, and buffer overflow. Vulnerabilities like these fall often outside the traditional expertise of network security managers.

Get it Now!  

3 Responses to "Safely Create and Store Passwords"

  1. joschi says:

    No, no, and no. Please don’t use SHA-(1|256|512) for hashing passwords.

    Please, for the love of your users, use a hash algorithm specifically created for hashing credentials, like bcrypt, scrypt, or PBKDF2.

  2. Taylor Mathewson says:

    PBKDF2 is a decent algo, but it requires very little RAM, so rainbow tables can be generated with comparative ease on GPU’s. Scrypt can use large amounts of both CPU and RAM, and hence is more resilient to GPU-based attacks.

    http://www.tarsnap.com/scrypt/scrypt.pdf

    Additionally, the salt can be almost anything, including user’s id or name. The salt does not need to be secret or random, the point of a per-user salt is that an attacker would need to generate a rainbow table per user.

Leave a Reply


6 × = thirty six



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books