Fork me on GitHub

A free Java implementation of RFC 2898 / PKCS#5 PBKDF2

Please see GitHub for updates, including adaption of the LoginModule to WildFly 8.

Also note that Java comes with "PBKDF2WithHmacSHA1" these days. You may still want to use this library here since that allows you to specify different (JDK) HMAC algorithms, such as "HmacSHA256", or inject your own.

(15 Oct 2014)

There seems to be no small and freely available Java implementation of RFC 2898 / PKCS#5 available. Small as in only a few source files, with trivial compile and no dependencies, free as in LGPL.

Given the availability of HMacSHA1 in the standard SUN JCE cryptographic provider, such an implementation is quite simple and can be derived from the RFC description quite literally. My code is a clean-room implementation with only the RFC as its basis.

Download the source code here (PBKDF2-1.0.4-src.zip) and class files here (PBKDF2-1.0.4.jar).

The binary jar file contains a small main routine which processes the password supplied as first parameter on the command line and outputs a colon-separated line consisting of 8-byte random salt, iteration count (1000 fixed) and HMacSHA1 PBKDF2 of the password. Please refer to this main routine for basic usage.

  $ java -jar PBKDF2-1.0.4.jar "Hello World"
  DB2F38A2243903DE:1000:ECD1542B2EFB3F520F12A527E386B33CF4ADE3A2

Such output may be supplied back to the tool as second argument in which case the password is verified against the reference data. Output in verification mode is either OK or FAIL with exit codes 0 or 1, respectively. Case of hex characters is not significant. Of course, arbitrary length salts and iteration counts other than 1000 may be given in verification mode.

  $ java -jar PBKDF2-1.0.4.jar "Hello World" db2f38a2243903de:1000:ecd1542b2efb3f520f12a527e386b33cf4ade3a2
  OK
  $ echo $?
  0

  $ java -jar PBKDF2-1.0.4.jar "HELLO WORLD" DB2F38A2243903DE:1000:ECD1542B2EFB3F520F12A527E386B33CF4ADE3A2
  FAIL
  $ echo $?
  1

It is trivial to replace the PRF. PRFs based on (H)MAC algorithms available in the JCE may be specified by just giving the JCE algorithm name. Also it is possible to inject your own PRF implementaton quite easily: create an PBKDF2Engine object and set your own implementation using public void setPseudoRandomFunction(PRF prf). Or, derive and override protected void assertPRF(byte[] P).

Caveat: it seems that Java 6 does come with its own implementation of PBKDF2 as part of the JCE implementation. I have not checked whether this is available in earlier versions of the Sun cryptographic providers or in fact whether this mechanism is accessible from normal classes.

Test Vectors

RFC 6070 "PKCS #5: Password-Based Key Derivation Function 2 (PBKDF2) Test Vectors" (Jan 2011) defines a set of test vectors for PBKDF2 HMAC-SHA1.

While it's not directly possible to generate these test vectors with the JAR's main method, it is possible to verify the first five of them right away:
  $ java -jar PBKDF2-1.0.4.jar password 73616C74:1:0c60c80f961f0e71f3a9b524af6012062fe037a6
  $ java -jar PBKDF2-1.0.4.jar password 73616C74:2:ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957
  $ java -jar PBKDF2-1.0.4.jar password 73616C74:4096:4b007901b765489abead49d926f721d065a429c1
  $ java -jar PBKDF2-1.0.4.jar password 73616C74:16777216:eefe3d61cd4da4e4e9945b3d6ba2158c2634e984
  $ java -jar PBKDF2-1.0.4.jar passwordPASSWORDpassword 73616C7453414C5473616C7453414C5473616C7453414C5473616C7453414C5473616C74:4096:3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038
  $ #6: pass\0word 7361006C74:4096:56fa6aa75548099dcc37d7f03425e0c3
As expected, all these calls return "OK". Test number six poses a bit of a challenge because of the zero byte in the password. Find a test program in RFC6070Test6.java which tests this vector. A test program is required because a zero byte cannot be represented on a command line.

During development of this piece of code in 2007 RFC 6070 had not been written yet. I have not hand-computed reference data myself. Instead, I have used the freely accessible JavaScript implementation at http://anandam.name/pbkdf2/ for initial testing. Comparing results for a few passwords and a few iterations has shown no differences so far, but YMMV.

A JBoss Login Module to Access PBKDF2-protected Passwords in a Database

The stock org.jboss.security.auth.spi.DatabaseServerLoginModule as supplied with JBoss does allow clear-text and hashed passwords, but no iterated hashes as provided by PBKDF2. A sample module is provided which builds on the existing implementation in DatabaseServerLoginModule but performs a different check. In this module it is expected that the "password" as retrieved from the database is formatted as described above.

The module has been implemented against JBoss 3.0.8. I have seen it to work with JBoss 4.2.1.GA. It may or may not work with other or more recent versions of the JBoss application server.

Download the class file here (SaltedDatabaseLoginModule-1.0.4.jar). Source code is contained in above source ZIP file.

How to use it?

  1. Copy both jar files to the ${JBOSS_HOME}/server/default/lib directory.
  2. Create an application-policy in ${JBOSS_HOME}/server/default/conf/login-config.xml as shown below.
  3. Associate your web/EJB resources with this security-domain using jboss-web.xml (WAR) of jboss-ejb-jar.xml (EAR).

Assume a database accessible through a datasource jdbc/DerbyDS having tables USERS (ID,USERNAME,PASSWORD), ROLES (ID,ROLE) and USER_ROLES(USER_ID,ROLE_ID). Put a user 'admin' with password '9FED6664E7D2497F:1000:C40712D4DAE9CBDC69965CF3AA9976A223D18577' into USERS and a role 'JBossAdmin' into ROLE. Link both tables through the USER_ROLES n:m relation.

Create an (additional) application-policy entry in ${JBOSS_HOME}/server/default/conf/login-config.xml.

    <application-policy name = "saltedDatabasePassword">
       <authentication>
          <login-module code = "de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule" flag = "required">
             <!-- Same parameters as DatabaseServerLoginModule here. -->
             <module-option name="dsJndiName">java:/jdbc/DerbyDS</module-option>
             <module-option name="principalsQuery">select PASSWORD from USERS where USERNAME=?</module-option>
             <module-option name="rolesQuery">select R.ROLE, 'Roles' from USERS U, ROLES R, USER_ROLES UR where U.ID=UR.USER_ID and R.ID=UR.ROLE_ID and U.USERNAME=?</module-option>
             <!-- Below four parameters are optional; defaults are shown for clarification. -->
             <module-option name="hmacAlgorithm">HMacSHA1</module-option>
             <module-option name="formatter">de.rtner.security.auth.spi.PBKDF2HexFormatter</module-option>
             <module-option name="engine">de.rtner.security.auth.spi.PBKDF2Engine</module-option>
             <module-option name="engine-parameters">de.rtner.security.auth.spi.PBKDF2Parameters</module-option>
          </login-module>
       </authentication>
    </application-policy>

Protect your web application or EJB by associating it with the application-policy. As an example, you may protect the JBoss JMX console by changing file ${JBOSS_HOME}/server/default/deploy/jmx-console.war/WEB-INF/jboss-web.xml to

    <jboss-web>
        <security-domain>java:/jaas/saltedDatabasePassword</security-domain>
    </jboss-web>

Restart JBoss. Now access the JMX console at http://admin:password@localhost:8080/jmx-console.

This code may be used freely under the terms of the LGPL.

History:

Back to main page. Back to software page.


 
This page was last changed on October 15th, 2014. © Matthias Gärtner 2007,2014