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.
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:56fa6aa75548099dcc37d7f03425e0c3As 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.
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?
${JBOSS_HOME}/server/default/lib
directory.application-policy
in ${JBOSS_HOME}/server/default/conf/login-config.xml
as shown below.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 |