Encryption, Codecs and Unit Tests in Grails

Certain data stored as plain text in a database is just asking for trouble these days. We hear too often about misplaced and stolen computers that contain databases full of Social Security numbers and other information that can lead to identity theft. We can help avoid these situations by encrypting those fields in a database so that if someone happens to get the data that they will have a difficult time getting the sensitive data.

Codecs

Grails provides a very good mechanism for this encryption in its Codec support. Codecs allow you to create encoders and decoders that become very easy to use in your application. Grails comes with a few useful ones built in to do things like Base64, URL, HTML, and Javascript Encoding.

Anywhere you have a string you can call the encodeAsCodecName or decodeCodecName to perform the encoding or decoding:

assert "apples & oranges " == "apples & oranges".encodeAsHTML()
assert "apples & oranges " == "apples & oranges".decodeHTML()

This is a nice, generally useful utility that can be used for any kind of string conversion really. There’s nothing from stopping you from creating your encodeAsInteger or decodeShortDate if that’s something you need a lot of in your application.

The basic format of a Codec is simple. You can create your new Codec in the grails-app/utils directory and it will be found automatically by Grails based on the naming convention.

class MyCodec {
static encode = { str ->
// Implement encoding here
}
static decode = { str ->
// Implement decoding here
}
}

Encryption Codec

In my case I wanted to create something to do encryption. Luckily this is not so hard with the javax.crypto classes. The crypto API is not the most straight forward to use in the world, but with a little bit of reading you can figure out how to encrypt and decrypt data without a lot of hassle. Basically what you see is a fairly simple encryption routine wrapped in the Grails Codec standard.

As you saw from previous example, the Codec standard is really simple, so all of the complexity here is really just the encryption code.


import javax.crypto.spec.SecretKeySpec
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import sun.misc.BASE64Encoder
import sun.misc.BASE64Decoder
import org.codehaus.groovy.grails.commons.ConfigurationHolder
/**
* Used for encrypting things to store in the database
*/
class SecureCodec {

static BASE64Decoder decoder = new BASE64Decoder()
static BASE64Encoder encoder = new BASE64Encoder()

static encode = { str ->
Cipher cipher = setupCipher(Cipher.ENCRYPT_MODE, getPassword())
return encoder.encode(cipher.doFinal(str.getBytes()));
}

static decode = { str ->
Cipher cipher = setupCipher(Cipher.DECRYPT_MODE, getPassword())
return new String(cipher.doFinal(decoder.decodeBuffer(str)));
}

static getPassword() {
return ConfigurationHolder.config.encryption.password
}

private static setupCipher(mode, password) {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

// setup key
byte[] keyBytes = new byte[16];
byte[] b = password.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(mode, keySpec, ivSpec);
return cipher
}
}

Another handy thing to notice is the ConfigurationHolder.config. This is the way to access application properties defined in Config.groovy. In a Domain class or a Controller you can get those values using grailsApplication.config but the grailsApplication variable is not available in Codecs or other classes. I use the Config.groovy to define an application specific secret to use for the encryption.

Testing Your Codec

Now to confirm that the code works we can write a Unit Tests. Encryption and Codecs are the perfect example of checking an Inverse Relationships to confirm the functionality of the Codec. Basically just encode it and decode it and compare the original value to the decoded value. If they match, it worked!

As a Unit Test

Outside the context of your running Grails application your Codec is just another Groovy class. Testing it in a Unit Test is easy though. You can just instantiate an instance of it and call the closures like they are methods.

class SecureCodecTests extends GroovyTestCase {

void test_roundtrip_decodes_to_the_same_thing() {
SecureCodec codec = new SecureCodec()
def original = "secret"
def encoded = codec.encode(original)
def decoded = codec.decode(encoded)

assert original != encoded
assert encoded != decoded
assert original == decoded
}
}

As an Integration Test

If you want to be able to test it as it will be used in your Grails application though, you will need to run it as an integration test. The integration tests are loaded, instrumented and run just like they would be by the real Grails application. To do that, you just have to create the test under the tests/integration directory of your Grails application.

class SecureCodecTests extends GroovyTestCase {

void test_roundtrip_decodes_to_the_same_thing() {
def original = "secret"
def encoded = original.encodeAsSecure()
def decoded = encoded.decodeSecure()

assert original != encoded
assert encoded != decoded
assert original == decoded
}
}

3 thoughts on “Encryption, Codecs and Unit Tests in Grails”

  1. Hi there,

    Thank you very much for a great post. This was very useful in my grails application.
    I did change one thing. I wanted to allow for longer passwords then 16 characters. So I split the password in fourths, generated hash-codes, then wrote them to the array.


    private static setupCipher(mode, password) {
    // setup key
    byte[] keyBytes = new byte[16];
    final int len = password.length();
    // four 'int's in sixteen bytes
    for(i in 0..<4) {
    // grab the hashcode of one forth of the string: 0..1/4, 1/4..2/4, 2/4..3/4, 3/4..4/4
    int hc = password.substring( (int)((len * i)/4), (int)((len * (i+1))/4) ).hashCode();
    // split an int into four bytes:
    keyBytes[i * 4 + 0] =(byte)( hc >> 24 );
    keyBytes[i * 4 + 1] =(byte)( (hc < < 8) >> 24 );
    keyBytes[i * 4 + 2] =(byte)( (hc < < 16) >> 24 );
    keyBytes[i * 4 + 3] =(byte)( (hc < < 24) >> 24 );
    }

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    // ...

    And Thanks again,
    - Andy G

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>