Key derivation functions

Introduction

Although initially intended for creating better secret keys, Key derivation functions are probably better for storing hashed passwords. This post tells you more about what a Key derivation function does, how you can use it for storing hashed passwords and how you can use it in the Octopus framework.

What is it?

For the symmetric encryption you need the secret key, an array of bytes basically. A password can also be converted to a byte array so a password can be used. Then the key doesn’t need to be stored and when the user types in the password, the message can be encrypted or decrypted.

But of course, passwords are not a really good candidate as the key for an encryption.
– passwords consist of characters which have all more or less the same bit pattern. So the ‘random’ spread of bits through-out the byte array is not good.
– password are mostly short, so your key is probably too small.

So that is where the Key derivation functions come into the picture. They take a password or passphrase (a sentence used as a password) and can generate a byte array out of this. It has the following characteristics
– It needs a salt, a byte array, to be able to do his work. So salting is mandatory.
– When the same password/passphrase and salt are presented to the Key Derivation function, it results in the same byte array outcome (so it is deterministic, no random outcome)
– It is a one-way procedure. So from the output buts, the original password / passphrase can’t be reconstructed.
– The output, the number of bits generated, is configurable (important because key sizes for encryption must have some minimum lengths)
– The functions are intentionally slow to counter any brute-force attack. And iterations can be applied to make it even more difficult.

You can read more background info on this wiki page

for hashed passwords

In the previous section, you can read why those Key derivation functions are very good for generating a secret key (for symmetric encryption). The properties are designed specifically for that purpose.

But very rapidly, they saw an alternative use for these functions, create hashed passwords. The reason why are easy to see
– When offered the same input, the same output is generated
– The input can’t be reconstructed from the output.

But they have a few other properties which make it a better candidate for storing passwords then the classic hashing functions.
– The computation requires a salt, so generating an output byte array is not possible without it. This in contrast to a classic hash algorithm where we add the salt to the password to overcome the use of rainbow tables.
– The computation of Key Derivation functions are slow, those of hash algorithms are fast. And performing the hashing function multiple times is not a good idea because of the increase in collisions.

Algorithms

So we are now at the point that we can say that Key Derivation functions are better for storing hashed passwords. So how can we get started with it in our Java programs?

There are different algorithms developed (just like there are different hash algorithms) like argon2, sCript, bCript or PBKDF2.
Only one is available by default on the JVM, PBKDF2, although most people say argon2 is the best algorithm. So let us see how we can use that one on the JVM.

Since Key derivation functions are something completely different then hash algorithms, these aren’t available from java.security.MessageDigest class. But there is another standard java class available which give you an instance of the algorithm, javax.crypto.SecretKeyFactory

The following snippets generate the BASE64 encoded output for a certain password. It also generates a salt value.

String password = "atbash";

String keyAlgorithmName = "PBKDF2WithHmacSHA256";
SecretKeyFactory keyFactory;
keyFactory = SecretKeyFactory.getInstance(keyAlgorithmName);

char[] chars = password.toCharArray();

byte[] salt = new byte[32];
new SecureRandom().nextBytes(salt);

int hashIterations = 1024;

int keySizeBytes = 32;

byte[] encoded = keyFactory.generateSecret(
        new PBEKeySpec(chars, salt, hashIterations, keySizeBytes * 8)).getEncoded();

String hashed = Base64.getEncoder().encodeToString(encoded);

System.out.println(hashed);

So using them us quite easily.

Octopus support

Also within Octopus, there is support added for the PBKDF2 algorithm within version 0.9.7.1. And since the way you use it is so similar then classic Hash algorithms, the only thing you need to do is set the algorithm name in the configuration file.

hashAlgorithmName=PBKDF2WithHmacSHA256

See also the chapter in the Octopus Cookbook

Conclusion

Key derivation functions are designed for creating a key which can be used in Symmetric encryption algorithms based on a password.

But it turns out that they are also very well suited to stored hashed passwords. So try them out and use them in your next project with or without the Octopus security framework.

Have fun.

 

Java EE Security API integration with Octopus

Introduction

The Java EE Security API (JSR-375) goal is to enhance the security features of the Java EE platform and to make sure that no custom configuration of the application server must be updated anymore when you want to use for example hashed passwords stored in a database table.
It was released together with Java EE 8 in September 2017 and one of the main concepts which are defined is the IdentityStore which validates the user credentials (like username and password) and retrieves the groups (the authorization grants) the user has.

