Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Why BCrypt

The big deal is that salting isn’t enough. Processing power has become so plentiful that even a brute force attack can crack salted passwords fairly quickly. BCrypt is slower. It fights processing power with iterations of encryption. This is commonly called the cost factor or work factor. You can configure BCrypt to encrypt multiple times, which causes the decrypt phase to be ran multiple times. The cost factor is used to encrypt the data 2^N times, where N is the cost factor. The default value is typically 10, depending on your implementation. Beware, it has been said on the internet (you know, out there) that a cost factor of 10 is not enough.

How does BCrypt work

BCrypt uses the Blowfish encryption algorithm’s keying schedule with the addition of the work factor. The hashed value that it creates is composed of the following parts, delimited with $:

  • BCrypt algorithm version identifier
  • Cost factor
  • 16-byte salt value, encoded in a modified Base-64 (22 characters)
  • cipher text (remaining characters)

An example hash is:

$21$10$MN9CW1vkR2xSXT8jqchug.wvLZbl4mtapxK0u/SLbTcgl9Ldzlq60

This hash value indicates:

  • BCrypt algorithm version 2a
  • Cost factor of 10
  • Salt is MN9CW1vkR2xSXT8jqchug.
  • the cipher text is wvLZbl4mtapxK0u/SLbTcgl9Ldzlq60

Cost Factor (work factor)

This is the real value of BCrypt. It directly targets the kind of brute force attacks that are so easy to implement with today’s processors. Each increment in the cost factor is exponential (e.g. 2^cost factor). The cost factor is stored as part of the hashed value. This offers the ability to change the cost factor as processing ability increases, without the immediate need to rehash all of the values. When your processors are upgraded, you can run performance tests to determine how many iterations can be performed at an acceptable pace, then update your cost factor. It’s as easy as that.

Flow for updating hashes when the Cost Factor is changed

Let’s consider the case where your processors are upgraded. If the processor upgrade allowed enough of a performance increase to justify that the Cost Factor should be increased, you can immediately start to hash new passwords with the increased Cost Factor. Existing passwords can’t be modified because the hashing is one-way. However, you can update hash values when a user logs in, because you have their plain-text value. If the user authenticates correctly, you can compare the Cost Factor from the pre-existing hash. If it is less than your desired value, you can rehash the password, store it and continue on. The user would not have any indication that you have increased the security of their passwords.

How do you use BCrypt

We use a Java implementation via Spring-security 3.2.5. The BCrypt object offers several methods that make using the API very easy.

One common things that is performed is salt generation. Salt generation is accomplished by calling genSalt. There are several variations of genSalt:

  • genSalt() – Uses the default Cost Factor of 10, uses a new instance of SecureRandom class to generate the 16-byte salt.
  • genSalt(int log_rounds) – Changes the Cost Factor to the value of specified int and uses a new instance of SecureRandom class to generate the 16-byte salt
  • genSalt(int log_rounds, SecureRandom) – Changes the Cost Factor to the value of the specified int. Uses the provided SecureRandom -instance to generate the 16-byte salt.

Once you have a salt, creating the hashed password is just a simple call.

  • hashpw(String password, String salt) – hashes the provided password with the provided salt.

Checking a password is very easy.

  • checkpw(String plaintext, String hashed) – This method will hash the given plain-text value using the salt from the provided hashed value and the provided Cost Factor. If they match, it returns true.

Here is an example of using the API:

String hashed = BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
//.. store the hash in the database in a <strong>VARBINARY</strong> field.

//.. sometime later, the user attempts to login
if (BCrypt.checkpw(passwordFromLoginPage, hashedValueFromDatabase)) {
    //.. they are authenticated
}

Conclusion

BCrypt is the way to securely store data at the moment. It is easy to customize the amount of processing time required hash a value. This allows you to be as secure as your processors can process and Product Owners want the user’s to wait.

Web page, Author:
Nathan Long, “How can bcrypt have built-in salts?”, StackOverflow.com, edited March 25, 2015, http://stackoverflow.com/questions/6832445/how-can-bcrypt-have-built-in-salts/6833165#6833165

Web page, Author:
Coda Hale, “How To Safely Store A Password”, Codahale.com, updated February 24, 2011, http://codahale.com/how-to-safely-store-a-password/

Web page, Author:
Joseph Wynn, “Bcrypt: Choosing a Work Factor”, http://wildlyinaccurate.com/, updated January 15, 2015, http://wildlyinaccurate.com/bcrypt-choosing-a-work-factor/

September 3rd, 2015

Posted In: Java, java ninja, Javaninja

Tags: , , ,

Leave a Comment

There will be sometimes in your code that you need access to the Springframework security principal object. Here is how you get it. You will need to create a Spring configuration class and annotate it with @EnableWebMvcSecurity

package com.cdi.igs.hub.spring;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;

/**
 * Spring Security configuration.
 * @author norris.shelton
 */
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // nothing needed here
}

The documentation then says to add a method parameter to a Spring MVC controller method with @AuthenticationPrincipal and you are done, like the following:

    @RequestMapping(value = "/{personId}", method = RequestMethod.GET)
    public ModelAndView getPersonAccount(@PathVariable int personId, @AuthenticationPrincipal User user) {
        ModelAndView modelAndView =  new ModelAndView("dashboard/account");
        modelAndView.addObject("person", personRepository.findOne(personId));
        return modelAndView;
    }

What they don’t tell you is that you need to configure a AuthenticationPrincipalArgumentResolver. Nor they tell you how to do it. This is the missing piece.

    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver"/>
        </mvc:argument-resolvers>
    </mvc:annotation-driven>

January 14th, 2014

Posted In: Spring, Spring MVC, Spring Security

Tags: , , , , ,

17 Comments

LinkedIn Auto Publish Powered By : XYZScripts.com