In my Java based applications I usually have the need to encrypt a string before storing it somewhere. Most commonly, I need to encrypt user passwords and credit card information before storing it in a character field in the database. I don’t want people to be able to walk away with a cleartext list of passwords or credit card numbers just by doing a simple select. Instead they’ll have to work a little harder to decrypt the values stored in the database.

To do this, I wrote a very simple utility class that takes a String, runs it through a javax.crypto.Cipher object to DES encrypt it, and finally passes it through the Jakarta Commons Codec class which encodes the encrypted bytes into a Base64 (org.apache.commons.codec.binary.Base64) byte array. I wanted to encode the encrypted string in Base64 to ensure it only contains ASCII characters before storing it in my database. The decryption just follows the previous explanation in reverse: decode base 64, unencrypt string, return unencrypted string.

I will present my class below, complete with a main method showing how to use it. Before compiling the class, make sure you have downloaded the Jakarta Commons Codec library from http://jakarta.apache.org/site/downloads/downloads_commons-codec.cgi. I downloaded the file labeled 1.3.zip Binary. Uncompress the zip file and put the commons codec jar file into your classpath. The name of the jar file in my example is commons-codec-1.3.jar. The Commons Codec jar file is what supports the Base 64 encryption and decryption.

And now I will present my utility class:

package com.tima.crypto;

import java.io.*;
import java.util.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.commons.codec.binary.Base64;

/**
 * Class which provides methods for encrypting and decrypting
 * strings using a DES encryption algorithm.
 * Strings can be encrypted and then are returned translated
 * into a Base64 Ascii String.
 *
 * @author  Tim Archer 11/11/03
 * @version $Revision: 1.2 $
 */
public class CryptString {

    private Cipher encryptCipher = null;
    private Cipher decryptCipher = null;

    /**
     * Construct a new object which can be utilized to encrypt
     * and decrypt strings using the specified key
     * with a DES encryption algorithm.
     *
     * @param key The secret key used in the crypto operations.
     * @throws Exception If an error occurs.
     *
     */
    public CryptString(SecretKey key) throws Exception {
        encryptCipher = Cipher.getInstance("DES");
        decryptCipher = Cipher.getInstance("DES");
        encryptCipher.init(Cipher.ENCRYPT_MODE, key);
        decryptCipher.init(Cipher.DECRYPT_MODE, key);
    }    

    /**
     * Encrypt a string using DES encryption, and return the encrypted
     * string as a base64 encoded string.
     * @param unencryptedString The string to encrypt.
     * @return String The DES encrypted and base 64 encoded string.
     * @throws Exception If an error occurs.
     */
    public String encryptBase64 (String unencryptedString) throws Exception {
        // Encode the string into bytes using utf-8
        byte[] unencryptedByteArray = unencryptedString.getBytes("UTF8");

        // Encrypt
        byte[] encryptedBytes = encryptCipher.doFinal(unencryptedByteArray);

        // Encode bytes to base64 to get a string
        byte [] encodedBytes = Base64.encodeBase64(encryptedBytes);

        return new String(encodedBytes);
    }

    /**
     * Decrypt a base64 encoded, DES encrypted string and return
     * the unencrypted string.
     * @param encryptedString The base64 encoded string to decrypt.
     * @return String The decrypted string.
     * @throws Exception If an error occurs.
     */
    public String decryptBase64 (String encryptedString) throws Exception {
        // Encode bytes to base64 to get a string
        byte [] decodedBytes = Base64.decodeBase64(encryptedString.getBytes());

        // Decrypt
        byte[] unencryptedByteArray = decryptCipher.doFinal(decodedBytes);

        // Decode using utf-8
        return new String(unencryptedByteArray, "UTF8");
    }    

    /**
     * Main unit test method.
     * @param args Command line arguments.
     *
     */
    public static void main(String args[]) {
        try {
            //Generate the secret key
            String password = "secretpassword";
            DESKeySpec key = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

            //Instantiate the encrypter/decrypter
            CryptString crypt = new CryptString(keyFactory.generateSecret(key));
            String unencryptedString = "This is a test.";
            String encryptedString = crypt.encryptBase64(unencryptedString);
            System.out.println("Encrypted String:"+encryptedString);

            //Decrypt the string
            unencryptedString = crypt.decryptBase64(encryptedString);
            System.out.println("UnEncrypted String:"+unencryptedString);

        } catch (Exception e) {
            System.err.println("Error:"+e.toString());
        }
    }
}

If you strip out the comments, the class is really quite small and by reviewing my main method you can see how easy this class is to use. One requirement to using the class is that you will need to generate a secret key which is needed for both the encryption and decryption processes. In my example its just a string with the value “secretpassword”. Realistically you’ll want to store the secret key that you use in a file or other secure location that can only be accessed by your application. The relevant part of the example that creates the DESKeySpec and SecretKeyFactory used to initialize the class is:

            String password = "secretpassword";
            DESKeySpec key = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

And then my CryptString class is initialized through the following line which passes the DESKeySpec into the KeyFactory to generate the secret, and then passes the secret to the CryptString class constructor.

            CryptString crypt = new CryptString(keyFactory.generateSecret(key));

Lastly, to encrypt the string and base 64 encode the result, you call:

String encryptedString = crypt.encryptBase64(unencryptedString);

The string returned should be suitable for a simple JDBC insert into your database.

Hopefully you learned two things today from my example: 1) How to use the java Cipher classes to encrypt, and 2) how to use the Jakarata Commons Codec class to Base64 Encode. Happy encrypting!