The Octopus framework is mainly targeted to authorization features like declarative permissions useable for JSF components (with a custom tag) or annotations (to protect EJB methods for example). There are many authentication integrations available like OAuth2, OpenId Connect, KeyCloak, CAS server and custom integrations for database usage to name a few.

Since v 0.9.7.1, released on 27 December 2017, it is possible to integrate the IdentityStores from JSR-375 within Octopus and most of all, it runs also on Java EE 7.

The demo code can be found in the Octopus demo repository.

Project setup

The JSR-375 integration is defined within a Maven artifact specifically created for this purpose,

<dependency>
    <groupId>be.c4j.ee.security.octopus.authentication</groupId>
    <artifactId>security-api</artifactId>
    <version>${octopus.version}</version>
</dependency>

Together with the dependency for JSF on a Java EE 7 server,

<dependency>
    <groupId>be.c4j.ee.security.octopus</groupId>
    <artifactId>octopus-javaee7-jsf</artifactId>
    <version>${octopus.version}</version>
</dependency>

they can be found in the Bintray repository

<repository>
    <id>Bintray_JCenter</id>
    <url>https://jcenter.bintray.com</url>
</repository>

These are the other dependencies which we need

  • Java EE 7 (Provided) all the features of the Java EE 7 platform
  • PrimeFaces (Compile) The JSF Component library
  • Deltaspike (Compile/Runtime) Required dependency of Octopus but set as provided within Octopus so it is easier to specify the version you want to use within your application
  • Soteria (Compile) JSR-375 implementation and required since we are using a Java EE 7 server.
  • H2 database (Runtime) Our database where we want to store hashed passwords.

Security config

In this example, I want to show you the usage of a JSR-375 defined IdentityStore and a custom one.

The default defined IdentityStore is the Database one which stores the passwords hashed. It can be configured by putting an annotation on a CDI bean.

@DatabaseIdentityStoreDefinition(
        dataSourceLookup = "java:global/MyDS",
        callerQuery = "select password from caller where name = ?",
        groupsQuery = "select group_name from caller_groups where caller_name = ?",
        hashAlgorithmParameters = {
                "Pbkdf2PasswordHash.Iterations=3072",
                "Pbkdf2PasswordHash.Algorithm=PBKDF2WithHmacSHA512",
                "Pbkdf2PasswordHash.SaltSizeBytes=64"

        }
)

The datasource is defined within the DatabaseSetup class, which ensures the correct tables are created and filled with a few credentials.

This @DatabaseIdentityStoreDefinition is placed in our demo on the CDI bean which defines the second IdentityStore which is consulted when the database store didn’t contain the username we specified.

This custom store is created by implementing the interface javax.security.enterprise.identitystore.IdentityStore and override the validate() method.

Here we check if it is a certain fixed user and if the correct password is supplied. If so, it returns a few groups. Of course, you can write any kind of logic in these custom stores when the default ones don’t fit your needs.

Authorization

JSR-375 and Java EE in general, expect that each user has some groups defined in the external system which are then converted in roles of your application.

Octopus can also work with roles but one should use permissions because they are far more powerful. It has very powerful permission support like named, wildcard and domain permissions.

The groups of the user are interpreted as follows:
– The group is converted to a role with the same name (for the case you want to work with roles within Octopus)
– The group is converted to a named permission.
– The group is converted to a set of permissions by a CDI bean implementing the RolePermissionResolver which needs to be supplied by the developer.

This last option is probably the best and most powerful way to convert a group to a set of permissions and thus getting the maximum out of the features of Octopus.

No full integration

The described solution here is to integrate the IdentityStores of Java EE 8 (JSR-375) into the Octopus framework. It does not use the JASPIC as the underlying mechanism as JSR-375 describes, nor is there any integration with the other security features of Java EE like @RolesAllowed.

Java EE 8

And your application, like the demo, will be ready to convert to Java EE 8 with a minimal amount of effort. The only thing you need to do is take the Java EE 8 dependency (instead of the Java EE 7 one) and remove the Soteria dependency.

There will be no other changes required to make your application run on Java EE 8 and make use of all the features in that latest release.

Conclusion

With the Octopus framework, you have today already the most powerful authorization features available. And by using you are preparing yourself for the future when Java EE also has the authorization features available which are planned within the Java EE Security API.

Have fun.