views:

392

answers:

2

Hi.

I was wondering if anyone have tried to do an equivalent of

Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(secret, saltValueBytes);
byte[] secretKey = key.GetBytes(16);

in Java. Where secret is a string(password), and saltValueBytes is, well, a salt in byte array.

I've tried stuff, but can't seem to wrap my head around it.

Thanks a lot for any help here.

+1  A: 

I found this implementation by means of a Google search but I have never used it.

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

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.

Andrew Hare
Thanks, Andrew. Not quite what I was looking for since I'd really like a regular Java implementation using the normal libraries
El Che
I know it - it's really a bummer that there isn't a direct equivalent.
Andrew Hare
+1  A: 

This one works for me. I still am in disbelief that a standard implementation of an RFC2898-compliant PBKDF2 is not present in the JRE. I think I must be looking in the wrong places. The name confusion (RFC2898 PKCS5 PBKDF2) doesn't help.

// PBKDF2.java
// ------------------------------------------------------------------
//
// RFC2898 PBKDF2 in Java.  The RFC2898 defines a standard algorithm for
// deriving key bytes from a text password.  This is also called 
// "PBKDF2", for Password-based key derivation function #2.
//
// There's no RFC2898-compliant PBKDF2 function in the JRE, as far as I
// know, but it is available in many J2EE runtimes, including those from
// JBoss, IBM, and Oracle.
//
// It's fairly simple to implement, so here it is. 
// 
// Author: Admin
// built on host: DINOCH-2
// Created Sun Aug 09 01:06:57 2009
//
// last saved: 
// Time-stamp: <2009-August-09 11:11:47>
// ------------------------------------------------------------------
//
// code from Matthias Gartner
//
// ------------------------------------------------------------------

package cheeso.examples;


import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


public class PBKDF2
{
    public static byte[] deriveKey( byte[] password, byte[] salt, int iterationCount, int dkLen )
        throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException
    {
        SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA1" );
        Mac prf = Mac.getInstance( "HmacSHA1" );
        prf.init( keyspec );

        // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
        //       variables and functions in this day and age, but they
        //       reflect the terse symbols used in RFC 2898 to describe
        //       the PBKDF2 algorithm, which improves validation of the
        //       code vs. the RFC.
        //
        // dklen is expressed in bytes. (16 for a 128-bit key)

        int hLen = prf.getMacLength();   // 20 for SHA1
        int l = Math.max( dkLen, hLen); //  1 for 128bit (16-byte) keys
        int r = dkLen - (l-1)*hLen;      // 16 for 128bit (16-byte) keys
        byte T[] = new byte[l * hLen];
        int ti_offset = 0;
        for (int i = 1; i <= l; i++) {
            F( T, ti_offset, prf, salt, iterationCount, i );
            ti_offset += hLen;
        }

        if (r < hLen) {
            // Incomplete last block
            byte DK[] = new byte[dkLen];
            System.arraycopy(T, 0, DK, 0, dkLen);
            return DK;
        }
        return T;
    } 


    private static void F( byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex ) {
        final int hLen = prf.getMacLength();
        byte U_r[] = new byte[ hLen ];
        // U0 = S || INT (i);
        byte U_i[] = new byte[S.length + 4];
        System.arraycopy( S, 0, U_i, 0, S.length );
        INT( U_i, S.length, blockIndex );
        for( int i = 0; i < c; i++ ) {
            U_i = prf.doFinal( U_i );
            xor( U_r, U_i );
        }

        System.arraycopy( U_r, 0, dest, offset, hLen );
    }

    private static void xor( byte[] dest, byte[] src ) {
        for( int i = 0; i < dest.length; i++ ) {
            dest[i] ^= src[i];
        }
    }

    private static void INT( byte[] dest, int offset, int i ) {
        dest[offset + 0] = (byte) (i / (256 * 256 * 256));
        dest[offset + 1] = (byte) (i / (256 * 256));
        dest[offset + 2] = (byte) (i / (256));
        dest[offset + 3] = (byte) (i);
    } 

    // ctor
    private PBKDF2 () {}

}
Cheeso