Java passphrase encryption

Question!

I'm trying to learn how to do passphrase-based encryption with Java. I'm finding several examples online, but none (yet) on Stack Overflow. The examples are a little light on explanation for me, particularly regarding algorithm selection. There seems to be a lot of passing strings around to say what algorithms to use, but little documentation as to where the strings came from and what they mean. And it also seems like the different algorithms may require different implementations of the KeySpec class, so I'm not sure what algorithms can use the PBEKeySpec class I'm looking at. Furthermore, the examples all seem a little out of date, many requiring you to get an older cryptography package that used to not be part of the JDK, or even a third-party implementation.

Can someone provide a straightforward introduction to what I need to do to implement encrypt(String data, String passphrase) and decrypt(byte[] data, String passphrase)?

By : skiphoppy


Answers

Convert your string to a byte array during encryption. Convert back to a string after decryption.

/**
 * Creates a cipher for encryption or decryption.
 * 
 * @param algorithm  PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES".
 * @param mode Encyrption or decyrption.
 * @param password Password
 * @param salt Salt usable with algorithm.
 * @param count Iterations.
 * @return Ready initialized cipher.
 * @throws GeneralSecurityException Error creating the cipher.
 */
private static Cipher createCipher(final String algorithm, final int mode, final char[] password, final byte[] salt, final int count) throws GeneralSecurityException {
    final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
    final PBEKeySpec keySpec = new PBEKeySpec(password);
    final SecretKey key = keyFactory.generateSecret(keySpec);
    final Cipher cipher = Cipher.getInstance(algorithm);
    final PBEParameterSpec params = new PBEParameterSpec(salt, count);
    cipher.init(mode, key, params);
    return cipher;
}

/**
 * Encrypts some data based on a password.
 * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES"
 * @param data Data to encrypt
 * @param password Password
 * @param salt Salt usable with algorithm
 * @param count Iterations.
 * @return Encrypted data.
 */
public static byte[] encryptPasswordBased(final String algorithm, final byte[] data, final char[] password, final byte[] salt, final int count) {
    Validate.notNull(algorithm);
    Validate.notNull(data);
    Validate.notNull(password);
    Validate.notNull(salt);
    try {
        final Cipher cipher = createCipher(algorithm, Cipher.ENCRYPT_MODE, password, salt, count);
        return cipher.doFinal(data);
    } catch (final Exception ex) {
        throw new RuntimeException("Error encrypting the password!", ex);
    }
}

/**
 * Decrypts some data based on a password.
 * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES"
 * @param encryptedData Data to decrypt
 * @param password Password
 * @param salt Salt usable with algorithm
 * @param count Iterations.
 * @return Encrypted data.
 */
public static byte[] decryptPasswordBased(final String algorithm, final byte[] encryptedData, final char[] password, final byte[] salt, final int count) {
    Validate.notNull(algorithm);
    Validate.notNull(encryptedData);
    Validate.notNull(password);
    Validate.notNull(salt);
    try {
        final Cipher cipher = createCipher(algorithm, Cipher.DECRYPT_MODE, password, salt, count);
        return cipher.doFinal(encryptedData);
    } catch (final Exception ex) {
        throw new RuntimeException("Error decrypting the password!", ex);
    }
}
By : Rohit


In Cheeso's very helpful answer above, there is a bad performance bug.

The line

int l = Math.max( dkLen, hLen)

should not caculate the max, but the ceiling of the division, so

int l = ((dkLen - 1) / hLen) + 1; // >= ceil(dkLen / hLen), == for dkLen =>1

This will speed up computation by a factor of 20 for 16 byte keys.

By : Joqn


Use RFC2898 to generate keys from passwords. This isn't included in the JRE or JCE, as far as I know, but it is included in J2EE Servers like JBoss, Oracle, and WebSphere. It is also included in the .NET Base Class Library (Rfc2898DeriveBytes).

There are some LGPL implementations in Java out there, but on a quick look this one looks a little over complicated. There is also a good javascript version. (I produced a modified version of that one and packaged it as a Windows Script Component)

Lacking a good implementation with an appropriate license, I packaged some code up from Mattias Gartner. This is the code in its entirety. Short, simple, easy to understand. It's licensed under the MS Public License.

// PBKDF2.java
// ------------------------------------------------------------------
//
// RFC2898 PBKDF2 in Java.  The RFC2898 defines a standard algorithm for
// deriving key bytes from a text password.  This is sometimes
// abbreviated "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. 
// 
// Created Sun Aug 09 01:06:57 2009
//
// last saved: 
// Time-stamp: <2009-August-09 02:19:50>
// ------------------------------------------------------------------
//
// code thanks to 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 () {}

}
By : Cheeso


This video can help you solving your question :)
By: admin